Close Menu
  • Home
  • AI
  • Big Data
  • Cloud Computing
  • iOS Development
  • IoT
  • IT/ Cybersecurity
  • Tech
    • Nanotechnology
    • Green Technology
    • Apple
    • Software Development
    • Software Engineering

Subscribe to Updates

Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

    What's Hot

    Authoring, simulating, and testing dynamic human-AI group conversations

    February 23, 2026

    Why aren’t live activities showing on iOS (flutter)

    February 23, 2026

    Inside the Birthplace of Your Favorite Technology

    February 22, 2026
    Facebook X (Twitter) Instagram
    Facebook X (Twitter) Instagram
    Big Tee Tech Hub
    • Home
    • AI
    • Big Data
    • Cloud Computing
    • iOS Development
    • IoT
    • IT/ Cybersecurity
    • Tech
      • Nanotechnology
      • Green Technology
      • Apple
      • Software Development
      • Software Engineering
    Big Tee Tech Hub
    Home»iOS Development»Why aren’t live activities showing on iOS (flutter)
    iOS Development

    Why aren’t live activities showing on iOS (flutter)

    big tee tech hubBy big tee tech hubFebruary 23, 20260013 Mins Read
    Share Facebook Twitter Pinterest Copy Link LinkedIn Tumblr Email Telegram WhatsApp
    Follow Us
    Google News Flipboard
    Why aren’t live activities showing on iOS (flutter)
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link


    As part of an app I am developing, I want to add live activities for iOS for a section of the app where a user can select Walk, Run, or Cycle. Currently when the user taps start, it tracks their route, distance, and time elapsed and saves that once they tap stop. What I want to achieve is to have a live activity showing their distance travelled and time elapsed that are frequently updated.

    I’m building for iOS 16.6+

    I’ve added these keys to Info.plist:

    NSSupportsLiveActivities
    
    NSSupportsLiveActivitiesFrequentUpdates
        
    

    I created a widget extension in Xcode with App Groups and have these swift files:

    GPSLiveActivityLiveActivity (target membership: Widget)

    import ActivityKit
    import WidgetKit
    import SwiftUI
    
    // MARK: - Live Activity Widget
    
    struct GPSLiveActivityLiveActivity: Widget {
        var body: some WidgetConfiguration {
            ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in
    
                LockScreenLiveActivityView(context: context)
            } dynamicIsland: { context in
                DynamicIsland {
                    DynamicIslandExpandedRegion(.leading) {
                        ExpandedLeadingView(context: context)
                    }
                    DynamicIslandExpandedRegion(.trailing) {
                        ExpandedTrailingView(context: context)
                    }
                    DynamicIslandExpandedRegion(.bottom) {
                        ExpandedBottomView(context: context)
                    }
                } compactLeading: {
                    CompactLeadingView(context: context)
                } compactTrailing: {
                    CompactTrailingView(context: context)
                } minimal: {
                    MinimalView()
                }
            }
        }
    }
    
    // MARK: - Shared reading helpers
    
    private struct SharedState {
        let activityType: String
        let elapsedSec: Int
        let distanceKm: Double
        let speedKmh: Double
    }
    
    private func readSharedState(_ context: ActivityViewContext) -> SharedState {
        let sharedDefaults = UserDefaults(suiteName: context.attributes.appGroupId)
    
        let type = sharedDefaults?.string(forKey: context.attributes.prefixedKey("activityType")) ?? "GPS"
    
        // Read as strings because Dart writes strings reliably
        let elapsedStr = sharedDefaults?.string(forKey: context.attributes.prefixedKey("elapsedSec")) ?? "0"
        let distanceStr = sharedDefaults?.string(forKey: context.attributes.prefixedKey("distanceKm")) ?? "0"
        let speedStr = sharedDefaults?.string(forKey: context.attributes.prefixedKey("speedKmh")) ?? "0"
    
        return SharedState(
            activityType: type,
            elapsedSec: Int(elapsedStr) ?? 0,
            distanceKm: Double(distanceStr) ?? 0.0,
            speedKmh: Double(speedStr) ?? 0.0
        )
    }
    
    private func formatElapsed(_ seconds: Int) -> String {
        let mins = seconds / 60
        let secs = seconds % 60
        return "\(mins):" + String(format: "%02d", secs)
    }
    
    // MARK: - Views
    
    private struct LockScreenLiveActivityView: View {
        let context: ActivityViewContext
    
        var body: some View {
            let state = readSharedState(context)
    
            VStack(alignment: .leading, spacing: 8) {
                Text("Pebblmed • \(state.activityType)")
                    .font(.headline)
    
                HStack {
                    Text("Time: \(formatElapsed(state.elapsedSec))")
                    Spacer()
                    Text(String(format: "%.2f km", state.distanceKm))
                }
                .font(.subheadline.monospacedDigit())
    
                Text(String(format: "Speed: %.1f km/h", state.speedKmh))
                    .font(.subheadline.monospacedDigit())
                    .foregroundStyle(.secondary)
    
                // Helpful sanity text while debugging:
                Text("id: \(context.attributes.id)")
                    .font(.caption2)
                    .foregroundStyle(.secondary)
            }
            .padding(.horizontal, 12)
            .padding(.vertical, 10)
        }
    }
    
    private struct ExpandedLeadingView: View {
        let context: ActivityViewContext
        var body: some View {
            let state = readSharedState(context)
            Text(state.activityType).font(.headline)
        }
    }
    
    private struct ExpandedTrailingView: View {
        let context: ActivityViewContext
        var body: some View {
            let state = readSharedState(context)
            Text(formatElapsed(state.elapsedSec))
                .font(.headline.monospacedDigit())
        }
    }
    
    private struct ExpandedBottomView: View {
        let context: ActivityViewContext
        var body: some View {
            let state = readSharedState(context)
            HStack {
                Text(String(format: "%.2f km", state.distanceKm))
                Spacer()
                Text(String(format: "%.1f km/h", state.speedKmh))
            }
            .font(.subheadline.monospacedDigit())
        }
    }
    
    private struct CompactLeadingView: View {
        let context: ActivityViewContext
        var body: some View {
            let state = readSharedState(context)
            Text(String(state.activityType.prefix(1))).font(.headline)
        }
    }
    
    private struct CompactTrailingView: View {
        let context: ActivityViewContext
        var body: some View {
            let state = readSharedState(context)
            Text(formatElapsed(state.elapsedSec))
                .font(.headline.monospacedDigit())
        }
    }
    
    private struct MinimalView: View {
        var body: some View {
            Image(systemName: "location.fill")
        }
    }
    
    // MARK: - Debug widget (optional)
    
    struct GPSLiveActivityDebugWidget: Widget {
        let kind: String = "GPSLiveActivityDebugWidget"
    
        var body: some WidgetConfiguration {
            StaticConfiguration(kind: kind, provider: GPSDebugProvider()) { _ in
                Text("Pebblmed Widget OK")
                    .padding()
            }
            .configurationDisplayName("Pebblmed Debug")
            .description("Confirms widget extension is installed.")
            .supportedFamilies([.systemSmall])
        }
    }
    
    private struct GPSDebugProvider: TimelineProvider {
        func placeholder(in context: Context) -> GPSDebugEntry { GPSDebugEntry(date: Date()) }
    
        func getSnapshot(in context: Context, completion: @escaping (GPSDebugEntry) -> Void) {
            completion(GPSDebugEntry(date: Date()))
        }
    
        func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) {
            completion(Timeline(entries: [GPSDebugEntry(date: Date())], policy: .never))
        }
    }
    
    private struct GPSDebugEntry: TimelineEntry {
        let date: Date
    }
    

    GPSLiveActivityBundle (target membership: Widget)

    import WidgetKit
    import SwiftUI
    
    @main
    struct GPSLiveActivityBundle: WidgetBundle {
        var body: some Widget {
            GPSLiveActivityLiveActivity()
            GPSLiveActivityDebugWidget()
        }
    }
    

    LiveActivitiesAppAttributes (target membership: Runner and Widget)

    import ActivityKit
    
    // MUST be exactly this name for the plugin:
    struct LiveActivitiesAppAttributes: ActivityAttributes {
    
        public struct ContentState: Codable, Hashable {
            // required by ActivityKit even if you don't use it
            var dummy: String = ""
        }
    
        // The id you pass from Dart createActivity(attributesId, ...)
        var id: String
    
        // The appGroupId you pass in plugin.init(appGroupId: ...)
        var appGroupId: String
    
        func prefixedKey(_ key: String) -> String {
            "\(id)_\(key)"
        }
    }
    

    AppDelegate:

    import UIKit
    import Flutter
    import UserNotifications
    import AVFAudio
    import GoogleMaps
    
    @main
    @objc class AppDelegate: FlutterAppDelegate {
    
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
    
        UIApplication.shared.ignoreSnapshotOnNextApplicationLaunch()
    
        // Set up audio playback category
        do {
          try AVAudioSession.sharedInstance().setCategory(
            .playback,
            mode: .default,
            options: [.mixWithOthers]
          )
          try AVAudioSession.sharedInstance().setActive(true)
        } catch {
          print("Failed to set audio session category.")
        }
    
        // Register Google Maps API key
        GMSServices.provideAPIKey("REDACTED")
    
        // Ensure notification taps are delivered to Flutter
        UNUserNotificationCenter.current().delegate = self
    
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    
      override func applicationWillResignActive(_ application: UIApplication) {
        // Add a white view over the window before backgrounding
        let whiteView = UIView(frame: window?.bounds ?? .zero)
        whiteView.backgroundColor = UIColor.white
        whiteView.tag = 999 // So we can remove it later
        window?.addSubview(whiteView)
      }
    
      override func applicationDidBecomeActive(_ application: UIApplication) {
        // Remove the white view when app becomes active
        if let whiteView = window?.viewWithTag(999) {
          whiteView.removeFromSuperview()
        }
      }
    }
    

    On the dart side I have these files:

    gps_live_activity_service:

    import 'dart:io';
    import 'package:flutter/foundation.dart';
    import 'package:live_activities/live_activities.dart';
    import 'package:uuid/uuid.dart';
    
    class GpsLiveActivityService {
      GpsLiveActivityService._();
      static final GpsLiveActivityService instance = GpsLiveActivityService._();
    
      static const String _appGroupId = 'group.com.stefanosai.pebbl'; // update if you changed it
    
      final LiveActivities _plugin = LiveActivities();
      bool _inited = false;
    
      /// The id YOU pass into createActivity (attributes.id in Swift)
      String? _attributesId;
    
      /// The id returned by createActivity (THIS is what update/end must use)
      String? _activityId;
    
      Future _ensureInit() async {
        if (!Platform.isIOS || _inited) return;
        await _plugin.init(appGroupId: _appGroupId);
        _inited = true;
        debugPrint('[LiveActivity] init ok appGroupId=$_appGroupId');
      }
    
      Future _isSupportedAndEnabled() async {
        if (!Platform.isIOS) return false;
        await _ensureInit();
        final supported = await _plugin.areActivitiesSupported();
        final enabled = await _plugin.areActivitiesEnabled();
        debugPrint('[LiveActivity] supported=$supported enabled=$enabled');
        return supported && enabled;
      }
    
      Future start({required String activityType}) async {
        if (!await _isSupportedAndEnabled()) return;
    
        // Optional, but helps prevent stale ids during testing
        await _plugin.endAllActivities();
    
        final attributesId = const Uuid().v4();
        _attributesId = attributesId;
    
        debugPrint('[LiveActivity] creating attributesId=$attributesId');
    
        try {
          // IMPORTANT: store the RETURNED activity id for update/end.
          final returnedActivityId = await _plugin.createActivity(
            attributesId,
            {
              // keep strings if your Swift is reading strings from UserDefaults
              'activityType': activityType,
              'elapsedSec': '0',
              'distanceKm': '0',
              'speedKmh': '0',
            },
            removeWhenAppIsKilled: true,
          );
    
          debugPrint('[LiveActivity] create returned activityId=$returnedActivityId');
    
          // Some versions return null; so we resolve from getAllActivitiesIds as fallback.
          final ids = await _plugin.getAllActivitiesIds();
          debugPrint('[LiveActivity] ids after create = $ids');
    
          final resolved = (returnedActivityId != null && returnedActivityId.isNotEmpty)
              ? returnedActivityId
              : (ids.isNotEmpty ? ids.first : null);
    
          _activityId = resolved;
          debugPrint('[LiveActivity] resolved activityId=$_activityId attributesId=$_attributesId');
        } catch (e) {
          debugPrint('[LiveActivity] create exception: $e');
        }
      }
    
      Future update({
        required int elapsedSec,
        required double distanceKm,
        required double speedKmh,
        String activityType="GPS",
      }) async {
        if (!Platform.isIOS) return;
        await _ensureInit();
    
        final activityId = _activityId;
        if (activityId == null) {
          debugPrint('[LiveActivity] update skipped: no activityId cached');
          return;
        }
    
        try {
          await _plugin.updateActivity(
            activityId, // MUST be the returned/resolved activityId
            {
              'activityType': activityType,
              'elapsedSec': elapsedSec.toString(),
              'distanceKm': distanceKm.toStringAsFixed(3),
              'speedKmh': speedKmh.toStringAsFixed(2),
            },
          );
    
          debugPrint('[LiveActivity] updated activityId=$activityId');
        } catch (e) {
          debugPrint('[LiveActivity] update exception: $e');
        }
      }
    
      Future end() async {
        if (!Platform.isIOS) return;
        await _ensureInit();
    
        final activityId = _activityId;
        if (activityId == null) return;
    
        try {
          await _plugin.endActivity(activityId);
          debugPrint('[LiveActivity] ended activityId=$activityId');
        } catch (e) {
          debugPrint('[LiveActivity] end exception: $e');
        } finally {
          _activityId = null;
          _attributesId = null;
        }
      }
    }
    

    gps_tracking_entry_ios_screen:

    import 'package:pebbl/l10n/app_localizations.dart';
    import 'dart:async';
    import 'dart:io';
    import 'package:flutter/material.dart';
    import 'package:geolocator/geolocator.dart';
    import 'package:firebase_auth/firebase_auth.dart';
    import 'package:pebbl/widgets/styled_dropdown_nullable.dart';
    import 'package:uuid/uuid.dart';
    import 'package:hive/hive.dart';
    import 'package:google_maps_flutter/google_maps_flutter.dart';
    import 'package:pebbl/models/gps_activity_entry.dart';
    import 'package:pebbl/services/feedback_service.dart';
    import 'package:pebbl/widgets/styled_elevated_button.dart';
    import 'package:pebbl/services/gps_live_activity_service.dart';
    
    class GpsTrackingEntryIosScreen extends StatefulWidget {
      const GpsTrackingEntryIosScreen({super.key});
    
      @override
      State createState() =>
          _GpsTrackingEntryIosScreenState();
    }
    
    class _GpsTrackingEntryIosScreenState extends State {
      final List _types = ['Walk', 'Run', 'Cycle'];
      String _selectedType="Walk";
    
      bool _isTracking = false;
      DateTime? _startTime;
      Timer? _timer;
      Duration _elapsed = Duration.zero;
      double _distanceKm = 0.0;
      final List _positions = [];
      StreamSubscription? _positionStream;
      DateTime? _lastLiveActivityUpdate;
      static const int _liveActivityUpdateEverySeconds = 10;
    
      // Live map state
      GoogleMapController? _mapController;
      final List _routePoints = [];
      LatLng? _currentLatLng;
    
      bool _followUser = true;
      bool _isProgrammaticMove = false;
    
      // Throttling / smoothing
      static const double _minAddPointMeters = 3.0; // only add points if moved ~3m+
      DateTime? _lastUiPointAdd;
      static const int _minUiPointAddMs = 400; // don’t redraw polylines too fast
    
      double _getMetValue(String type) {
        switch (type) {
          case 'Walk':
            return 3.5;
          case 'Run':
            return 7.0;
          case 'Cycle':
            return 6.0;
          default:
            return 4.0;
        }
      }
    
      @override
      void dispose() {
        _timer?.cancel();
        _positionStream?.cancel();
        _mapController?.dispose();
        if (_isTracking) {
          GpsLiveActivityService.instance.end();
        }
        super.dispose();
      }
    
      Future _maybeUpdateLiveActivity() async {
        if (!_isTracking || _startTime == null) return;
    
        final now = DateTime.now();
        final last = _lastLiveActivityUpdate;
        if (last != null &&
            now.difference(last).inSeconds < _liveActivityUpdateEverySeconds) {
          return;
        }
    
        final elapsedSec = now.difference(_startTime!).inSeconds;
        final durationHours = elapsedSec / 3600.0;
        final speedKmh = durationHours > 0 ? _distanceKm / durationHours : 0.0;
    
        await GpsLiveActivityService.instance.update(
          elapsedSec: elapsedSec,
          distanceKm: _distanceKm,
          speedKmh: speedKmh,
        );
    
        _lastLiveActivityUpdate = now;
      }
    
      Future _startTracking() async {
        final permission = await Geolocator.checkPermission();
        final serviceEnabled = await Geolocator.isLocationServiceEnabled();
    
        if (permission == LocationPermission.denied || !serviceEnabled) {
          await Geolocator.requestPermission();
          if (!mounted) return;
          FeedbackService.showSnackBar(
              context, 'Location permission is required.');
          return;
        }
    
        setState(() {
          _isTracking = true;
          _startTime = DateTime.now();
          _elapsed = Duration.zero;
          _distanceKm = 0.0;
    
          _positions.clear();
          _routePoints.clear();
          _currentLatLng = null;
    
          _followUser = true;
          _isProgrammaticMove = false;
          _lastUiPointAdd = null;
        });
    
        // Start Live Activity (iOS only)
        await GpsLiveActivityService.instance.start(activityType: _selectedType);
        _lastLiveActivityUpdate = DateTime.now();
    
        _timer = Timer.periodic(const Duration(seconds: 1), (_) {
          if (!mounted) return;
          setState(() {
            _elapsed = DateTime.now().difference(_startTime!);
          });
        });
    
        final LocationSettings settings = Platform.isAndroid
            ? AndroidSettings(
          accuracy: LocationAccuracy.best,
          distanceFilter: 5,
          intervalDuration: const Duration(seconds: 3),
        )
            : AppleSettings(
          accuracy: LocationAccuracy.best,
          distanceFilter: 5,
          activityType: ActivityType.fitness,
          pauseLocationUpdatesAutomatically: false,
        );
    
        _positionStream =
            Geolocator.getPositionStream(locationSettings: settings).listen(
                  (position) async {
                if (!mounted || !_isTracking) return;
    
                // distance
                if (_positions.isNotEmpty) {
                  final last = _positions.last;
                  final segmentMeters = Geolocator.distanceBetween(
                    last.latitude,
                    last.longitude,
                    position.latitude,
                    position.longitude,
                  );
                  _distanceKm += segmentMeters / 1000.0;
                }
    
                _positions.add(position);
    
                // ✅ Update Live Activity (throttled)
                await _maybeUpdateLiveActivity();
    
                // map points (throttled + minimum movement)
                final now = DateTime.now();
                final newPoint = LatLng(position.latitude, position.longitude);
    
                bool shouldAdd = false;
                if (_routePoints.isEmpty) {
                  shouldAdd = true;
                } else {
                  final lastPoint = _routePoints.last;
                  final movedMeters = Geolocator.distanceBetween(
                    lastPoint.latitude,
                    lastPoint.longitude,
                    newPoint.latitude,
                    newPoint.longitude,
                  );
                  if (movedMeters >= _minAddPointMeters) {
                    shouldAdd = true;
                  }
                }
    
                final uiOk = _lastUiPointAdd == null
                    ? true
                    : now.difference(_lastUiPointAdd!).inMilliseconds >= _minUiPointAddMs;
    
                if (shouldAdd && uiOk) {
                  _lastUiPointAdd = now;
                  setState(() {
                    _currentLatLng = newPoint;
                    _routePoints.add(newPoint);
                  });
    
                  if (_followUser) {
                    _animateTo(newPoint);
                  }
                } else {
                  // still update current location (marker) occasionally even if not adding polyline point
                  if (_currentLatLng == null ||
                      now.second % 2 == 0) { // lightweight cadence
                    setState(() {
                      _currentLatLng = newPoint;
                    });
                  }
                  if (_followUser) {
                    _animateTo(newPoint);
                  }
                }
              },
            );
      }
    
      Future _stopTracking() async {
        await GpsLiveActivityService.instance.end();
        _lastLiveActivityUpdate = null;
        _timer?.cancel();
        await _positionStream?.cancel();
        _positionStream = null;
    
        final endTime = DateTime.now();
        final path =
        _positions.map((pos) => {'lat': pos.latitude, 'lng': pos.longitude}).toList();
    
        final durationHours = _elapsed.inSeconds / 3600;
        final avSpeedKmh = durationHours > 0 ? _distanceKm / durationHours : 0.0;
    
        final met = _getMetValue(_selectedType);
        final userWeight = 70.0; // Replace with actual profile weight if available
        final calories = met * userWeight * durationHours;
    
        final uid = FirebaseAuth.instance.currentUser?.uid ?? '';
        final entry = GpsActivityEntry(
          id: const Uuid().v4(),
          type: _selectedType,
          startTime: _startTime!,
          endTime: endTime,
          distanceKm: _distanceKm,
          path: path,
          uid: uid,
          avSpeedKmh: avSpeedKmh,
          calories: calories,
        );
    
        final box = Hive.isBoxOpen('gps_activities')
            ? Hive.box('gps_activities')
            : await Hive.openBox('gps_activities');
    
        await box.add(entry);
    
        if (!mounted) return;
    
        FeedbackService.showSnackBar(context, 'GPS activity saved!');
        Navigator.pop(context, true);
    
        setState(() {
          _isTracking = false;
          _timer = null;
        });
      }
    
      Future _animateTo(LatLng target) async {
        if (_mapController == null) return;
    
        _isProgrammaticMove = true;
        try {
          // keep a pleasant zoom; don’t fight user zoom if they changed it
          await _mapController!.animateCamera(
            CameraUpdate.newLatLng(target),
          );
        } catch (_) {
          // ignore
        } finally {
          // small delay so onCameraMoveStarted doesn’t immediately flip followUser
          Future.delayed(const Duration(milliseconds: 250), () {
            _isProgrammaticMove = false;
          });
        }
      }
    
      Widget _buildPermissionWarning() {
        return FutureBuilder(
          future: Geolocator.checkPermission(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done &&
                snapshot.data != LocationPermission.always) {
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 12),
                child: TextButton(
                  onPressed: Geolocator.openAppSettings,
                  child: const Text(
                    'Location permission is not set to "Always". Tap here to update.',
                    style: TextStyle(color: Colors.red),
                    textAlign: TextAlign.center,
                  ),
                ),
              );
            }
            return const SizedBox.shrink();
          },
        );
      }
    
      Widget _buildLiveMap() {
        if (!_isTracking) return const SizedBox.shrink();
    
        // if we don’t have a first fix yet, show a placeholder
        if (_currentLatLng == null) {
          return Container(
            height: 280,
            margin: const EdgeInsets.only(top: 16),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(12),
              border: Border.all(color: Colors.black12),
            ),
            child: const Center(
              child: Padding(
                padding: EdgeInsets.all(16),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    CircularProgressIndicator(),
                    SizedBox(height: 12),
                    Text('Waiting for GPS signal…'),
                  ],
                ),
              ),
            ),
          );
        }
    
        final polyline = Polyline(
          polylineId: const PolylineId('live_route'),
          points: _routePoints.isEmpty ? [_currentLatLng!] : List.of(_routePoints),
          width: 5,
        );
    
        final markers = {
          Marker(
            markerId: const MarkerId('current'),
            position: _currentLatLng!,
          ),
        };
    
        return Container(
          height: 280,
          margin: const EdgeInsets.only(top: 16),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(12),
            border: Border.all(color: Colors.black12),
          ),
          clipBehavior: Clip.antiAlias,
          child: Stack(
            children: [
              GoogleMap(
                initialCameraPosition: CameraPosition(
                  target: _currentLatLng!,
                  zoom: 17,
                ),
                myLocationEnabled: false, // we use our own marker
                myLocationButtonEnabled: false,
                compassEnabled: true,
                zoomControlsEnabled: false,
                markers: markers,
                polylines: {polyline},
                onMapCreated: (c) {
                  _mapController = c;
                },
                onCameraMoveStarted: () {
                  // If user drags/zooms, stop following
                  if (!_isProgrammaticMove) {
                    setState(() => _followUser = false);
                  }
                },
              ),
              Positioned(
                right: 10,
                top: 10,
                child: Column(
                  children: [
                    if (!_followUser)
                      ElevatedButton.icon(
                        onPressed: () {
                          setState(() => _followUser = true);
                          _animateTo(_currentLatLng!);
                        },
                        icon: const Icon(Icons.my_location, size: 18),
                        label: const Text('Recenter'),
                      ),
                  ],
                ),
              ),
            ],
          ),
        );
      }
    
      String _formatElapsed(Duration d) {
        final mins = d.inMinutes;
        final secs = (d.inSeconds % 60).toString().padLeft(2, '0');
        return '$mins:$secs';
      }
    
      @override
      Widget build(BuildContext context) {
        // If you want localization here later, swap these hard-coded strings for AppLocalizations keys.
        return Scaffold(
          appBar: AppBar(title: const Text('GPS Activity')),
          body: SingleChildScrollView(
            padding: const EdgeInsets.all(16),
            child: Column(
              children: [
                StyledDropdownNullable(
                  value: _selectedType,
                  items: _types
                      .map>(
                        (type) => DropdownMenuItem(
                      value: type,
                      child: Text(type),
                    ),
                  )
                      .toList(),
                  hintText: 'Activity Type',
                  onChanged: _isTracking
                      ? null
                      : (String? value) {
                    if (value != null) {
                      setState(() => _selectedType = value);
                    }
                  },
                ),
                const SizedBox(height: 16),
                if (_isTracking) ...[
                  Text('Time Elapsed: ${_formatElapsed(_elapsed)}'),
                  Text('Distance: ${_distanceKm.toStringAsFixed(2)} km'),
                  _buildLiveMap(),
                  const SizedBox(height: 16),
                  StyledElevatedButton(
                    label: 'Stop',
                    type: StyledButtonType.delete,
                    onPressed: _stopTracking,
                  ),
                ] else ...[
                  StyledElevatedButton(
                    label: 'Start',
                    type: StyledButtonType.save,
                    onPressed: _startTracking,
                  ),
                ],
                _buildPermissionWarning(),
              ],
            ),
          ),
        );
      }
    }
    

    When I tap start and lock the screen, nothing appears to happen, and no live activities appear. I’m unsure what I have missed? I don’t see any errors in console, and the gps function itself works fine and saves correctly, there’s just no live activity. This is my 5th attempt at it and I keep giving up and reverting back, but I’d really like to finally get this sorted.

    Is anyone able to tell me where I have gone wrong?



    Source link

    Activities arent Flutter iOS Live Showing
    Follow on Google News Follow on Flipboard
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email Copy Link
    tonirufai
    big tee tech hub
    • Website

    Related Posts

    Pusher and push notifications

    February 22, 2026

    ios – How-To wrap Native Tabs with a custom Header?

    February 21, 2026

    swift – Flutter iOS build fails with “Framework ‘Pods_Runner’ not found” on Xcode 26.2 beta

    February 20, 2026
    Add A Comment
    Leave A Reply Cancel Reply

    Editors Picks

    Authoring, simulating, and testing dynamic human-AI group conversations

    February 23, 2026

    Why aren’t live activities showing on iOS (flutter)

    February 23, 2026

    Inside the Birthplace of Your Favorite Technology

    February 22, 2026

    Arkanix Stealer pops up as short-lived AI info-stealer experiment

    February 22, 2026
    About Us
    About Us

    Welcome To big tee tech hub. Big tee tech hub is a Professional seo tools Platform. Here we will provide you only interesting content, which you will like very much. We’re dedicated to providing you the best of seo tools, with a focus on dependability and tools. We’re working to turn our passion for seo tools into a booming online website. We hope you enjoy our seo tools as much as we enjoy offering them to you.

    Don't Miss!

    Authoring, simulating, and testing dynamic human-AI group conversations

    February 23, 2026

    Why aren’t live activities showing on iOS (flutter)

    February 23, 2026

    Subscribe to Updates

    Get the latest technology news from Bigteetechhub about IT, Cybersecurity and Big Data.

      • About Us
      • Contact Us
      • Disclaimer
      • Privacy Policy
      • Terms and Conditions
      © 2026 bigteetechhub.All Right Reserved

      Type above and press Enter to search. Press Esc to cancel.