一个 Flutter 插件,用于使用 iOS 16.1+ 的实时活动和 iPhone 14 Pro 的灵动岛功能。
? 这是什么?
此插件使用了 iOS ActivityKit API。
live_activities 可用于显示动态实时通知和在 iPhone 14 Pro / Max 上实现灵动岛功能 ?
⚠️ live_activities 仅适用于 iOS 16.1+!在其他平台和 < iOS 16.1 上它将不会有任何作用。
? 入门
由于一些技术限制,目前无法仅使用 Flutter ?。
您需要在 Flutter iOS 项目中实现一个小部件扩展 (Widget Extension),并用 *Swift*/*Objective-C* 开发您自己的实时活动 / 灵动岛设计。
ℹ️ 您可以在 示例存储库 中找到一个使用实时活动和灵动岛的完整示例应用程序。
-
? 原生
- 打开 Xcode 工作空间项目
ios/Runner.xcworkspace。 - 点击
文件->新建->目标…- 选择
Widget Extension并点击下一步。 - 指定产品名称(例如:*MyApp*Widget),并确保在“嵌入到应用程序”下拉菜单中选择“Runner”。
- 点击完成。
- 点击完成时,会出现一个提示,您需要点击激活。
- 选择
- 打开 Xcode 工作空间项目
- 仅在主
Runner应用中启用推送通知功能!
- 通过在
Runner和您的Widget Extension的Info.plist中添加此行来启用实时活动。
<key>NSSupportsLiveActivities</key>
<true/>
- 为
Runner和您的Widget Extension创建 App Group。
- 在您的扩展中,您需要创建一个名为 正好
LiveActivitiesAppAttributes的ActivityAttributes(如果您重命名了,活动会创建但不会显示!)
struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
public typealias LiveDeliveryData = ContentState // don't forget to add this line, otherwise, live activity will not display it.
public struct ContentState: Codable, Hashable { }
var id = UUID()
}
- 创建一个
UserDefaults并指定您的 group id,以便在 Swift 代码中访问 Flutter 数据。
// Create shared default with custom group
let sharedDefault = UserDefaults(suiteName: "YOUR_GROUP_ID")!
struct FootballMatchApp: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: LiveActivitiesAppAttributes.self) { context in
// create your live activity widget extension here
// to access Flutter properties:
let myVariableFromFlutter = sharedDefault.string(forKey: "myVariableFromFlutter")!
// [...]
}
}
}
-
? Flutter
- 导入插件。
import 'package:live_activities/live_activities.dart';
- 通过传入已创建的应用组 ID (App Group Id) 来初始化插件(如上所述)。
final _liveActivitiesPlugin = LiveActivities(); _liveActivitiesPlugin.init(appGroupId: "YOUR_CREATED_APP_ID");
- 创建您的动态活动。
final Map<String, dynamic> activityModel = { 'name': 'Margherita', 'ingredient': 'tomato, mozzarella, basil', 'quantity': 1, }; _liveActivitiesPlugin.createActivity(activityModel);
您可以传递任何类型的数据,但请记住它应该与
UserDefaults兼容。
从原生访问 Flutter 基本数据?
- 在您的 Swift 扩展中,您需要创建一个
UserDefaults实例来访问数据。
let sharedDefault = UserDefaults(suiteName: "YOUR_CREATED_APP_ID")!
⚠️ 确保在 Swift 扩展和 Flutter 应用中使用相同的 group id!
- 访问您的类型化数据
let pizzaName = sharedDefault.string(forKey: "name")! // put the same key as your Dart map
let pizzaPrice = sharedDefault.float(forKey: "price")
let quantity = sharedDefault.integer(forKey: "quantity")
// [...]
从原生访问 Flutter 图片?
- 在您的 map 中,传递一个
LiveActivityImageFromAsset或LiveActivityImageFromUrl对象。
final Map<String, dynamic> activityModel = {
'assetKey': LiveActivityImageFromAsset('assets/images/pizza_chorizo.png'),
'url': LiveActivityImageFromUrl(
'https://cdn.pixabay.com/photo/2015/10/01/17/17/car-967387__480.png',
resizeFactor: 0.3,
),
};
_liveActivitiesPlugin.createActivity(activityModel);
ℹ️ 使用 LiveActivityImageFromAsset 从您的 Flutter 资源加载图片。
ℹ️ 使用 LiveActivityImageFromUrl 从外部 URL 加载图片。
⚠️ 图片需要是小分辨率才能显示在您的实时活动/灵动岛中,您可以使用
resizeFactor自动调整图片大小 ?。
- 在您的 Swift 扩展中显示图片
if let assetImage = sharedDefault.string(forKey: "assetKey"), // <-- Put your key here
let uiImage = UIImage(contentsOfFile: shop) {
Image(uiImage: uiImage)
.resizable()
.frame(width: 53, height: 53)
.cornerRadius(13)
} else {
Text("Loading")
}
通过原生 ? 和 Flutter ? 进行通信
为了在您的原生实时活动 / 灵动岛与您的Flutter 应用之间传递一些有用的数据,您只需要设置URL 方案。
- 通过导航到 Runner -> Runner -> URL 类型 -> URL 方案,在 Xcode 中添加自定义 URL 方案。
- 在您的 Swift 代码中,只需创建一个新的链接并打开到您的自定义URL 方案。
Link(destination: URL(string: "la://my.app/order?=123")!) { // Replace "la" with your scheme
Text("See order")
}
⚠️ 不要忘记输入上一步中键入的URL 方案。
- 在您的 Flutter 应用中,您只需要监听URL 方案。
_liveActivitiesPlugin.urlSchemeStream().listen((schemeData) {
// do what do you want here ?
});
通过推送通知更新实时活动 ?
您可以使用 updateActivity() 方法直接在应用中更新实时活动,但如果您的应用已被杀死或在后台,您将无法更新通知……
要做到这一点,您可以通过服务器上的推送通知来更新它。
- 获取推送令牌
- 监听活动更新(推荐)
_liveActivitiesPlugin.activityUpdateStream.listen((event) { event.map( active: (activity) { // Get the token print(activity.activityToken); }, ended: (activity) {}, unknown: (activity) {}, ); });
- 直接获取推送令牌(不推荐,因为令牌将来可能会更改)。
final activityToken = await _liveActivitiesPlugin.getPushToken(_latestActivityId!); print(activityToken);
- 监听活动更新(推荐)
- 在您的服务器上使用令牌更新您的活动(更多信息可以在 这里 找到)。
? 文档
| 名称 | 描述 | 返回值 |
|---|---|---|
.init() |
通过提供应用组 ID (App Group Id) 来初始化插件(见上文)。 | Future 插件准备好创建/更新活动时。 |
.createActivity() |
创建 iOS 实时活动。 | String 活动标识符。 |
.updateActivity() |
使用提供的 activityId 更新实时活动数据。 |
Future 活动更新后。 |
.endActivity() |
使用提供的 activityId 结束实时活动。 |
Future 活动结束后。 |
.getAllActivitiesIds() |
获取所有已创建的活动 ID。 | Future<List<String>> 所有活动 ID 的列表。 |
.endAllActivities() |
结束应用的所有实时活动。 | Future 所有活动结束后。 |
.areActivitiesEnabled() |
检查实时活动功能是否受支持和启用。 | Future<bool> 实时活动是否受支持。 |
.getActivityState() |
获取活动的当前状态。 | Future<LiveActivityState> 一个枚举,用于了解活动的狀態(active、dismissed 或 ended)。 |
.getPushToken() |
同步获取活动的推送令牌(最好使用 activityUpdateStream 来保持推送令牌的最新)。 |
String? 活动的推送令牌(可能为 null)。 |
.urlSchemeStream() |
用于处理所有 URL 方案的订阅(例如:当应用从实时活动/灵动岛按钮打开时,您可以传递数据)。 | Future<UrlSchemeData> URL 方案数据,处理 scheme url host path queryItems。 |
.dispose() |
移除当前会话中已传递到 AppGroups 目录的所有图片,您可以使用 force 参数来删除所有图片。 |
Future 图片已移除。 |
.activityUpdateStream |
获取实时活动推送令牌和状态的流式通知。 | Stream<ActivityUpdate> 新推送令牌或活动结束时的状态更新。 |
? 贡献
欢迎贡献。通过创建 PR 或提交 issue 来贡献 ?。
? 路线图
- 通过 Flutter Engine 将 Widget 注入通知中 ?
- 支持推送令牌。
- 在扩展和 Flutter 应用之间传递媒体。
- 支持多种类型,而不是仅支持
String(日期、数字等)。 - 在原生灵动岛和 Flutter 应用之间传递数据。
- 在原生实时活动通知和 Flutter 应用之间传递数据。
- 取消所有活动。
- 获取所有活动 ID。
- 检查实时活动是否受支持。









