Flutter Live Activities not showing on Lock Screen or Dynamic Island

2 weeks ago 15
ARTICLE AD BOX

I’m trying to display a Live Activity + Dynamic Island in my Flutter app using the live_activities plugin. A simple Live Activity shows correctly, but when I switched to a more detailed Live Activity layout, nothing appears on the lock screen or Dynamic Island no errors from Flutter.

working code :

MineAppWidgetLiveActivity.swift

import ActivityKit import WidgetKit import SwiftUI // 1. ATTRIBUTES struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable { public struct ContentState: Codable, Hashable { var score: String } var matchName: String } extension LiveActivitiesAppAttributes { func prefixedKey(_ key: String) -> String { "\(id)_\(key)" } } let sharedDefault = UserDefaults(suiteName: "group.com.example.appLiveActivitytest")! struct MineAppWidgetLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in VStack { Text("⚽ \(context.attributes.matchName)") .font(.headline) Text(context.state.score) .font(.title) } .padding() } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.center) { Text("Score: \(context.state.score)") } } compactLeading: { Text("⚽") } compactTrailing: { Text(context.state.score) } minimal: { Text("⚽") } } } }

MineAppWidgetBundle.swift

import WidgetKit import SwiftUI @main struct MineAppWidgetBundle: WidgetBundle { var body: some Widget { MineAppWidget() MineAppWidgetLiveActivity() } }

main.dart

class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final _liveActivitiesPlugin = LiveActivities(); String? _latestActivityId; @override void initState() { _liveActivitiesPlugin.init( appGroupId: 'group.com.example.appLiveActivitytest', requestAndroidNotificationPermission: true, ); super.initState(); } Future<void> start() async { _latestActivityId = await _liveActivitiesPlugin.createActivity( DateTime.now().millisecondsSinceEpoch.toString(), {"score": "0 - 0"}, ); setState(() {}); } Future<void> update() async { if (_latestActivityId == null) return; final asd = await _liveActivitiesPlugin.updateActivity(_latestActivityId!, { "score": "5 - 3", }); log(asd.toString()); } Future<void> stop() async { if (_latestActivityId == null) return; _liveActivitiesPlugin.endAllActivities(); _latestActivityId = null; setState(() {}); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text("Live Activities Test")), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton(onPressed: start, child: const Text("Start")), ElevatedButton(onPressed: update, child: const Text("Update")), ElevatedButton(onPressed: stop, child: const Text("Stop")), Text("Activity: ${_latestActivityId ?? 'None'}"), ], ), ), ), ); } }

below code not working

main.dart

class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final _liveActivitiesPlugin = LiveActivities(); String? _latestActivityId; Timer? _timer; double _currentProgress = 0.0; @override void initState() { _liveActivitiesPlugin.init( appGroupId: 'group.com.example.appLiveActivitytest', requestAndroidNotificationPermission: true, ); super.initState(); } Future<void> start() async { try { _currentProgress = 0.0; final activityData = { "status": "Preparing your order...", "driverName": "Assigning...", "estimatedTime": "1:00 PM", "progress": 0.0, }; _latestActivityId = await _liveActivitiesPlugin.createActivity( "Burger King", activityData, ); setState(() {}); _timer?.cancel(); _timer = Timer.periodic(const Duration(seconds: 3), (timer) async { if (_latestActivityId == null) { timer.cancel(); return; } _currentProgress += 0.1; if (_currentProgress >= 1.0) _currentProgress = 1.0; final status = _currentProgress >= 1.0 ? "Enjoy your meal!" : _currentProgress >= 0.8 ? "Arriving soon" : _currentProgress >= 0.5 ? "Driver picked up order" : "Preparing your order..."; final updateData = { "status": status, "driverName": "Mike", "estimatedTime": "12:55 PM", "progress": _currentProgress, }; await _liveActivitiesPlugin.updateActivity( _latestActivityId!, updateData, ); log("Progress: $_currentProgress"); if (_currentProgress >= 1.0) { stop(); timer.cancel(); } }); } catch (e) { log(e.toString()); } } Future<void> stop() async { _timer?.cancel(); if (_latestActivityId == null) return; await _liveActivitiesPlugin.endAllActivities(); _latestActivityId = null; _currentProgress = 0.0; setState(() {}); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text("Delivery Tracker")), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ if (_latestActivityId != null) const Text( "Order Active!", style: TextStyle( color: Colors.green, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 20), ElevatedButton.icon( icon: const Icon(Icons.restaurant), label: const Text("Place Order (Start)"), onPressed: start, ), const SizedBox(height: 10), ElevatedButton.icon( icon: const Icon(Icons.stop), label: const Text("Delivered (Stop)"), onPressed: stop, ), ], ), ), ), ); } }

MineAppWidgetBundle.swift

import WidgetKit import SwiftUI @main struct MineAppWidgetBundle: WidgetBundle { var body: some Widget { MineAppWidget() MineAppWidgetLiveActivity() } }

MineAppWidgetLiveActivity.swift

import ActivityKit import WidgetKit import SwiftUI struct DeliveryAttributes: ActivityAttributes { public struct ContentState: Codable, Hashable { var status: String var driverName: String var estimatedTime: String var progress: Double } var restaurantName: String } struct MineAppWidgetLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: DeliveryAttributes.self) { context in VStack(alignment: .leading) { HStack { Image(systemName: "fork.knife.circle.fill") .foregroundColor(.orange) .font(.title) VStack(alignment: .leading) { Text(context.attributes.restaurantName) .font(.headline) .foregroundColor(.white) Text(context.state.status) .font(.subheadline) .foregroundColor(.gray) } Spacer() Text(context.state.estimatedTime) .font(.title3) .bold() .foregroundColor(.white) } .padding(.bottom, 8) ProgressView(value: context.state.progress, total: 1.0) .tint(.orange) .padding(.vertical, 4) Text("Driver: \(context.state.driverName)") .font(.caption) .foregroundColor(.secondary) } .padding() .activityBackgroundTint(Color.black.opacity(0.85)) .activitySystemActionForegroundColor(.white) } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.leading) { Label(context.state.driverName, systemImage: "car.fill") .foregroundColor(.orange) } DynamicIslandExpandedRegion(.trailing) { Text(context.state.estimatedTime) .font(.headline) } DynamicIslandExpandedRegion(.center) { Text(context.attributes.restaurantName) .font(.headline) } DynamicIslandExpandedRegion(.bottom) { VStack { ProgressView(value: context.state.progress, total: 1.0) .tint(.orange) Text(context.state.status) .font(.caption) .foregroundColor(.secondary) } } } compactLeading: { Image(systemName: "fork.knife") } compactTrailing: { Text(context.state.estimatedTime) .font(.caption) .bold() } minimal: { Image(systemName: "fork.knife") } } } }
Read Entire Article