flutter_live_activities

Creator: coderz1093

Last updated:

Add to Cart

Description:

flutter live activities

Flutter Live Activities #
Flutter plugin for Live Activities. Use to create, update and handling action for [DynamicIsland UI] and [Lock screen/banner UI]
English | 中文说明





This plugin requires notification permission


1. Add a Widget to the iOS project




Directory structure


2. Edit Runner/Info.plist and live_activity_test/Info.plist
both add:
<plist version="1.0">
<dict>
...
<key>NSSupportsLiveActivities</key>
<true/>
...
</dict>
</plist>
copied to clipboard
3. Create a data channel in widget swift file
live_activity_test/live_activity_testLiveActivity.swift
import ActivityKit
import SwiftUI
import WidgetKit

// Custom data model
struct TestData {
var text: String

init?(JSONData data: [String: String]) {
self.text = data["text"] ?? ""
}

init(text: String) {
self.text = text
}
}

// Data channel <- Must!
struct FlutterLiveActivities: ActivityAttributes, Identifiable {
public typealias LiveData = ContentState

public struct ContentState: Codable, Hashable {
var data: [String: String]
}

var id = UUID()
}

@available(iOSApplicationExtension 16.1, *)
struct live_activity_testLiveActivity: Widget {
var body: some WidgetConfiguration {
// Binding
ActivityConfiguration(for: FlutterLiveActivities.self) { context in

// Lock screen/banner UI goes here

// Json to model
let data = TestData(JSONData: context.state.data)

// UI
VStack {
Text(data?.text ?? "")
}
.activityBackgroundTint(Color.cyan)
.activitySystemActionForegroundColor(Color.black)
} dynamicIsland: { context in
// Json to model
let data = TestData(JSONData: context.state.data)

// DynamicIsland
return DynamicIsland {
// Expanded UI goes here. Compose the expanded UI through
// various regions, like leading/trailing/center/bottom
DynamicIslandExpandedRegion(.leading) {
Text("Leading")
}
DynamicIslandExpandedRegion(.trailing) {
Text("Trailing")
}
DynamicIslandExpandedRegion(.bottom) {
// Show data from flutter
Text(data?.text ?? "")
}
} compactLeading: {
Text("L")
} compactTrailing: {
Text("T")
} minimal: {
Text("Min")
}
.keylineTint(Color.red)
}
}
}
copied to clipboard
For more layout information, please refer to: live activities
4. APIs
import 'package:flutter_live_activities/flutter_live_activities.dart';

...

final FlutterLiveActivities _liveActivities = FlutterLiveActivities();

String? _activityId;
copied to clipboard

Check if the Live Activities function is enabled

await _liveActivities.areActivitiesEnabled();
copied to clipboard

Get launch url

await _liveActivities.getInitUri()
copied to clipboard

Create a Live Activity

_activityId = await _liveActivities.createActivity(<String, String>{'text': 'Hello World'});
copied to clipboard

Update a Live Activity

if(_activityId != null) {
await _liveActivities.updateActivity(_activityId!, <String, String>{'text': 'Update Hello World'});
}
copied to clipboard

The updated dynamic data for both ActivityKit updates and remote push notification updates can’t exceed 4KB in size. doc



For more solutions, please refer to live_activities


End a Live Activity

if(_activityId != null) {
await _liveActivities.endActivity(_activityId!);
}
copied to clipboard

End all Live Activities

await _liveActivities.endAllActivities();
copied to clipboard

Get all Live Activities id

await _liveActivities.getAllActivities()
copied to clipboard
5. Deeplink

The default urlScheme is fla


FlutterLiveActivities({this.urlScheme = 'fla'})


Add urlScheme in your project



Swift code:

@available(iOSApplicationExtension 16.1, *)
struct live_activity_testLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: FlutterLiveActivities.self) { context in
let data = TestData(JSONData: context.state.data)

// Lock screen/banner UI goes here

VStack(alignment: .leading) {
Text(data?.text ?? "")
HStack {
// Create an action via `Link`
Link(destination: URL(string: "fla://xx.xx/tap/A")!) {
Text("A")
.frame(width: 40, height: 40)
.background(.blue)
}
// Create an action via `Link`
Link(destination: URL(string: "fla://xx.xx/tap/B")!) {
Text("B")
.frame(width: 40, height: 40)
.background(.blue)
}
// Create an action via `Link`
Link(destination: URL(string: "fla://xx.xx/tap/C")!) {
Text("C")
.frame(width: 40, height: 40)
.background(.blue)
}
}
.frame(width: .infinity, height: .infinity)
}
.padding(20)
.activityBackgroundTint(Color.cyan)
.activitySystemActionForegroundColor(Color.black)

} dynamicIsland: { context in

let data = TestData(JSONData: context.state.data)

return DynamicIsland {
DynamicIslandExpandedRegion(.bottom) {
// Create an action via `Link`
Link(destination: URL(string: "fla://xxxxxxx.xxxxxx")!) {
Text(data?.text ?? "")
.background(.red)
}
}
} compactLeading: {
Text("L")
} compactTrailing: {
Text("T")
} minimal: {
Text("Min")
}
.widgetURL(URL(string: "fla://www.apple.com")) // or use widgetURL
.keylineTint(Color.red)
}
}
}
copied to clipboard

Dart code:

_subscription ??= _liveActivities.uriStream().listen((String? uri) {
dev.log('deeplink uri: $uri');
});
copied to clipboard
6. Display image

Due to block size limitations. We can't send metadata to LiveActivities


LiveActivities does not support async loading, so we can't use AsyncImage or read local file


Solution from Developer Forums: 716902


Add group config (Paid account required)



Add group id both Runner and Widget



Send image to group:

Dart code:
Future<void> _sendImageToGroup() async {
const String url = 'https://cdn.iconscout.com/icon/free/png-256/flutter-2752187-2285004.png';

final String? path = await ImageHelper.getFilePathFromUrl(url);

if (path != null) {
_liveActivities.sendImageToGroup(
id: 'test-img',
filePath: path,
groupId: 'group.live_example',
);
}
}
copied to clipboard
Swift code:
DynamicIslandExpandedRegion(.leading) {
if let imageContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.live_example")?.appendingPathComponent("test-img"), /// Use id here
let uiImage = UIImage(contentsOfFile: imageContainer.path())
{
Image(uiImage: uiImage)
.resizable()
.frame(width: 53, height: 53)
.cornerRadius(13)
} else {
Text("Leading")
}
}
copied to clipboard

License

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Files:

Customer Reviews

There are no reviews.