├── .gitignore ├── .metadata ├── CHANGELOG.md ├── CODEOWNERS ├── LICENSE ├── README-ZH.md ├── README.md ├── analysis_options.yaml ├── example ├── .gitignore ├── README.md ├── analysis_options.yaml ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ ├── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ └── LaunchImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ └── README.md │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── Runner-Bridging-Header.h │ │ └── Runner.entitlements │ ├── live_activity_test │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── WidgetBackground.colorset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── live_activity_test.intentdefinition │ │ ├── live_activity_testBundle.swift │ │ └── live_activity_testLiveActivity.swift │ └── live_activity_testExtension.entitlements ├── lib │ ├── helper │ │ └── image_helper.dart │ └── main.dart ├── pubspec.lock └── pubspec.yaml ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterLiveActivities.swift │ ├── FlutterLiveActivitiesPlugin.h │ ├── FlutterLiveActivitiesPlugin.m │ └── SwiftFlutterLiveActivitiesPlugin.swift └── flutter_live_activities.podspec ├── lib ├── flutter_live_activities.dart ├── flutter_live_activities_method_channel.dart ├── flutter_live_activities_platform_interface.dart └── src │ └── live_activities_status.dart └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 8 | channel: stable 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 17 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 18 | - platform: ios 19 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 20 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * First commit 4 | 5 | ## 0.0.2 6 | 7 | * Update README 8 | 9 | ## 0.0.3 10 | 11 | * Edit example 12 | 13 | ## 0.0.4 14 | 15 | * Add multiple streams to coexist, add Chinese documents 16 | 17 | ## 0.0.4+1 18 | 19 | * Add Lock screen/banner UI example 20 | 21 | ## 0.0.4+2 22 | 23 | * Fix the bug of url callback twice 24 | 25 | ## 0.0.4+3 26 | 27 | * Update README 28 | 29 | ## 0.0.4+4 30 | 31 | * Fix stream bug 32 | 33 | ## 0.0.5 34 | 35 | * Add apis 36 | * Add image solution 37 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @xSILENCEx 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 FlutterCandies 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-ZH.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Flutter Live Activities 4 | 5 | Live Activities 的 Flutter 插件。用于创建、更新和处理 [DynamicIsland UI] 和 [Lock screen/banner UI] 的动作 6 | 7 | [English](README.md) | 中文说明 8 | 9 | [![pub package](https://img.shields.io/pub/v/flutter_live_activities?logo=dart&label=stable&style=flat-square)](https://pub.dev/packages/flutter_live_activities) 10 | [![GitHub stars](https://img.shields.io/github/stars/fluttercandies/flutter_live_activities?logo=github&style=flat-square)](https://github.com/fluttercandies/flutter_live_activities/stargazers) 11 | [![GitHub forks](https://img.shields.io/github/forks/fluttercandies/flutter_live_activities?logo=github&style=flat-square)](https://github.com/fluttercandies/flutter_live_activities/network/members) 12 | FlutterCandies 13 | 14 | > 此插件需要通知权限 15 | 16 | 17 | 18 | #### 1. 在iOS项目中添加 Widget 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | * 创建成功后的目录结构 28 | 29 | 30 | 31 | #### 2. 编辑 `Runner/Info.plist` 和 `live_activity_test/Info.plist` 32 | 33 | 两个文件中都添加以下内容: 34 | ```xml 35 | 36 | 37 | ... 38 | NSSupportsLiveActivities 39 | 40 | ... 41 | 42 | 43 | ``` 44 | 45 | #### 3. 在小部件 swift 文件中创建数据通道 46 | 47 | [live_activity_test/live_activity_testLiveActivity.swift](https://github.com/fluttercandies/flutter_live_activities/blob/main/example/ios/live_activity_test/live_activity_testLiveActivity.swift) 48 | 49 | ```swift 50 | import ActivityKit 51 | import SwiftUI 52 | import WidgetKit 53 | 54 | // 自定义Model 55 | struct TestData { 56 | var text: String 57 | 58 | init?(JSONData data: [String: String]) { 59 | self.text = data["text"] ?? "" 60 | } 61 | 62 | init(text: String) { 63 | self.text = text 64 | } 65 | } 66 | 67 | // 数据通道 <- 必要!不能更改任何内容 68 | struct FlutterLiveActivities: ActivityAttributes, Identifiable { 69 | public typealias LiveData = ContentState 70 | 71 | public struct ContentState: Codable, Hashable { 72 | var data: [String: String] 73 | } 74 | 75 | var id = UUID() 76 | } 77 | 78 | @available(iOSApplicationExtension 16.1, *) 79 | struct live_activity_testLiveActivity: Widget { 80 | var body: some WidgetConfiguration { 81 | // 绑定通道 82 | ActivityConfiguration(for: FlutterLiveActivities.self) { context in 83 | 84 | // 锁屏上显示的内容 85 | 86 | // Json to model 87 | let data = TestData(JSONData: context.state.data) 88 | 89 | // UI 90 | VStack { 91 | Text(data?.text ?? "") 92 | } 93 | .activityBackgroundTint(Color.cyan) 94 | .activitySystemActionForegroundColor(Color.black) 95 | } dynamicIsland: { context in 96 | // Json to model 97 | let data = TestData(JSONData: context.state.data) 98 | 99 | // 灵动岛 100 | return DynamicIsland { 101 | // Expanded UI goes here. Compose the expanded UI through 102 | // various regions, like leading/trailing/center/bottom 103 | DynamicIslandExpandedRegion(.leading) { 104 | Text("Leading") 105 | } 106 | DynamicIslandExpandedRegion(.trailing) { 107 | Text("Trailing") 108 | } 109 | DynamicIslandExpandedRegion(.bottom) { 110 | // 显示 Flutter 传递过来的数据 111 | Text(data?.text ?? "") 112 | } 113 | } compactLeading: { 114 | Text("L") 115 | } compactTrailing: { 116 | Text("T") 117 | } minimal: { 118 | Text("Min") 119 | } 120 | .keylineTint(Color.red) 121 | } 122 | } 123 | } 124 | ``` 125 | 126 | 更多布局信息,请参考: [live activities](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities) 127 | 128 | #### 4. APIs 129 | 130 | ```dart 131 | import 'package:flutter_live_activities/flutter_live_activities.dart'; 132 | 133 | ... 134 | 135 | final FlutterLiveActivities _liveActivities = FlutterLiveActivities(); 136 | 137 | String? _activityId; 138 | ``` 139 | 140 | * 检查设备是否开启此功能 141 | ```dart 142 | await _liveActivities.areActivitiesEnabled(); 143 | ``` 144 | 145 | * 获取启动Link 146 | ```dart 147 | await _liveActivities.getInitUri() 148 | ``` 149 | 150 | * 创建一个 Live Activity 151 | ```dart 152 | _activityId = await _liveActivities.createActivity({'text': 'Hello World'}); 153 | ``` 154 | 155 | * 更新 Live Activity 156 | ```dart 157 | if(_activityId != null) { 158 | await _liveActivities.updateActivity(_activityId!, {'text': 'Update Hello World'}); 159 | } 160 | ``` 161 | 162 | > ActivityKit 更新和远程推送通知更新的更新动态数据大小不能超过 4KB。 [相关文档](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities) 163 | 164 | 165 | 166 | > 其它解决方案请参考 [live_activities](https://pub.dev/packages/live_activities) 167 | 168 | * 结束 Live Activity 169 | ```dart 170 | if(_activityId != null) { 171 | await _liveActivities.endActivity(_activityId!); 172 | } 173 | ``` 174 | 175 | * 结束全部 Live Activities 176 | ```dart 177 | await _liveActivities.endAllActivities(); 178 | ``` 179 | 180 | * 获取全部 Live Activities id 181 | ```dart 182 | await _liveActivities.getAllActivities() 183 | ``` 184 | 185 | #### 5. Deeplink(点击动作) 186 | 187 | * 默认 urlScheme 为 `fla` 188 | 189 | > `FlutterLiveActivities({this.urlScheme = 'fla'})` 190 | 191 | * 在项目中添加 urlScheme 192 | 193 | 194 | 195 | * Swift 代码: 196 | 197 | ```swift 198 | @available(iOSApplicationExtension 16.1, *) 199 | struct live_activity_testLiveActivity: Widget { 200 | var body: some WidgetConfiguration { 201 | ActivityConfiguration(for: FlutterLiveActivities.self) { context in 202 | let data = TestData(JSONData: context.state.data) 203 | 204 | // Lock screen/banner UI goes here 205 | 206 | VStack(alignment: .leading) { 207 | Text(data?.text ?? "") 208 | HStack { 209 | // 通过 `Link` 创建一个动作 210 | Link(destination: URL(string: "fla://xx.xx/tap/A")!) { 211 | Text("A") 212 | .frame(width: 40, height: 40) 213 | .background(.blue) 214 | } 215 | // 通过 `Link` 创建一个动作 216 | Link(destination: URL(string: "fla://xx.xx/tap/B")!) { 217 | Text("B") 218 | .frame(width: 40, height: 40) 219 | .background(.blue) 220 | } 221 | // 通过 `Link` 创建一个动作 222 | Link(destination: URL(string: "fla://xx.xx/tap/C")!) { 223 | Text("C") 224 | .frame(width: 40, height: 40) 225 | .background(.blue) 226 | } 227 | } 228 | .frame(width: .infinity, height: .infinity) 229 | } 230 | .padding(20) 231 | .activityBackgroundTint(Color.cyan) 232 | .activitySystemActionForegroundColor(Color.black) 233 | 234 | } dynamicIsland: { context in 235 | 236 | let data = TestData(JSONData: context.state.data) 237 | 238 | return DynamicIsland { 239 | DynamicIslandExpandedRegion(.bottom) { 240 | // 通过 `Link` 创建一个动作 241 | Link(destination: URL(string: "fla://xxxxxxx.xxxxxx")!) { 242 | Text(data?.text ?? "") 243 | .background(.red) 244 | } 245 | } 246 | } compactLeading: { 247 | Text("L") 248 | } compactTrailing: { 249 | Text("T") 250 | } minimal: { 251 | Text("Min") 252 | } 253 | .widgetURL(URL(string: "fla://www.apple.com")) // 或使用 widgetURL 254 | .keylineTint(Color.red) 255 | } 256 | } 257 | } 258 | ``` 259 | 260 | * Dart 代码: 261 | 262 | ```dart 263 | _subscription ??= _liveActivities.uriStream().listen((String? uri) { 264 | dev.log('deeplink uri: $uri'); 265 | }); 266 | ``` 267 | 268 | #### 6. Display image 269 | 270 | > 由于数据块大小的限制。我们无法向LiveActivities发送图片元数据 271 | 272 | > LiveActivities不支持异步加载,所以我们不能使用AsyncImage或读取本地文件 273 | 274 | > 开发者论坛的解决方案: [716902](https://developer.apple.com/forums/thread/716902) 275 | 276 | * 添加 AppGroup (此操作需要付费Apple账户) 277 | 278 | 279 | 280 | * 在 Runner 和 Widget 中创建/选择同样的 groupId 281 | 282 | 283 | 284 | * 发送图片到 group: 285 | 286 | Dart代码: 287 | ```dart 288 | Future _sendImageToGroup() async { 289 | const String url = 'https://cdn.iconscout.com/icon/free/png-256/flutter-2752187-2285004.png'; 290 | 291 | final String? path = await ImageHelper.getFilePathFromUrl(url); 292 | 293 | if (path != null) { 294 | _liveActivities.sendImageToGroup( 295 | id: 'test-img', 296 | filePath: path, 297 | groupId: 'group.live_example', 298 | ); 299 | } 300 | } 301 | ``` 302 | 303 | Swift代码: 304 | ```swift 305 | DynamicIslandExpandedRegion(.leading) { 306 | if let imageContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.live_example")?.appendingPathComponent("test-img"), /// Use id here 307 | let uiImage = UIImage(contentsOfFile: imageContainer.path()) 308 | { 309 | Image(uiImage: uiImage) 310 | .resizable() 311 | .frame(width: 53, height: 53) 312 | .cornerRadius(13) 313 | } else { 314 | Text("Leading") 315 | } 316 | } 317 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Flutter Live Activities 4 | 5 | Flutter plugin for Live Activities. Use to create, update and handling action for [DynamicIsland UI] and [Lock screen/banner UI] 6 | 7 | English | [中文说明](README-ZH.md) 8 | 9 | [![pub package](https://img.shields.io/pub/v/flutter_live_activities?logo=dart&label=stable&style=flat-square)](https://pub.dev/packages/flutter_live_activities) 10 | [![GitHub stars](https://img.shields.io/github/stars/fluttercandies/flutter_live_activities?logo=github&style=flat-square)](https://github.com/fluttercandies/flutter_live_activities/stargazers) 11 | [![GitHub forks](https://img.shields.io/github/forks/fluttercandies/flutter_live_activities?logo=github&style=flat-square)](https://github.com/fluttercandies/flutter_live_activities/network/members) 12 | FlutterCandies 13 | 14 | > This plugin requires notification permission 15 | 16 | 17 | 18 | #### 1. Add a Widget to the iOS project 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | * Directory structure 28 | 29 | 30 | 31 | #### 2. Edit `Runner/Info.plist` and `live_activity_test/Info.plist` 32 | 33 | both add: 34 | ```xml 35 | 36 | 37 | ... 38 | NSSupportsLiveActivities 39 | 40 | ... 41 | 42 | 43 | ``` 44 | 45 | #### 3. Create a data channel in widget swift file 46 | 47 | [live_activity_test/live_activity_testLiveActivity.swift](https://github.com/fluttercandies/flutter_live_activities/blob/main/example/ios/live_activity_test/live_activity_testLiveActivity.swift) 48 | 49 | ```swift 50 | import ActivityKit 51 | import SwiftUI 52 | import WidgetKit 53 | 54 | // Custom data model 55 | struct TestData { 56 | var text: String 57 | 58 | init?(JSONData data: [String: String]) { 59 | self.text = data["text"] ?? "" 60 | } 61 | 62 | init(text: String) { 63 | self.text = text 64 | } 65 | } 66 | 67 | // Data channel <- Must! 68 | struct FlutterLiveActivities: ActivityAttributes, Identifiable { 69 | public typealias LiveData = ContentState 70 | 71 | public struct ContentState: Codable, Hashable { 72 | var data: [String: String] 73 | } 74 | 75 | var id = UUID() 76 | } 77 | 78 | @available(iOSApplicationExtension 16.1, *) 79 | struct live_activity_testLiveActivity: Widget { 80 | var body: some WidgetConfiguration { 81 | // Binding 82 | ActivityConfiguration(for: FlutterLiveActivities.self) { context in 83 | 84 | // Lock screen/banner UI goes here 85 | 86 | // Json to model 87 | let data = TestData(JSONData: context.state.data) 88 | 89 | // UI 90 | VStack { 91 | Text(data?.text ?? "") 92 | } 93 | .activityBackgroundTint(Color.cyan) 94 | .activitySystemActionForegroundColor(Color.black) 95 | } dynamicIsland: { context in 96 | // Json to model 97 | let data = TestData(JSONData: context.state.data) 98 | 99 | // DynamicIsland 100 | return DynamicIsland { 101 | // Expanded UI goes here. Compose the expanded UI through 102 | // various regions, like leading/trailing/center/bottom 103 | DynamicIslandExpandedRegion(.leading) { 104 | Text("Leading") 105 | } 106 | DynamicIslandExpandedRegion(.trailing) { 107 | Text("Trailing") 108 | } 109 | DynamicIslandExpandedRegion(.bottom) { 110 | // Show data from flutter 111 | Text(data?.text ?? "") 112 | } 113 | } compactLeading: { 114 | Text("L") 115 | } compactTrailing: { 116 | Text("T") 117 | } minimal: { 118 | Text("Min") 119 | } 120 | .keylineTint(Color.red) 121 | } 122 | } 123 | } 124 | ``` 125 | 126 | For more layout information, please refer to: [live activities](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities) 127 | 128 | #### 4. APIs 129 | 130 | ```dart 131 | import 'package:flutter_live_activities/flutter_live_activities.dart'; 132 | 133 | ... 134 | 135 | final FlutterLiveActivities _liveActivities = FlutterLiveActivities(); 136 | 137 | String? _activityId; 138 | ``` 139 | 140 | * Check if the Live Activities function is enabled 141 | ```dart 142 | await _liveActivities.areActivitiesEnabled(); 143 | ``` 144 | 145 | * Get launch url 146 | ```dart 147 | await _liveActivities.getInitUri() 148 | ``` 149 | 150 | * Create a Live Activity 151 | ```dart 152 | _activityId = await _liveActivities.createActivity({'text': 'Hello World'}); 153 | ``` 154 | 155 | * Update a Live Activity 156 | ```dart 157 | if(_activityId != null) { 158 | await _liveActivities.updateActivity(_activityId!, {'text': 'Update Hello World'}); 159 | } 160 | ``` 161 | 162 | > The updated dynamic data for both ActivityKit updates and remote push notification updates can’t exceed 4KB in size. [doc](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities) 163 | 164 | 165 | 166 | > For more solutions, please refer to [live_activities](https://pub.dev/packages/live_activities) 167 | 168 | * End a Live Activity 169 | ```dart 170 | if(_activityId != null) { 171 | await _liveActivities.endActivity(_activityId!); 172 | } 173 | ``` 174 | 175 | * End all Live Activities 176 | ```dart 177 | await _liveActivities.endAllActivities(); 178 | ``` 179 | 180 | * Get all Live Activities id 181 | ```dart 182 | await _liveActivities.getAllActivities() 183 | ``` 184 | 185 | #### 5. Deeplink 186 | 187 | * The default urlScheme is `fla` 188 | 189 | > `FlutterLiveActivities({this.urlScheme = 'fla'})` 190 | 191 | * Add urlScheme in your project 192 | 193 | 194 | 195 | * Swift code: 196 | 197 | ```swift 198 | @available(iOSApplicationExtension 16.1, *) 199 | struct live_activity_testLiveActivity: Widget { 200 | var body: some WidgetConfiguration { 201 | ActivityConfiguration(for: FlutterLiveActivities.self) { context in 202 | let data = TestData(JSONData: context.state.data) 203 | 204 | // Lock screen/banner UI goes here 205 | 206 | VStack(alignment: .leading) { 207 | Text(data?.text ?? "") 208 | HStack { 209 | // Create an action via `Link` 210 | Link(destination: URL(string: "fla://xx.xx/tap/A")!) { 211 | Text("A") 212 | .frame(width: 40, height: 40) 213 | .background(.blue) 214 | } 215 | // Create an action via `Link` 216 | Link(destination: URL(string: "fla://xx.xx/tap/B")!) { 217 | Text("B") 218 | .frame(width: 40, height: 40) 219 | .background(.blue) 220 | } 221 | // Create an action via `Link` 222 | Link(destination: URL(string: "fla://xx.xx/tap/C")!) { 223 | Text("C") 224 | .frame(width: 40, height: 40) 225 | .background(.blue) 226 | } 227 | } 228 | .frame(width: .infinity, height: .infinity) 229 | } 230 | .padding(20) 231 | .activityBackgroundTint(Color.cyan) 232 | .activitySystemActionForegroundColor(Color.black) 233 | 234 | } dynamicIsland: { context in 235 | 236 | let data = TestData(JSONData: context.state.data) 237 | 238 | return DynamicIsland { 239 | DynamicIslandExpandedRegion(.bottom) { 240 | // Create an action via `Link` 241 | Link(destination: URL(string: "fla://xxxxxxx.xxxxxx")!) { 242 | Text(data?.text ?? "") 243 | .background(.red) 244 | } 245 | } 246 | } compactLeading: { 247 | Text("L") 248 | } compactTrailing: { 249 | Text("T") 250 | } minimal: { 251 | Text("Min") 252 | } 253 | .widgetURL(URL(string: "fla://www.apple.com")) // or use widgetURL 254 | .keylineTint(Color.red) 255 | } 256 | } 257 | } 258 | ``` 259 | 260 | * Dart code: 261 | 262 | ```dart 263 | _subscription ??= _liveActivities.uriStream().listen((String? uri) { 264 | dev.log('deeplink uri: $uri'); 265 | }); 266 | ``` 267 | 268 | #### 6. Display image 269 | 270 | > Due to block size limitations. We can't send metadata to LiveActivities 271 | 272 | > LiveActivities does not support async loading, so we can't use AsyncImage or read local file 273 | 274 | > Solution from Developer Forums: [716902](https://developer.apple.com/forums/thread/716902) 275 | 276 | * Add group config (Paid account required) 277 | 278 | 279 | 280 | * Add group id both Runner and Widget 281 | 282 | 283 | 284 | * Send image to group: 285 | 286 | Dart code: 287 | ```dart 288 | Future _sendImageToGroup() async { 289 | const String url = 'https://cdn.iconscout.com/icon/free/png-256/flutter-2752187-2285004.png'; 290 | 291 | final String? path = await ImageHelper.getFilePathFromUrl(url); 292 | 293 | if (path != null) { 294 | _liveActivities.sendImageToGroup( 295 | id: 'test-img', 296 | filePath: path, 297 | groupId: 'group.live_example', 298 | ); 299 | } 300 | } 301 | ``` 302 | 303 | Swift code: 304 | ```swift 305 | DynamicIslandExpandedRegion(.leading) { 306 | if let imageContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.live_example")?.appendingPathComponent("test-img"), /// Use id here 307 | let uiImage = UIImage(contentsOfFile: imageContainer.path()) 308 | { 309 | Image(uiImage: uiImage) 310 | .resizable() 311 | .frame(width: 53, height: 53) 312 | .cornerRadius(13) 313 | } else { 314 | Text("Leading") 315 | } 316 | } 317 | ``` -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Specify analysis options. 2 | # 3 | # Until there are meta linter rules, each desired lint must be explicitly enabled. 4 | # See: https://github.com/dart-lang/linter/issues/288 5 | # 6 | # For a list of lints, see: http://dart-lang.github.io/linter/lints/ 7 | # See the configuration guide for more 8 | # https://github.com/dart-lang/sdk/tree/main/pkg/analyzer#configuring-the-analyzer 9 | # 10 | # There are other similar analysis options files in the flutter repos, 11 | # which should be kept in sync with this file: 12 | # 13 | # - analysis_options.yaml (this file) 14 | # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml 15 | # - https://github.com/flutter/engine/blob/master/analysis_options.yaml 16 | # - https://github.com/flutter/packages/blob/master/analysis_options.yaml 17 | # 18 | # This file contains the analysis options used by Flutter tools, such as IntelliJ, 19 | # Android Studio, and the `flutter analyze` command. 20 | 21 | analyzer: 22 | strong-mode: 23 | implicit-casts: false 24 | implicit-dynamic: false 25 | errors: 26 | # treat missing required parameters as a warning (not a hint) 27 | missing_required_param: warning 28 | # treat missing returns as a warning (not a hint) 29 | missing_return: warning 30 | # allow having TODO comments in the code 31 | # todo: ignore 32 | # allow self-reference to deprecated members (we do this because otherwise we have 33 | # to annotate every member in every test, assert, etc, when we deprecate something) 34 | deprecated_member_use_from_same_package: ignore 35 | # TODO(ianh): https://github.com/flutter/flutter/issues/74381 36 | # Clean up existing unnecessary imports, and remove line to ignore. 37 | unnecessary_import: ignore 38 | # Turned off until null-safe rollout is complete. 39 | unnecessary_null_comparison: ignore 40 | exclude: 41 | - "bin/cache/**" 42 | # Ignore protoc generated files 43 | - "dev/conductor/lib/proto/*" 44 | - "lib/core/l10n/**" 45 | - "lib/res/images.dart" 46 | - "lib/generated_plugin_registrant.dart" 47 | - "lib/widgets/country_code/flag_codes.dart" 48 | - "build/**" 49 | - "lib/**.freezed.dart" 50 | - "lib/**.g.dart" 51 | - "lib/data_source/database/database.g.dart" 52 | - "lib/domain/enum/gps_proto/**" 53 | 54 | linter: 55 | rules: 56 | # these rules are documented on and in the same order as 57 | # the Dart Lint rules page to make maintenance easier 58 | # https://github.com/dart-lang/linter/blob/master/example/all.yaml 59 | - always_declare_return_types 60 | # - always_put_control_body_on_new_line 61 | # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 62 | - always_require_non_null_named_parameters 63 | - always_specify_types 64 | # - always_use_package_imports # we do this commonly 65 | - annotate_overrides 66 | # - avoid_annotating_with_dynamic # conflicts with always_specify_types 67 | - avoid_bool_literals_in_conditional_expressions 68 | # - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023 69 | # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023 70 | - avoid_classes_with_only_static_members 71 | - avoid_double_and_int_checks 72 | - avoid_dynamic_calls 73 | - avoid_empty_else 74 | - avoid_equals_and_hash_code_on_mutable_classes 75 | - avoid_escaping_inner_quotes 76 | - avoid_field_initializers_in_const_classes 77 | - avoid_function_literals_in_foreach_calls 78 | - avoid_implementing_value_types 79 | - avoid_init_to_null 80 | - avoid_js_rounded_ints 81 | # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to 82 | - avoid_null_checks_in_equality_operators 83 | # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it 84 | - avoid_print 85 | # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) 86 | - avoid_redundant_argument_values 87 | - avoid_relative_lib_imports 88 | - avoid_renaming_method_parameters 89 | - avoid_return_types_on_setters 90 | # - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated 91 | - avoid_returning_null_for_future 92 | - avoid_returning_null_for_void 93 | # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives 94 | - avoid_setters_without_getters 95 | - avoid_shadowing_type_parameters 96 | - avoid_single_cascade_in_expression_statements 97 | - avoid_slow_async_io 98 | - avoid_type_to_string 99 | - avoid_types_as_parameter_names 100 | # - avoid_types_on_closure_parameters # conflicts with always_specify_types 101 | - avoid_unnecessary_containers 102 | - avoid_unused_constructor_parameters 103 | - avoid_void_async 104 | # - avoid_web_libraries_in_flutter # we use web libraries in web-specific code, and our tests prevent us from using them elsewhere 105 | - await_only_futures 106 | - camel_case_extensions 107 | - camel_case_types 108 | - cancel_subscriptions 109 | # - cascade_invocations # doesn't match the typical style of this repo 110 | - cast_nullable_to_non_nullable 111 | # - close_sinks # not reliable enough 112 | # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 113 | # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 114 | - control_flow_in_finally 115 | # - curly_braces_in_flow_control_structures # not required by flutter style 116 | - depend_on_referenced_packages 117 | - deprecated_consistency 118 | # - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib) 119 | - directives_ordering 120 | # - do_not_use_environment # there are appropriate times to use the environment, especially in our tests and build logic 121 | - empty_catches 122 | - empty_constructor_bodies 123 | - empty_statements 124 | - eol_at_end_of_file 125 | - exhaustive_cases 126 | - file_names 127 | - flutter_style_todos 128 | - hash_and_equals 129 | - implementation_imports 130 | # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 131 | - iterable_contains_unrelated_type 132 | # - join_return_with_assignment # not required by flutter style 133 | - leading_newlines_in_multiline_strings 134 | - library_names 135 | - library_prefixes 136 | - library_private_types_in_public_api 137 | # - lines_longer_than_80_chars # not required by flutter style 138 | - list_remove_unrelated_type 139 | # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453 140 | - missing_whitespace_between_adjacent_strings 141 | - no_adjacent_strings_in_list 142 | - no_default_cases 143 | - no_duplicate_case_values 144 | - no_logic_in_create_state 145 | # - no_runtimeType_toString # ok in tests; we enable this only in packages/ 146 | - non_constant_identifier_names 147 | - noop_primitive_operations 148 | - null_check_on_nullable_type_parameter 149 | - null_closures 150 | # - omit_local_variable_types # opposite of always_specify_types 151 | # - one_member_abstracts # too many false positives 152 | - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al 153 | - overridden_fields 154 | - package_api_docs 155 | - package_names 156 | - package_prefixed_library_names 157 | # - parameter_assignments # we do this commonly 158 | - prefer_adjacent_string_concatenation 159 | - prefer_asserts_in_initializer_lists 160 | # - prefer_asserts_with_message # not required by flutter style 161 | - prefer_collection_literals 162 | - prefer_conditional_assignment 163 | - prefer_const_constructors 164 | - prefer_const_constructors_in_immutables 165 | - prefer_const_declarations 166 | - prefer_const_literals_to_create_immutables 167 | # - prefer_constructors_over_static_methods # far too many false positives 168 | - prefer_contains 169 | # - prefer_double_quotes # opposite of prefer_single_quotes 170 | - prefer_equal_for_default_values 171 | # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods 172 | - prefer_final_fields 173 | - prefer_final_in_for_each 174 | - prefer_final_locals 175 | # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments 176 | - prefer_for_elements_to_map_fromIterable 177 | - prefer_foreach 178 | - prefer_function_declarations_over_variables 179 | - prefer_generic_function_type_aliases 180 | - prefer_if_elements_to_conditional_expressions 181 | - prefer_if_null_operators 182 | - prefer_initializing_formals 183 | - prefer_inlined_adds 184 | # - prefer_int_literals # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-double-literals-for-double-constants 185 | - prefer_interpolation_to_compose_strings 186 | - prefer_is_empty 187 | - prefer_is_not_empty 188 | - prefer_is_not_operator 189 | - prefer_iterable_whereType 190 | # - prefer_mixin # Has false positives, see https://github.com/dart-lang/linter/issues/3018 191 | - prefer_null_aware_operators 192 | # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere 193 | # - prefer_relative_imports 194 | - prefer_single_quotes 195 | - prefer_spread_collections 196 | - prefer_typing_uninitialized_variables 197 | - prefer_void_to_null 198 | - provide_deprecation_message 199 | # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml 200 | - recursive_getters 201 | # - require_trailing_commas # blocked on https://github.com/dart-lang/sdk/issues/47441 202 | - sized_box_for_whitespace 203 | - slash_for_doc_comments 204 | - sort_child_properties_last 205 | - sort_constructors_first 206 | # - sort_pub_dependencies # prevents separating pinned transitive dependencies 207 | - sort_unnamed_constructors_first 208 | - test_types_in_equals 209 | - throw_in_finally 210 | - tighten_type_of_initializing_formals 211 | # - type_annotate_public_apis # subset of always_specify_types 212 | - type_init_formals 213 | # - unawaited_futures # too many false positives, especially with the way AnimationController works 214 | - unnecessary_await_in_return 215 | - unnecessary_brace_in_string_interps 216 | - unnecessary_const 217 | - unnecessary_constructor_name 218 | # - unnecessary_final # conflicts with prefer_final_locals 219 | - unnecessary_getters_setters 220 | # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 221 | - unnecessary_new 222 | - unnecessary_null_aware_assignments 223 | - unnecessary_null_checks 224 | - unnecessary_null_in_if_null_operators 225 | - unnecessary_nullable_for_final_variable_declarations 226 | - unnecessary_overrides 227 | - unnecessary_parenthesis 228 | # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint 229 | - unnecessary_statements 230 | - unnecessary_string_escapes 231 | - unnecessary_string_interpolations 232 | - unnecessary_this 233 | - unrelated_type_equality_checks 234 | - unsafe_html 235 | # - use_build_context_synchronously 236 | - use_full_hex_values_for_flutter_colors 237 | - use_function_type_syntax_for_parameters 238 | # - use_if_null_to_convert_nulls_to_bools # blocked on https://github.com/dart-lang/sdk/issues/47436 239 | - use_is_even_rather_than_modulo 240 | - use_key_in_widget_constructors 241 | - use_late_for_private_fields_and_variables 242 | - use_named_constants 243 | - use_raw_strings 244 | - use_rethrow_when_possible 245 | - use_setters_to_change_properties 246 | # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 247 | - use_test_throws_matchers 248 | # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review 249 | - valid_regexps 250 | - void_checks 251 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_live_activities_example 2 | 3 | Demonstrates how to use the flutter_live_activities plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Specify analysis options. 2 | # 3 | # Until there are meta linter rules, each desired lint must be explicitly enabled. 4 | # See: https://github.com/dart-lang/linter/issues/288 5 | # 6 | # For a list of lints, see: http://dart-lang.github.io/linter/lints/ 7 | # See the configuration guide for more 8 | # https://github.com/dart-lang/sdk/tree/main/pkg/analyzer#configuring-the-analyzer 9 | # 10 | # There are other similar analysis options files in the flutter repos, 11 | # which should be kept in sync with this file: 12 | # 13 | # - analysis_options.yaml (this file) 14 | # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml 15 | # - https://github.com/flutter/engine/blob/master/analysis_options.yaml 16 | # - https://github.com/flutter/packages/blob/master/analysis_options.yaml 17 | # 18 | # This file contains the analysis options used by Flutter tools, such as IntelliJ, 19 | # Android Studio, and the `flutter analyze` command. 20 | 21 | analyzer: 22 | strong-mode: 23 | implicit-casts: false 24 | implicit-dynamic: false 25 | errors: 26 | # treat missing required parameters as a warning (not a hint) 27 | missing_required_param: warning 28 | # treat missing returns as a warning (not a hint) 29 | missing_return: warning 30 | # allow having TODO comments in the code 31 | # todo: ignore 32 | # allow self-reference to deprecated members (we do this because otherwise we have 33 | # to annotate every member in every test, assert, etc, when we deprecate something) 34 | deprecated_member_use_from_same_package: ignore 35 | # TODO(ianh): https://github.com/flutter/flutter/issues/74381 36 | # Clean up existing unnecessary imports, and remove line to ignore. 37 | unnecessary_import: ignore 38 | # Turned off until null-safe rollout is complete. 39 | unnecessary_null_comparison: ignore 40 | exclude: 41 | - "bin/cache/**" 42 | # Ignore protoc generated files 43 | - "dev/conductor/lib/proto/*" 44 | - "lib/core/l10n/**" 45 | - "lib/res/images.dart" 46 | - "lib/generated_plugin_registrant.dart" 47 | - "lib/widgets/country_code/flag_codes.dart" 48 | - "build/**" 49 | - "lib/**.freezed.dart" 50 | - "lib/**.g.dart" 51 | - "lib/data_source/database/database.g.dart" 52 | - "lib/domain/enum/gps_proto/**" 53 | 54 | linter: 55 | rules: 56 | # these rules are documented on and in the same order as 57 | # the Dart Lint rules page to make maintenance easier 58 | # https://github.com/dart-lang/linter/blob/master/example/all.yaml 59 | - always_declare_return_types 60 | # - always_put_control_body_on_new_line 61 | # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 62 | - always_require_non_null_named_parameters 63 | - always_specify_types 64 | # - always_use_package_imports # we do this commonly 65 | - annotate_overrides 66 | # - avoid_annotating_with_dynamic # conflicts with always_specify_types 67 | - avoid_bool_literals_in_conditional_expressions 68 | # - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023 69 | # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023 70 | - avoid_classes_with_only_static_members 71 | - avoid_double_and_int_checks 72 | - avoid_dynamic_calls 73 | - avoid_empty_else 74 | - avoid_equals_and_hash_code_on_mutable_classes 75 | - avoid_escaping_inner_quotes 76 | - avoid_field_initializers_in_const_classes 77 | - avoid_function_literals_in_foreach_calls 78 | - avoid_implementing_value_types 79 | - avoid_init_to_null 80 | - avoid_js_rounded_ints 81 | # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to 82 | - avoid_null_checks_in_equality_operators 83 | # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it 84 | - avoid_print 85 | # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) 86 | - avoid_redundant_argument_values 87 | - avoid_relative_lib_imports 88 | - avoid_renaming_method_parameters 89 | - avoid_return_types_on_setters 90 | # - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated 91 | - avoid_returning_null_for_future 92 | - avoid_returning_null_for_void 93 | # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives 94 | - avoid_setters_without_getters 95 | - avoid_shadowing_type_parameters 96 | - avoid_single_cascade_in_expression_statements 97 | - avoid_slow_async_io 98 | - avoid_type_to_string 99 | - avoid_types_as_parameter_names 100 | # - avoid_types_on_closure_parameters # conflicts with always_specify_types 101 | - avoid_unnecessary_containers 102 | - avoid_unused_constructor_parameters 103 | - avoid_void_async 104 | # - avoid_web_libraries_in_flutter # we use web libraries in web-specific code, and our tests prevent us from using them elsewhere 105 | - await_only_futures 106 | - camel_case_extensions 107 | - camel_case_types 108 | - cancel_subscriptions 109 | # - cascade_invocations # doesn't match the typical style of this repo 110 | - cast_nullable_to_non_nullable 111 | # - close_sinks # not reliable enough 112 | # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 113 | # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 114 | - control_flow_in_finally 115 | # - curly_braces_in_flow_control_structures # not required by flutter style 116 | - depend_on_referenced_packages 117 | - deprecated_consistency 118 | # - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib) 119 | - directives_ordering 120 | # - do_not_use_environment # there are appropriate times to use the environment, especially in our tests and build logic 121 | - empty_catches 122 | - empty_constructor_bodies 123 | - empty_statements 124 | - eol_at_end_of_file 125 | - exhaustive_cases 126 | - file_names 127 | - flutter_style_todos 128 | - hash_and_equals 129 | - implementation_imports 130 | # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 131 | - iterable_contains_unrelated_type 132 | # - join_return_with_assignment # not required by flutter style 133 | - leading_newlines_in_multiline_strings 134 | - library_names 135 | - library_prefixes 136 | - library_private_types_in_public_api 137 | # - lines_longer_than_80_chars # not required by flutter style 138 | - list_remove_unrelated_type 139 | # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453 140 | - missing_whitespace_between_adjacent_strings 141 | - no_adjacent_strings_in_list 142 | - no_default_cases 143 | - no_duplicate_case_values 144 | - no_logic_in_create_state 145 | # - no_runtimeType_toString # ok in tests; we enable this only in packages/ 146 | - non_constant_identifier_names 147 | - noop_primitive_operations 148 | - null_check_on_nullable_type_parameter 149 | - null_closures 150 | # - omit_local_variable_types # opposite of always_specify_types 151 | # - one_member_abstracts # too many false positives 152 | - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al 153 | - overridden_fields 154 | - package_api_docs 155 | - package_names 156 | - package_prefixed_library_names 157 | # - parameter_assignments # we do this commonly 158 | - prefer_adjacent_string_concatenation 159 | - prefer_asserts_in_initializer_lists 160 | # - prefer_asserts_with_message # not required by flutter style 161 | - prefer_collection_literals 162 | - prefer_conditional_assignment 163 | - prefer_const_constructors 164 | - prefer_const_constructors_in_immutables 165 | - prefer_const_declarations 166 | - prefer_const_literals_to_create_immutables 167 | # - prefer_constructors_over_static_methods # far too many false positives 168 | - prefer_contains 169 | # - prefer_double_quotes # opposite of prefer_single_quotes 170 | - prefer_equal_for_default_values 171 | # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods 172 | - prefer_final_fields 173 | - prefer_final_in_for_each 174 | - prefer_final_locals 175 | # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments 176 | - prefer_for_elements_to_map_fromIterable 177 | - prefer_foreach 178 | - prefer_function_declarations_over_variables 179 | - prefer_generic_function_type_aliases 180 | - prefer_if_elements_to_conditional_expressions 181 | - prefer_if_null_operators 182 | - prefer_initializing_formals 183 | - prefer_inlined_adds 184 | # - prefer_int_literals # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-double-literals-for-double-constants 185 | - prefer_interpolation_to_compose_strings 186 | - prefer_is_empty 187 | - prefer_is_not_empty 188 | - prefer_is_not_operator 189 | - prefer_iterable_whereType 190 | # - prefer_mixin # Has false positives, see https://github.com/dart-lang/linter/issues/3018 191 | - prefer_null_aware_operators 192 | # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere 193 | # - prefer_relative_imports 194 | - prefer_single_quotes 195 | - prefer_spread_collections 196 | - prefer_typing_uninitialized_variables 197 | - prefer_void_to_null 198 | - provide_deprecation_message 199 | # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml 200 | - recursive_getters 201 | # - require_trailing_commas # blocked on https://github.com/dart-lang/sdk/issues/47441 202 | - sized_box_for_whitespace 203 | - slash_for_doc_comments 204 | - sort_child_properties_last 205 | - sort_constructors_first 206 | # - sort_pub_dependencies # prevents separating pinned transitive dependencies 207 | - sort_unnamed_constructors_first 208 | - test_types_in_equals 209 | - throw_in_finally 210 | - tighten_type_of_initializing_formals 211 | # - type_annotate_public_apis # subset of always_specify_types 212 | - type_init_formals 213 | # - unawaited_futures # too many false positives, especially with the way AnimationController works 214 | - unnecessary_await_in_return 215 | - unnecessary_brace_in_string_interps 216 | - unnecessary_const 217 | - unnecessary_constructor_name 218 | # - unnecessary_final # conflicts with prefer_final_locals 219 | - unnecessary_getters_setters 220 | # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 221 | - unnecessary_new 222 | - unnecessary_null_aware_assignments 223 | - unnecessary_null_checks 224 | - unnecessary_null_in_if_null_operators 225 | - unnecessary_nullable_for_final_variable_declarations 226 | - unnecessary_overrides 227 | - unnecessary_parenthesis 228 | # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint 229 | - unnecessary_statements 230 | - unnecessary_string_escapes 231 | - unnecessary_string_interpolations 232 | - unnecessary_this 233 | - unrelated_type_equality_checks 234 | - unsafe_html 235 | # - use_build_context_synchronously 236 | - use_full_hex_values_for_flutter_colors 237 | - use_function_type_syntax_for_parameters 238 | # - use_if_null_to_convert_nulls_to_bools # blocked on https://github.com/dart-lang/sdk/issues/47436 239 | - use_is_even_rather_than_modulo 240 | - use_key_in_widget_constructors 241 | - use_late_for_private_fields_and_variables 242 | - use_named_constants 243 | - use_raw_strings 244 | - use_rethrow_when_possible 245 | - use_setters_to_change_properties 246 | # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 247 | - use_test_throws_matchers 248 | # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review 249 | - valid_regexps 250 | - void_checks 251 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_live_activities (0.0.1): 4 | - Flutter 5 | - path_provider_ios (0.0.1): 6 | - Flutter 7 | 8 | DEPENDENCIES: 9 | - Flutter (from `Flutter`) 10 | - flutter_live_activities (from `.symlinks/plugins/flutter_live_activities/ios`) 11 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) 12 | 13 | EXTERNAL SOURCES: 14 | Flutter: 15 | :path: Flutter 16 | flutter_live_activities: 17 | :path: ".symlinks/plugins/flutter_live_activities/ios" 18 | path_provider_ios: 19 | :path: ".symlinks/plugins/path_provider_ios/ios" 20 | 21 | SPEC CHECKSUMS: 22 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 23 | flutter_live_activities: 49925d06d6bcbe36ab07c04d7a84ac907114b67f 24 | path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 25 | 26 | PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 27 | 28 | COCOAPODS: 1.11.3 29 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 2770E018291511C500771F44 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2770E017291511C500771F44 /* WidgetKit.framework */; }; 12 | 2770E01A291511C500771F44 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2770E019291511C500771F44 /* SwiftUI.framework */; }; 13 | 2770E01D291511C500771F44 /* live_activity_testBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2770E01C291511C500771F44 /* live_activity_testBundle.swift */; }; 14 | 2770E01F291511C500771F44 /* live_activity_testLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2770E01E291511C500771F44 /* live_activity_testLiveActivity.swift */; }; 15 | 2770E024291511C600771F44 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2770E023291511C600771F44 /* Assets.xcassets */; }; 16 | 2770E026291511C600771F44 /* live_activity_test.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 2770E022291511C500771F44 /* live_activity_test.intentdefinition */; }; 17 | 2770E027291511C600771F44 /* live_activity_test.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 2770E022291511C500771F44 /* live_activity_test.intentdefinition */; }; 18 | 2770E02A291511C600771F44 /* live_activity_testExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 2770E016291511C500771F44 /* live_activity_testExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 19 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 20 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 21 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 22 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 23 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 24 | C15A7BBE550183F5860C9555 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60B91EA2AF415F3D26D60DC3 /* Pods_Runner.framework */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 2770E028291511C600771F44 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 97C146E61CF9000F007C117D /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 2770E015291511C500771F44; 33 | remoteInfo = live_activity_testExtension; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXCopyFilesBuildPhase section */ 38 | 2770E02F291511C600771F44 /* Embed Foundation Extensions */ = { 39 | isa = PBXCopyFilesBuildPhase; 40 | buildActionMask = 2147483647; 41 | dstPath = ""; 42 | dstSubfolderSpec = 13; 43 | files = ( 44 | 2770E02A291511C600771F44 /* live_activity_testExtension.appex in Embed Foundation Extensions */, 45 | ); 46 | name = "Embed Foundation Extensions"; 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 50 | isa = PBXCopyFilesBuildPhase; 51 | buildActionMask = 2147483647; 52 | dstPath = ""; 53 | dstSubfolderSpec = 10; 54 | files = ( 55 | ); 56 | name = "Embed Frameworks"; 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXCopyFilesBuildPhase section */ 60 | 61 | /* Begin PBXFileReference section */ 62 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 63 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 64 | 2770E016291511C500771F44 /* live_activity_testExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = live_activity_testExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 2770E017291511C500771F44 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; 66 | 2770E019291511C500771F44 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 67 | 2770E01C291511C500771F44 /* live_activity_testBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = live_activity_testBundle.swift; sourceTree = ""; }; 68 | 2770E01E291511C500771F44 /* live_activity_testLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = live_activity_testLiveActivity.swift; sourceTree = ""; }; 69 | 2770E022291511C500771F44 /* live_activity_test.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = live_activity_test.intentdefinition; sourceTree = ""; }; 70 | 2770E023291511C600771F44 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 71 | 2770E025291511C600771F44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | 2770E0302915123700771F44 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 73 | 2770E0312915129600771F44 /* live_activity_testExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = live_activity_testExtension.entitlements; sourceTree = ""; }; 74 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 75 | 458DA777FB8597417C298567 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 76 | 58941C887787630E0DC83CF7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 77 | 60B91EA2AF415F3D26D60DC3 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 79 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 80 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 81 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 83 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 85 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 86 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 87 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 88 | FFA92E86F409F6A9AA3BBE58 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 89 | /* End PBXFileReference section */ 90 | 91 | /* Begin PBXFrameworksBuildPhase section */ 92 | 2770E013291511C500771F44 /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | 2770E01A291511C500771F44 /* SwiftUI.framework in Frameworks */, 97 | 2770E018291511C500771F44 /* WidgetKit.framework in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | C15A7BBE550183F5860C9555 /* Pods_Runner.framework in Frameworks */, 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | /* End PBXFrameworksBuildPhase section */ 110 | 111 | /* Begin PBXGroup section */ 112 | 2770E01B291511C500771F44 /* live_activity_test */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 2770E01C291511C500771F44 /* live_activity_testBundle.swift */, 116 | 2770E01E291511C500771F44 /* live_activity_testLiveActivity.swift */, 117 | 2770E022291511C500771F44 /* live_activity_test.intentdefinition */, 118 | 2770E023291511C600771F44 /* Assets.xcassets */, 119 | 2770E025291511C600771F44 /* Info.plist */, 120 | ); 121 | path = live_activity_test; 122 | sourceTree = ""; 123 | }; 124 | 42E2FA8A5218D71213299155 /* Pods */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | FFA92E86F409F6A9AA3BBE58 /* Pods-Runner.debug.xcconfig */, 128 | 58941C887787630E0DC83CF7 /* Pods-Runner.release.xcconfig */, 129 | 458DA777FB8597417C298567 /* Pods-Runner.profile.xcconfig */, 130 | ); 131 | path = Pods; 132 | sourceTree = ""; 133 | }; 134 | 6C05ED94426A36133CF94D04 /* Frameworks */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 60B91EA2AF415F3D26D60DC3 /* Pods_Runner.framework */, 138 | 2770E017291511C500771F44 /* WidgetKit.framework */, 139 | 2770E019291511C500771F44 /* SwiftUI.framework */, 140 | ); 141 | name = Frameworks; 142 | sourceTree = ""; 143 | }; 144 | 9740EEB11CF90186004384FC /* Flutter */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 148 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 149 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 150 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 151 | ); 152 | name = Flutter; 153 | sourceTree = ""; 154 | }; 155 | 97C146E51CF9000F007C117D = { 156 | isa = PBXGroup; 157 | children = ( 158 | 2770E0312915129600771F44 /* live_activity_testExtension.entitlements */, 159 | 9740EEB11CF90186004384FC /* Flutter */, 160 | 97C146F01CF9000F007C117D /* Runner */, 161 | 2770E01B291511C500771F44 /* live_activity_test */, 162 | 97C146EF1CF9000F007C117D /* Products */, 163 | 42E2FA8A5218D71213299155 /* Pods */, 164 | 6C05ED94426A36133CF94D04 /* Frameworks */, 165 | ); 166 | sourceTree = ""; 167 | }; 168 | 97C146EF1CF9000F007C117D /* Products */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 97C146EE1CF9000F007C117D /* Runner.app */, 172 | 2770E016291511C500771F44 /* live_activity_testExtension.appex */, 173 | ); 174 | name = Products; 175 | sourceTree = ""; 176 | }; 177 | 97C146F01CF9000F007C117D /* Runner */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | 2770E0302915123700771F44 /* Runner.entitlements */, 181 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 182 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 183 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 184 | 97C147021CF9000F007C117D /* Info.plist */, 185 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 186 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 187 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 188 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 189 | ); 190 | path = Runner; 191 | sourceTree = ""; 192 | }; 193 | /* End PBXGroup section */ 194 | 195 | /* Begin PBXNativeTarget section */ 196 | 2770E015291511C500771F44 /* live_activity_testExtension */ = { 197 | isa = PBXNativeTarget; 198 | buildConfigurationList = 2770E02B291511C600771F44 /* Build configuration list for PBXNativeTarget "live_activity_testExtension" */; 199 | buildPhases = ( 200 | 2770E012291511C500771F44 /* Sources */, 201 | 2770E013291511C500771F44 /* Frameworks */, 202 | 2770E014291511C500771F44 /* Resources */, 203 | ); 204 | buildRules = ( 205 | ); 206 | dependencies = ( 207 | ); 208 | name = live_activity_testExtension; 209 | productName = live_activity_testExtension; 210 | productReference = 2770E016291511C500771F44 /* live_activity_testExtension.appex */; 211 | productType = "com.apple.product-type.app-extension"; 212 | }; 213 | 97C146ED1CF9000F007C117D /* Runner */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 216 | buildPhases = ( 217 | 8E66A351ECE4730D6CB5F797 /* [CP] Check Pods Manifest.lock */, 218 | 9740EEB61CF901F6004384FC /* Run Script */, 219 | 97C146EA1CF9000F007C117D /* Sources */, 220 | 97C146EB1CF9000F007C117D /* Frameworks */, 221 | 97C146EC1CF9000F007C117D /* Resources */, 222 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 223 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 224 | 1613AA33CF4A811D03437973 /* [CP] Embed Pods Frameworks */, 225 | 2770E02F291511C600771F44 /* Embed Foundation Extensions */, 226 | ); 227 | buildRules = ( 228 | ); 229 | dependencies = ( 230 | 2770E029291511C600771F44 /* PBXTargetDependency */, 231 | ); 232 | name = Runner; 233 | productName = Runner; 234 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 235 | productType = "com.apple.product-type.application"; 236 | }; 237 | /* End PBXNativeTarget section */ 238 | 239 | /* Begin PBXProject section */ 240 | 97C146E61CF9000F007C117D /* Project object */ = { 241 | isa = PBXProject; 242 | attributes = { 243 | LastSwiftUpdateCheck = 1410; 244 | LastUpgradeCheck = 1300; 245 | ORGANIZATIONNAME = ""; 246 | TargetAttributes = { 247 | 2770E015291511C500771F44 = { 248 | CreatedOnToolsVersion = 14.1; 249 | }; 250 | 97C146ED1CF9000F007C117D = { 251 | CreatedOnToolsVersion = 7.3.1; 252 | LastSwiftMigration = 1100; 253 | }; 254 | }; 255 | }; 256 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 257 | compatibilityVersion = "Xcode 9.3"; 258 | developmentRegion = en; 259 | hasScannedForEncodings = 0; 260 | knownRegions = ( 261 | en, 262 | Base, 263 | ); 264 | mainGroup = 97C146E51CF9000F007C117D; 265 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 266 | projectDirPath = ""; 267 | projectRoot = ""; 268 | targets = ( 269 | 97C146ED1CF9000F007C117D /* Runner */, 270 | 2770E015291511C500771F44 /* live_activity_testExtension */, 271 | ); 272 | }; 273 | /* End PBXProject section */ 274 | 275 | /* Begin PBXResourcesBuildPhase section */ 276 | 2770E014291511C500771F44 /* Resources */ = { 277 | isa = PBXResourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | 2770E024291511C600771F44 /* Assets.xcassets in Resources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | 97C146EC1CF9000F007C117D /* Resources */ = { 285 | isa = PBXResourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 289 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 290 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 291 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | /* End PBXResourcesBuildPhase section */ 296 | 297 | /* Begin PBXShellScriptBuildPhase section */ 298 | 1613AA33CF4A811D03437973 /* [CP] Embed Pods Frameworks */ = { 299 | isa = PBXShellScriptBuildPhase; 300 | buildActionMask = 2147483647; 301 | files = ( 302 | ); 303 | inputFileListPaths = ( 304 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", 305 | ); 306 | name = "[CP] Embed Pods Frameworks"; 307 | outputFileListPaths = ( 308 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | shellPath = /bin/sh; 312 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 313 | showEnvVarsInLog = 0; 314 | }; 315 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 316 | isa = PBXShellScriptBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | ); 320 | inputPaths = ( 321 | ); 322 | name = "Thin Binary"; 323 | outputPaths = ( 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | shellPath = /bin/sh; 327 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 328 | }; 329 | 8E66A351ECE4730D6CB5F797 /* [CP] Check Pods Manifest.lock */ = { 330 | isa = PBXShellScriptBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | ); 334 | inputFileListPaths = ( 335 | ); 336 | inputPaths = ( 337 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 338 | "${PODS_ROOT}/Manifest.lock", 339 | ); 340 | name = "[CP] Check Pods Manifest.lock"; 341 | outputFileListPaths = ( 342 | ); 343 | outputPaths = ( 344 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | shellPath = /bin/sh; 348 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 349 | showEnvVarsInLog = 0; 350 | }; 351 | 9740EEB61CF901F6004384FC /* Run Script */ = { 352 | isa = PBXShellScriptBuildPhase; 353 | buildActionMask = 2147483647; 354 | files = ( 355 | ); 356 | inputPaths = ( 357 | ); 358 | name = "Run Script"; 359 | outputPaths = ( 360 | ); 361 | runOnlyForDeploymentPostprocessing = 0; 362 | shellPath = /bin/sh; 363 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 364 | }; 365 | /* End PBXShellScriptBuildPhase section */ 366 | 367 | /* Begin PBXSourcesBuildPhase section */ 368 | 2770E012291511C500771F44 /* Sources */ = { 369 | isa = PBXSourcesBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | 2770E01D291511C500771F44 /* live_activity_testBundle.swift in Sources */, 373 | 2770E01F291511C500771F44 /* live_activity_testLiveActivity.swift in Sources */, 374 | 2770E026291511C600771F44 /* live_activity_test.intentdefinition in Sources */, 375 | ); 376 | runOnlyForDeploymentPostprocessing = 0; 377 | }; 378 | 97C146EA1CF9000F007C117D /* Sources */ = { 379 | isa = PBXSourcesBuildPhase; 380 | buildActionMask = 2147483647; 381 | files = ( 382 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 383 | 2770E027291511C600771F44 /* live_activity_test.intentdefinition in Sources */, 384 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 385 | ); 386 | runOnlyForDeploymentPostprocessing = 0; 387 | }; 388 | /* End PBXSourcesBuildPhase section */ 389 | 390 | /* Begin PBXTargetDependency section */ 391 | 2770E029291511C600771F44 /* PBXTargetDependency */ = { 392 | isa = PBXTargetDependency; 393 | target = 2770E015291511C500771F44 /* live_activity_testExtension */; 394 | targetProxy = 2770E028291511C600771F44 /* PBXContainerItemProxy */; 395 | }; 396 | /* End PBXTargetDependency section */ 397 | 398 | /* Begin PBXVariantGroup section */ 399 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 400 | isa = PBXVariantGroup; 401 | children = ( 402 | 97C146FB1CF9000F007C117D /* Base */, 403 | ); 404 | name = Main.storyboard; 405 | sourceTree = ""; 406 | }; 407 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 408 | isa = PBXVariantGroup; 409 | children = ( 410 | 97C147001CF9000F007C117D /* Base */, 411 | ); 412 | name = LaunchScreen.storyboard; 413 | sourceTree = ""; 414 | }; 415 | /* End PBXVariantGroup section */ 416 | 417 | /* Begin XCBuildConfiguration section */ 418 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 419 | isa = XCBuildConfiguration; 420 | buildSettings = { 421 | ALWAYS_SEARCH_USER_PATHS = NO; 422 | CLANG_ANALYZER_NONNULL = YES; 423 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 424 | CLANG_CXX_LIBRARY = "libc++"; 425 | CLANG_ENABLE_MODULES = YES; 426 | CLANG_ENABLE_OBJC_ARC = YES; 427 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 428 | CLANG_WARN_BOOL_CONVERSION = YES; 429 | CLANG_WARN_COMMA = YES; 430 | CLANG_WARN_CONSTANT_CONVERSION = YES; 431 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 432 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 433 | CLANG_WARN_EMPTY_BODY = YES; 434 | CLANG_WARN_ENUM_CONVERSION = YES; 435 | CLANG_WARN_INFINITE_RECURSION = YES; 436 | CLANG_WARN_INT_CONVERSION = YES; 437 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 438 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 439 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 440 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 441 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 442 | CLANG_WARN_STRICT_PROTOTYPES = YES; 443 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 444 | CLANG_WARN_UNREACHABLE_CODE = YES; 445 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 446 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 447 | COPY_PHASE_STRIP = NO; 448 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 449 | ENABLE_NS_ASSERTIONS = NO; 450 | ENABLE_STRICT_OBJC_MSGSEND = YES; 451 | GCC_C_LANGUAGE_STANDARD = gnu99; 452 | GCC_NO_COMMON_BLOCKS = YES; 453 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 454 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 455 | GCC_WARN_UNDECLARED_SELECTOR = YES; 456 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 457 | GCC_WARN_UNUSED_FUNCTION = YES; 458 | GCC_WARN_UNUSED_VARIABLE = YES; 459 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 460 | MTL_ENABLE_DEBUG_INFO = NO; 461 | SDKROOT = iphoneos; 462 | SUPPORTED_PLATFORMS = iphoneos; 463 | TARGETED_DEVICE_FAMILY = "1,2"; 464 | VALIDATE_PRODUCT = YES; 465 | }; 466 | name = Profile; 467 | }; 468 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 469 | isa = XCBuildConfiguration; 470 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 471 | buildSettings = { 472 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 473 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 474 | CLANG_ENABLE_MODULES = YES; 475 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 476 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 477 | DEVELOPMENT_TEAM = 3U3296XZA5; 478 | ENABLE_BITCODE = NO; 479 | INFOPLIST_FILE = Runner/Info.plist; 480 | LD_RUNPATH_SEARCH_PATHS = ( 481 | "$(inherited)", 482 | "@executable_path/Frameworks", 483 | ); 484 | PRODUCT_BUNDLE_IDENTIFIER = com.fluttercandies.flutterLiveActivitiesExample; 485 | PRODUCT_NAME = "$(TARGET_NAME)"; 486 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 487 | SWIFT_VERSION = 5.0; 488 | VERSIONING_SYSTEM = "apple-generic"; 489 | }; 490 | name = Profile; 491 | }; 492 | 2770E02C291511C600771F44 /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 496 | ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; 497 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 498 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 499 | CLANG_ENABLE_OBJC_WEAK = YES; 500 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 501 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 502 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 503 | CODE_SIGN_ENTITLEMENTS = live_activity_testExtension.entitlements; 504 | CODE_SIGN_STYLE = Automatic; 505 | CURRENT_PROJECT_VERSION = 1; 506 | DEVELOPMENT_TEAM = 3U3296XZA5; 507 | GCC_C_LANGUAGE_STANDARD = gnu11; 508 | GENERATE_INFOPLIST_FILE = YES; 509 | INFOPLIST_FILE = live_activity_test/Info.plist; 510 | INFOPLIST_KEY_CFBundleDisplayName = live_activity_test; 511 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 512 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 513 | LD_RUNPATH_SEARCH_PATHS = ( 514 | "$(inherited)", 515 | "@executable_path/Frameworks", 516 | "@executable_path/../../Frameworks", 517 | ); 518 | MARKETING_VERSION = 1.0; 519 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 520 | MTL_FAST_MATH = YES; 521 | PRODUCT_BUNDLE_IDENTIFIER = "com.fluttercandies.flutterLiveActivitiesExample.live-activity-test"; 522 | PRODUCT_NAME = "$(TARGET_NAME)"; 523 | SKIP_INSTALL = YES; 524 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 525 | SWIFT_EMIT_LOC_STRINGS = YES; 526 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 527 | SWIFT_VERSION = 5.0; 528 | TARGETED_DEVICE_FAMILY = "1,2"; 529 | }; 530 | name = Debug; 531 | }; 532 | 2770E02D291511C600771F44 /* Release */ = { 533 | isa = XCBuildConfiguration; 534 | buildSettings = { 535 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 536 | ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; 537 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 538 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 539 | CLANG_ENABLE_OBJC_WEAK = YES; 540 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 541 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 542 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 543 | CODE_SIGN_ENTITLEMENTS = live_activity_testExtension.entitlements; 544 | CODE_SIGN_STYLE = Automatic; 545 | CURRENT_PROJECT_VERSION = 1; 546 | DEVELOPMENT_TEAM = 3U3296XZA5; 547 | GCC_C_LANGUAGE_STANDARD = gnu11; 548 | GENERATE_INFOPLIST_FILE = YES; 549 | INFOPLIST_FILE = live_activity_test/Info.plist; 550 | INFOPLIST_KEY_CFBundleDisplayName = live_activity_test; 551 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 552 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 553 | LD_RUNPATH_SEARCH_PATHS = ( 554 | "$(inherited)", 555 | "@executable_path/Frameworks", 556 | "@executable_path/../../Frameworks", 557 | ); 558 | MARKETING_VERSION = 1.0; 559 | MTL_FAST_MATH = YES; 560 | PRODUCT_BUNDLE_IDENTIFIER = "com.fluttercandies.flutterLiveActivitiesExample.live-activity-test"; 561 | PRODUCT_NAME = "$(TARGET_NAME)"; 562 | SKIP_INSTALL = YES; 563 | SWIFT_EMIT_LOC_STRINGS = YES; 564 | SWIFT_VERSION = 5.0; 565 | TARGETED_DEVICE_FAMILY = "1,2"; 566 | }; 567 | name = Release; 568 | }; 569 | 2770E02E291511C600771F44 /* Profile */ = { 570 | isa = XCBuildConfiguration; 571 | buildSettings = { 572 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 573 | ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; 574 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 575 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 576 | CLANG_ENABLE_OBJC_WEAK = YES; 577 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 578 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 579 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 580 | CODE_SIGN_ENTITLEMENTS = live_activity_testExtension.entitlements; 581 | CODE_SIGN_STYLE = Automatic; 582 | CURRENT_PROJECT_VERSION = 1; 583 | DEVELOPMENT_TEAM = 3U3296XZA5; 584 | GCC_C_LANGUAGE_STANDARD = gnu11; 585 | GENERATE_INFOPLIST_FILE = YES; 586 | INFOPLIST_FILE = live_activity_test/Info.plist; 587 | INFOPLIST_KEY_CFBundleDisplayName = live_activity_test; 588 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 589 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 590 | LD_RUNPATH_SEARCH_PATHS = ( 591 | "$(inherited)", 592 | "@executable_path/Frameworks", 593 | "@executable_path/../../Frameworks", 594 | ); 595 | MARKETING_VERSION = 1.0; 596 | MTL_FAST_MATH = YES; 597 | PRODUCT_BUNDLE_IDENTIFIER = "com.fluttercandies.flutterLiveActivitiesExample.live-activity-test"; 598 | PRODUCT_NAME = "$(TARGET_NAME)"; 599 | SKIP_INSTALL = YES; 600 | SWIFT_EMIT_LOC_STRINGS = YES; 601 | SWIFT_VERSION = 5.0; 602 | TARGETED_DEVICE_FAMILY = "1,2"; 603 | }; 604 | name = Profile; 605 | }; 606 | 97C147031CF9000F007C117D /* Debug */ = { 607 | isa = XCBuildConfiguration; 608 | buildSettings = { 609 | ALWAYS_SEARCH_USER_PATHS = NO; 610 | CLANG_ANALYZER_NONNULL = YES; 611 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 612 | CLANG_CXX_LIBRARY = "libc++"; 613 | CLANG_ENABLE_MODULES = YES; 614 | CLANG_ENABLE_OBJC_ARC = YES; 615 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 616 | CLANG_WARN_BOOL_CONVERSION = YES; 617 | CLANG_WARN_COMMA = YES; 618 | CLANG_WARN_CONSTANT_CONVERSION = YES; 619 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 620 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 621 | CLANG_WARN_EMPTY_BODY = YES; 622 | CLANG_WARN_ENUM_CONVERSION = YES; 623 | CLANG_WARN_INFINITE_RECURSION = YES; 624 | CLANG_WARN_INT_CONVERSION = YES; 625 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 626 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 627 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 628 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 629 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 630 | CLANG_WARN_STRICT_PROTOTYPES = YES; 631 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 632 | CLANG_WARN_UNREACHABLE_CODE = YES; 633 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 634 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 635 | COPY_PHASE_STRIP = NO; 636 | DEBUG_INFORMATION_FORMAT = dwarf; 637 | ENABLE_STRICT_OBJC_MSGSEND = YES; 638 | ENABLE_TESTABILITY = YES; 639 | GCC_C_LANGUAGE_STANDARD = gnu99; 640 | GCC_DYNAMIC_NO_PIC = NO; 641 | GCC_NO_COMMON_BLOCKS = YES; 642 | GCC_OPTIMIZATION_LEVEL = 0; 643 | GCC_PREPROCESSOR_DEFINITIONS = ( 644 | "DEBUG=1", 645 | "$(inherited)", 646 | ); 647 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 648 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 649 | GCC_WARN_UNDECLARED_SELECTOR = YES; 650 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 651 | GCC_WARN_UNUSED_FUNCTION = YES; 652 | GCC_WARN_UNUSED_VARIABLE = YES; 653 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 654 | MTL_ENABLE_DEBUG_INFO = YES; 655 | ONLY_ACTIVE_ARCH = YES; 656 | SDKROOT = iphoneos; 657 | TARGETED_DEVICE_FAMILY = "1,2"; 658 | }; 659 | name = Debug; 660 | }; 661 | 97C147041CF9000F007C117D /* Release */ = { 662 | isa = XCBuildConfiguration; 663 | buildSettings = { 664 | ALWAYS_SEARCH_USER_PATHS = NO; 665 | CLANG_ANALYZER_NONNULL = YES; 666 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 667 | CLANG_CXX_LIBRARY = "libc++"; 668 | CLANG_ENABLE_MODULES = YES; 669 | CLANG_ENABLE_OBJC_ARC = YES; 670 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 671 | CLANG_WARN_BOOL_CONVERSION = YES; 672 | CLANG_WARN_COMMA = YES; 673 | CLANG_WARN_CONSTANT_CONVERSION = YES; 674 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 675 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 676 | CLANG_WARN_EMPTY_BODY = YES; 677 | CLANG_WARN_ENUM_CONVERSION = YES; 678 | CLANG_WARN_INFINITE_RECURSION = YES; 679 | CLANG_WARN_INT_CONVERSION = YES; 680 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 681 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 682 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 683 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 684 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 685 | CLANG_WARN_STRICT_PROTOTYPES = YES; 686 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 687 | CLANG_WARN_UNREACHABLE_CODE = YES; 688 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 689 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 690 | COPY_PHASE_STRIP = NO; 691 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 692 | ENABLE_NS_ASSERTIONS = NO; 693 | ENABLE_STRICT_OBJC_MSGSEND = YES; 694 | GCC_C_LANGUAGE_STANDARD = gnu99; 695 | GCC_NO_COMMON_BLOCKS = YES; 696 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 697 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 698 | GCC_WARN_UNDECLARED_SELECTOR = YES; 699 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 700 | GCC_WARN_UNUSED_FUNCTION = YES; 701 | GCC_WARN_UNUSED_VARIABLE = YES; 702 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 703 | MTL_ENABLE_DEBUG_INFO = NO; 704 | SDKROOT = iphoneos; 705 | SUPPORTED_PLATFORMS = iphoneos; 706 | SWIFT_COMPILATION_MODE = wholemodule; 707 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 708 | TARGETED_DEVICE_FAMILY = "1,2"; 709 | VALIDATE_PRODUCT = YES; 710 | }; 711 | name = Release; 712 | }; 713 | 97C147061CF9000F007C117D /* Debug */ = { 714 | isa = XCBuildConfiguration; 715 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 716 | buildSettings = { 717 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 718 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 719 | CLANG_ENABLE_MODULES = YES; 720 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 721 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 722 | DEVELOPMENT_TEAM = 3U3296XZA5; 723 | ENABLE_BITCODE = NO; 724 | INFOPLIST_FILE = Runner/Info.plist; 725 | LD_RUNPATH_SEARCH_PATHS = ( 726 | "$(inherited)", 727 | "@executable_path/Frameworks", 728 | ); 729 | PRODUCT_BUNDLE_IDENTIFIER = com.fluttercandies.flutterLiveActivitiesExample; 730 | PRODUCT_NAME = "$(TARGET_NAME)"; 731 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 732 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 733 | SWIFT_VERSION = 5.0; 734 | VERSIONING_SYSTEM = "apple-generic"; 735 | }; 736 | name = Debug; 737 | }; 738 | 97C147071CF9000F007C117D /* Release */ = { 739 | isa = XCBuildConfiguration; 740 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 741 | buildSettings = { 742 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 743 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 744 | CLANG_ENABLE_MODULES = YES; 745 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 746 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 747 | DEVELOPMENT_TEAM = 3U3296XZA5; 748 | ENABLE_BITCODE = NO; 749 | INFOPLIST_FILE = Runner/Info.plist; 750 | LD_RUNPATH_SEARCH_PATHS = ( 751 | "$(inherited)", 752 | "@executable_path/Frameworks", 753 | ); 754 | PRODUCT_BUNDLE_IDENTIFIER = com.fluttercandies.flutterLiveActivitiesExample; 755 | PRODUCT_NAME = "$(TARGET_NAME)"; 756 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 757 | SWIFT_VERSION = 5.0; 758 | VERSIONING_SYSTEM = "apple-generic"; 759 | }; 760 | name = Release; 761 | }; 762 | /* End XCBuildConfiguration section */ 763 | 764 | /* Begin XCConfigurationList section */ 765 | 2770E02B291511C600771F44 /* Build configuration list for PBXNativeTarget "live_activity_testExtension" */ = { 766 | isa = XCConfigurationList; 767 | buildConfigurations = ( 768 | 2770E02C291511C600771F44 /* Debug */, 769 | 2770E02D291511C600771F44 /* Release */, 770 | 2770E02E291511C600771F44 /* Profile */, 771 | ); 772 | defaultConfigurationIsVisible = 0; 773 | defaultConfigurationName = Release; 774 | }; 775 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 776 | isa = XCConfigurationList; 777 | buildConfigurations = ( 778 | 97C147031CF9000F007C117D /* Debug */, 779 | 97C147041CF9000F007C117D /* Release */, 780 | 249021D3217E4FDB00AE95B9 /* Profile */, 781 | ); 782 | defaultConfigurationIsVisible = 0; 783 | defaultConfigurationName = Release; 784 | }; 785 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 786 | isa = XCConfigurationList; 787 | buildConfigurations = ( 788 | 97C147061CF9000F007C117D /* Debug */, 789 | 97C147071CF9000F007C117D /* Release */, 790 | 249021D4217E4FDB00AE95B9 /* Profile */, 791 | ); 792 | defaultConfigurationIsVisible = 0; 793 | defaultConfigurationName = Release; 794 | }; 795 | /* End XCConfigurationList section */ 796 | }; 797 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 798 | } 799 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | Flutter Live Activities 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | flutter_live_activities_example 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleURLTypes 26 | 27 | 28 | CFBundleTypeRole 29 | Editor 30 | CFBundleURLSchemes 31 | 32 | fla 33 | 34 | 35 | 36 | CFBundleVersion 37 | $(FLUTTER_BUILD_NUMBER) 38 | LSRequiresIPhoneOS 39 | 40 | NSSupportsLiveActivities 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | UIViewControllerBasedStatusBarAppearance 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.live_example 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/Assets.xcassets/WidgetBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.widgetkit-extension 9 | 10 | NSSupportsLiveActivities 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/live_activity_test.intentdefinition: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | INEnums 6 | 7 | INIntentDefinitionModelVersion 8 | 1.2 9 | INIntentDefinitionNamespace 10 | 88xZPY 11 | INIntentDefinitionSystemVersion 12 | 20A294 13 | INIntentDefinitionToolsBuildVersion 14 | 12A6144 15 | INIntentDefinitionToolsVersion 16 | 12.0 17 | INIntents 18 | 19 | 20 | INIntentCategory 21 | information 22 | INIntentDescriptionID 23 | tVvJ9c 24 | INIntentEligibleForWidgets 25 | 26 | INIntentIneligibleForSuggestions 27 | 28 | INIntentName 29 | Configuration 30 | INIntentResponse 31 | 32 | INIntentResponseCodes 33 | 34 | 35 | INIntentResponseCodeName 36 | success 37 | INIntentResponseCodeSuccess 38 | 39 | 40 | 41 | INIntentResponseCodeName 42 | failure 43 | 44 | 45 | 46 | INIntentTitle 47 | Configuration 48 | INIntentTitleID 49 | gpCwrM 50 | INIntentType 51 | Custom 52 | INIntentVerb 53 | View 54 | 55 | 56 | INTypes 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/live_activity_testBundle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // live_activity_testBundle.swift 3 | // live_activity_test 4 | // 5 | // Created by Mike on 2022/11/4. 6 | // 7 | 8 | import WidgetKit 9 | import SwiftUI 10 | 11 | @main 12 | struct live_activity_testBundle: WidgetBundle { 13 | var body: some Widget { 14 | live_activity_testLiveActivity() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/ios/live_activity_test/live_activity_testLiveActivity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // live_activity_testLiveActivity.swift 3 | // live_activity_test 4 | // 5 | // Created by Mike on 2022/11/4. 6 | // 7 | 8 | import ActivityKit 9 | import SwiftUI 10 | import WidgetKit 11 | 12 | // TestData 13 | struct TestData { 14 | var text: String 15 | 16 | init?(JSONData data: [String: String]) { 17 | self.text = data["text"] ?? "" 18 | } 19 | 20 | init(text: String) { 21 | self.text = text 22 | } 23 | } 24 | 25 | struct FlutterLiveActivities: ActivityAttributes, Identifiable { 26 | public typealias LiveData = ContentState 27 | 28 | public struct ContentState: Codable, Hashable { 29 | var data: [String: String] 30 | } 31 | 32 | var id = UUID() 33 | } 34 | 35 | @available(iOSApplicationExtension 16.1, *) 36 | struct live_activity_testLiveActivity: Widget { 37 | var body: some WidgetConfiguration { 38 | ActivityConfiguration(for: FlutterLiveActivities.self) { context in 39 | let data = TestData(JSONData: context.state.data) 40 | 41 | // Lock screen/banner UI goes here 42 | 43 | VStack(alignment: .leading) { 44 | Text(data?.text ?? "") 45 | HStack { 46 | Link(destination: URL(string: "fla://xx.xx/tap/A")!) { 47 | Text("A") 48 | .frame(width: 40, height: 40) 49 | .background(.blue) 50 | } 51 | 52 | Link(destination: URL(string: "fla://xx.xx/tap/B")!) { 53 | Text("B") 54 | .frame(width: 40, height: 40) 55 | .background(.blue) 56 | } 57 | 58 | Link(destination: URL(string: "fla://xx.xx/tap/C")!) { 59 | Text("C") 60 | .frame(width: 40, height: 40) 61 | .background(.blue) 62 | } 63 | } 64 | .frame(width: .infinity, height: .infinity) 65 | } 66 | .padding(20) 67 | .activityBackgroundTint(Color.cyan) 68 | .activitySystemActionForegroundColor(Color.black) 69 | 70 | } dynamicIsland: { context in 71 | 72 | let data = TestData(JSONData: context.state.data) 73 | 74 | return DynamicIsland { 75 | // Expanded UI goes here. Compose the expanded UI through 76 | // various regions, like leading/trailing/center/bottom 77 | DynamicIslandExpandedRegion(.leading) { 78 | if let imageContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.live_example")?.appendingPathComponent("test-img"), 79 | let uiImage = UIImage(contentsOfFile: imageContainer.path()) 80 | { 81 | Image(uiImage: uiImage) 82 | .resizable() 83 | .frame(width: 53, height: 53) 84 | .cornerRadius(13) 85 | .overlay( 86 | RoundedRectangle(cornerRadius: 15) 87 | .stroke(.white.opacity(0.15), lineWidth: 1) 88 | ) 89 | } else { 90 | Text("Leading") 91 | } 92 | } 93 | DynamicIslandExpandedRegion(.trailing) { 94 | Text("Trailing") 95 | } 96 | DynamicIslandExpandedRegion(.bottom) { 97 | Link(destination: URL(string: "fla://xx.xx/tap/HelloWorld")!) { 98 | Text(data?.text ?? "") 99 | .background(.red) 100 | } 101 | // more content 102 | } 103 | } compactLeading: { 104 | Text("L") 105 | } compactTrailing: { 106 | Text("T") 107 | } minimal: { 108 | Text("Min") 109 | } 110 | .widgetURL(URL(string: "fla://xx.xx/tap/DynamicIsland")) 111 | .keylineTint(Color.red) 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /example/ios/live_activity_testExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.live_example 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/lib/helper/image_helper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:extended_image/extended_image.dart'; 4 | import 'package:path/path.dart'; 5 | import 'package:path_provider/path_provider.dart'; 6 | 7 | /// Image Helper 8 | class ImageHelper { 9 | ImageHelper._(); 10 | 11 | /// get file path from url 12 | static Future getFilePathFromUrl(String url) async { 13 | await preloadImage(url); 14 | return (await getImageFile(url))?.path; 15 | } 16 | 17 | /// Pre-cache images by url 18 | static Future preloadImage(String url) async { 19 | final ExtendedNetworkImageProvider provider = 20 | ExtendedNetworkImageProvider(url, cache: true); 21 | 22 | await provider.getNetworkImageData(); 23 | } 24 | 25 | /// Get the cache file by url 26 | static Future getImageFile(String? url) async { 27 | try { 28 | if (url == null) { 29 | return null; 30 | } 31 | 32 | final Directory _cacheImagesDirectory = Directory( 33 | join((await getTemporaryDirectory()).path, cacheImageFolderName)); 34 | 35 | if (!_cacheImagesDirectory.existsSync()) { 36 | return null; 37 | } 38 | 39 | final String md5Key = keyToMd5(url); 40 | final File cacheFlie = File(join(_cacheImagesDirectory.path, md5Key)); 41 | 42 | if (cacheFlie.existsSync()) { 43 | return cacheFlie; 44 | } 45 | } catch (e) { 46 | // error('getImageFile error : $e'); 47 | } 48 | 49 | return null; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:developer' as dev; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_live_activities/flutter_live_activities.dart'; 6 | import 'package:flutter_live_activities_example/helper/image_helper.dart'; 7 | 8 | void main() { 9 | runApp(const MyApp()); 10 | } 11 | 12 | class MyApp extends StatelessWidget { 13 | const MyApp({super.key}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return const MaterialApp( 18 | title: 'Flutter Demo', 19 | home: Home(), 20 | ); 21 | } 22 | } 23 | 24 | class Home extends StatefulWidget { 25 | const Home({super.key}); 26 | 27 | @override 28 | State createState() => _HomeState(); 29 | } 30 | 31 | class _HomeState extends State { 32 | final FlutterLiveActivities _liveActivities = FlutterLiveActivities(); 33 | String? _activityId; 34 | bool? _enabled; 35 | 36 | StreamSubscription? _subscription; 37 | 38 | String _info = ''; 39 | 40 | @override 41 | void initState() { 42 | super.initState(); 43 | _initStream(); 44 | _getInitUri(); 45 | } 46 | 47 | Future _initStream() async { 48 | _subscription ??= _liveActivities.uriStream().listen((Uri? uri) { 49 | dev.log('deeplink uri: $uri'); 50 | if (uri != null) _setInfo(uri.toString()); 51 | }); 52 | } 53 | 54 | void _cancelStream() { 55 | _subscription?.cancel(); 56 | _subscription = null; 57 | } 58 | 59 | @override 60 | void dispose() { 61 | _cancelStream(); 62 | super.dispose(); 63 | } 64 | 65 | Future _getInitUri() async { 66 | _setInfo('initUri : ${(await _liveActivities.getInitUri()) ?? ''}'); 67 | } 68 | 69 | void _setInfo(String info) { 70 | setState(() { 71 | _info = info; 72 | }); 73 | } 74 | 75 | Future _checkEnabled() async { 76 | _enabled = await _liveActivities.areActivitiesEnabled(); 77 | setState(() {}); 78 | } 79 | 80 | Future _getAllActivities() async { 81 | _setInfo((await _liveActivities.getAllActivities()).toString()); 82 | } 83 | 84 | Future _endAllActivities() async { 85 | await _liveActivities.endAllActivities(); 86 | } 87 | 88 | Future _createActivity() async { 89 | _initStream(); 90 | 91 | _activityId = await _liveActivities 92 | .createActivity({'text': 'Hello World'}); 93 | 94 | setState(() {}); 95 | } 96 | 97 | Future _updateActivity() async { 98 | _liveActivities.updateActivity( 99 | _activityId!, {'text': 'Update Hello World'}); 100 | } 101 | 102 | Future _endActivity() async { 103 | _cancelStream(); 104 | _liveActivities.endActivity(_activityId!); 105 | _activityId = null; 106 | _setInfo(''); 107 | } 108 | 109 | Future _sendImageToGroup() async { 110 | const String url = 111 | 'https://cdn.iconscout.com/icon/free/png-256/flutter-2752187-2285004.png'; 112 | final String? path = await ImageHelper.getFilePathFromUrl(url); 113 | 114 | if (path != null) { 115 | _liveActivities.sendImageToGroup( 116 | id: 'test-img', 117 | filePath: path, 118 | groupId: 'group.live_example', 119 | ); 120 | } 121 | } 122 | 123 | @override 124 | Widget build(BuildContext context) { 125 | return Scaffold( 126 | appBar: AppBar( 127 | title: const Text('Flutter Live Activities'), 128 | ), 129 | body: SizedBox.expand( 130 | child: Padding( 131 | padding: const EdgeInsets.all(16.0), 132 | child: Column( 133 | mainAxisAlignment: MainAxisAlignment.center, 134 | children: [ 135 | Text('Info: $_info', textAlign: TextAlign.center), 136 | ElevatedButton( 137 | onPressed: _checkEnabled, 138 | child: Text('Enabled: $_enabled'), 139 | ), 140 | if (_enabled == true) 141 | ElevatedButton( 142 | onPressed: _getAllActivities, 143 | child: const Text('getAllActivities'), 144 | ), 145 | if (_enabled == true) 146 | ElevatedButton( 147 | onPressed: _getInitUri, 148 | child: const Text('getInitUri'), 149 | ), 150 | ElevatedButton( 151 | onPressed: _sendImageToGroup, 152 | child: const Text('Send image to group'), 153 | ), 154 | if (_enabled == true && _activityId == null) 155 | ElevatedButton( 156 | onPressed: _createActivity, 157 | child: const Text('Create live activity'), 158 | ), 159 | if (_activityId != null) 160 | ElevatedButton( 161 | onPressed: _updateActivity, 162 | child: Text( 163 | 'Update live activity $_activityId', 164 | textAlign: TextAlign.center, 165 | ), 166 | ), 167 | if (_activityId != null) 168 | ElevatedButton( 169 | onPressed: _endActivity, 170 | child: Text( 171 | 'End live activity $_activityId', 172 | textAlign: TextAlign.center, 173 | ), 174 | ), 175 | if (_enabled == true) 176 | ElevatedButton( 177 | onPressed: _endAllActivities, 178 | child: const Text('endAllActivities'), 179 | ), 180 | ], 181 | ), 182 | ), 183 | ), 184 | ); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "2.9.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.2.1" 25 | clock: 26 | dependency: transitive 27 | description: 28 | name: clock 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "1.1.1" 32 | collection: 33 | dependency: transitive 34 | description: 35 | name: collection 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "1.16.0" 39 | crypto: 40 | dependency: transitive 41 | description: 42 | name: crypto 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "3.0.2" 46 | cupertino_icons: 47 | dependency: "direct main" 48 | description: 49 | name: cupertino_icons 50 | url: "https://pub.flutter-io.cn" 51 | source: hosted 52 | version: "1.0.5" 53 | extended_image: 54 | dependency: "direct main" 55 | description: 56 | name: extended_image 57 | url: "https://pub.flutter-io.cn" 58 | source: hosted 59 | version: "6.3.2" 60 | extended_image_library: 61 | dependency: transitive 62 | description: 63 | name: extended_image_library 64 | url: "https://pub.flutter-io.cn" 65 | source: hosted 66 | version: "3.4.1" 67 | fake_async: 68 | dependency: transitive 69 | description: 70 | name: fake_async 71 | url: "https://pub.flutter-io.cn" 72 | source: hosted 73 | version: "1.3.1" 74 | ffi: 75 | dependency: transitive 76 | description: 77 | name: ffi 78 | url: "https://pub.flutter-io.cn" 79 | source: hosted 80 | version: "2.0.1" 81 | file: 82 | dependency: transitive 83 | description: 84 | name: file 85 | url: "https://pub.flutter-io.cn" 86 | source: hosted 87 | version: "6.1.4" 88 | flutter: 89 | dependency: "direct main" 90 | description: flutter 91 | source: sdk 92 | version: "0.0.0" 93 | flutter_lints: 94 | dependency: "direct dev" 95 | description: 96 | name: flutter_lints 97 | url: "https://pub.flutter-io.cn" 98 | source: hosted 99 | version: "2.0.1" 100 | flutter_live_activities: 101 | dependency: "direct main" 102 | description: 103 | path: ".." 104 | relative: true 105 | source: path 106 | version: "0.0.5" 107 | flutter_test: 108 | dependency: "direct dev" 109 | description: flutter 110 | source: sdk 111 | version: "0.0.0" 112 | http: 113 | dependency: transitive 114 | description: 115 | name: http 116 | url: "https://pub.flutter-io.cn" 117 | source: hosted 118 | version: "0.13.5" 119 | http_client_helper: 120 | dependency: transitive 121 | description: 122 | name: http_client_helper 123 | url: "https://pub.flutter-io.cn" 124 | source: hosted 125 | version: "2.0.3" 126 | http_parser: 127 | dependency: transitive 128 | description: 129 | name: http_parser 130 | url: "https://pub.flutter-io.cn" 131 | source: hosted 132 | version: "4.0.2" 133 | lints: 134 | dependency: transitive 135 | description: 136 | name: lints 137 | url: "https://pub.flutter-io.cn" 138 | source: hosted 139 | version: "2.0.1" 140 | matcher: 141 | dependency: transitive 142 | description: 143 | name: matcher 144 | url: "https://pub.flutter-io.cn" 145 | source: hosted 146 | version: "0.12.12" 147 | material_color_utilities: 148 | dependency: transitive 149 | description: 150 | name: material_color_utilities 151 | url: "https://pub.flutter-io.cn" 152 | source: hosted 153 | version: "0.1.5" 154 | meta: 155 | dependency: transitive 156 | description: 157 | name: meta 158 | url: "https://pub.flutter-io.cn" 159 | source: hosted 160 | version: "1.8.0" 161 | path: 162 | dependency: "direct main" 163 | description: 164 | name: path 165 | url: "https://pub.flutter-io.cn" 166 | source: hosted 167 | version: "1.8.2" 168 | path_provider: 169 | dependency: "direct main" 170 | description: 171 | name: path_provider 172 | url: "https://pub.flutter-io.cn" 173 | source: hosted 174 | version: "2.0.11" 175 | path_provider_android: 176 | dependency: transitive 177 | description: 178 | name: path_provider_android 179 | url: "https://pub.flutter-io.cn" 180 | source: hosted 181 | version: "2.0.21" 182 | path_provider_ios: 183 | dependency: transitive 184 | description: 185 | name: path_provider_ios 186 | url: "https://pub.flutter-io.cn" 187 | source: hosted 188 | version: "2.0.11" 189 | path_provider_linux: 190 | dependency: transitive 191 | description: 192 | name: path_provider_linux 193 | url: "https://pub.flutter-io.cn" 194 | source: hosted 195 | version: "2.1.7" 196 | path_provider_macos: 197 | dependency: transitive 198 | description: 199 | name: path_provider_macos 200 | url: "https://pub.flutter-io.cn" 201 | source: hosted 202 | version: "2.0.6" 203 | path_provider_platform_interface: 204 | dependency: transitive 205 | description: 206 | name: path_provider_platform_interface 207 | url: "https://pub.flutter-io.cn" 208 | source: hosted 209 | version: "2.0.5" 210 | path_provider_windows: 211 | dependency: transitive 212 | description: 213 | name: path_provider_windows 214 | url: "https://pub.flutter-io.cn" 215 | source: hosted 216 | version: "2.1.3" 217 | platform: 218 | dependency: transitive 219 | description: 220 | name: platform 221 | url: "https://pub.flutter-io.cn" 222 | source: hosted 223 | version: "3.1.0" 224 | plugin_platform_interface: 225 | dependency: transitive 226 | description: 227 | name: plugin_platform_interface 228 | url: "https://pub.flutter-io.cn" 229 | source: hosted 230 | version: "2.1.3" 231 | process: 232 | dependency: transitive 233 | description: 234 | name: process 235 | url: "https://pub.flutter-io.cn" 236 | source: hosted 237 | version: "4.2.4" 238 | sky_engine: 239 | dependency: transitive 240 | description: flutter 241 | source: sdk 242 | version: "0.0.99" 243 | source_span: 244 | dependency: transitive 245 | description: 246 | name: source_span 247 | url: "https://pub.flutter-io.cn" 248 | source: hosted 249 | version: "1.9.0" 250 | stack_trace: 251 | dependency: transitive 252 | description: 253 | name: stack_trace 254 | url: "https://pub.flutter-io.cn" 255 | source: hosted 256 | version: "1.10.0" 257 | stream_channel: 258 | dependency: transitive 259 | description: 260 | name: stream_channel 261 | url: "https://pub.flutter-io.cn" 262 | source: hosted 263 | version: "2.1.0" 264 | string_scanner: 265 | dependency: transitive 266 | description: 267 | name: string_scanner 268 | url: "https://pub.flutter-io.cn" 269 | source: hosted 270 | version: "1.1.1" 271 | term_glyph: 272 | dependency: transitive 273 | description: 274 | name: term_glyph 275 | url: "https://pub.flutter-io.cn" 276 | source: hosted 277 | version: "1.2.1" 278 | test_api: 279 | dependency: transitive 280 | description: 281 | name: test_api 282 | url: "https://pub.flutter-io.cn" 283 | source: hosted 284 | version: "0.4.12" 285 | typed_data: 286 | dependency: transitive 287 | description: 288 | name: typed_data 289 | url: "https://pub.flutter-io.cn" 290 | source: hosted 291 | version: "1.3.1" 292 | vector_math: 293 | dependency: transitive 294 | description: 295 | name: vector_math 296 | url: "https://pub.flutter-io.cn" 297 | source: hosted 298 | version: "2.1.2" 299 | win32: 300 | dependency: transitive 301 | description: 302 | name: win32 303 | url: "https://pub.flutter-io.cn" 304 | source: hosted 305 | version: "3.1.1" 306 | xdg_directories: 307 | dependency: transitive 308 | description: 309 | name: xdg_directories 310 | url: "https://pub.flutter-io.cn" 311 | source: hosted 312 | version: "0.2.0+2" 313 | sdks: 314 | dart: ">=2.18.2 <3.0.0" 315 | flutter: ">=3.3.0" 316 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_live_activities_example 2 | description: Demonstrates how to use the flutter_live_activities plugin. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | environment: 9 | sdk: '>=2.18.2 <3.0.0' 10 | 11 | # Dependencies specify other packages that your package needs in order to work. 12 | # To automatically upgrade your package dependencies to the latest versions 13 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 14 | # dependencies can be manually updated by changing the version numbers below to 15 | # the latest version available on pub.dev. To see which dependencies have newer 16 | # versions available, run `flutter pub outdated`. 17 | dependencies: 18 | flutter: 19 | sdk: flutter 20 | 21 | flutter_live_activities: 22 | # When depending on this package from a real application you should use: 23 | # flutter_live_activities: ^x.y.z 24 | # See https://dart.dev/tools/pub/dependencies#version-constraints 25 | # The example app is bundled with the plugin so we use a path dependency on 26 | # the parent directory to use the current plugin's version. 27 | path: ../ 28 | 29 | # The following adds the Cupertino Icons font to your application. 30 | # Use with the CupertinoIcons class for iOS style icons. 31 | cupertino_icons: ^1.0.2 32 | extended_image: ^6.3.2 33 | path: ^1.8.2 34 | path_provider: ^2.0.11 35 | 36 | dev_dependencies: 37 | flutter_test: 38 | sdk: flutter 39 | 40 | # The "flutter_lints" package below contains a set of recommended lints to 41 | # encourage good coding practices. The lint set provided by the package is 42 | # activated in the `analysis_options.yaml` file located at the root of your 43 | # package. See that file for information about deactivating specific lint 44 | # rules and activating additional ones. 45 | flutter_lints: ^2.0.0 46 | 47 | # For information on the generic Dart part of this file, see the 48 | # following page: https://dart.dev/tools/pub/pubspec 49 | 50 | # The following section is specific to Flutter packages. 51 | flutter: 52 | 53 | # The following line ensures that the Material Icons font is 54 | # included with your application, so that you can use the icons in 55 | # the material Icons class. 56 | uses-material-design: true 57 | 58 | # To add assets to your application, add an assets section, like this: 59 | # assets: 60 | # - images/a_dot_burr.jpeg 61 | # - images/a_dot_ham.jpeg 62 | 63 | # An image asset can refer to one or more resolution-specific "variants", see 64 | # https://flutter.dev/assets-and-images/#resolution-aware 65 | 66 | # For details regarding adding assets from package dependencies, see 67 | # https://flutter.dev/assets-and-images/#from-packages 68 | 69 | # To add custom fonts to your application, add a fonts section here, 70 | # in this "flutter" section. Each entry in this list should have a 71 | # "family" key with the font family name, and a "fonts" key with a 72 | # list giving the asset and other descriptors for the font. For 73 | # example: 74 | # fonts: 75 | # - family: Schyler 76 | # fonts: 77 | # - asset: fonts/Schyler-Regular.ttf 78 | # - asset: fonts/Schyler-Italic.ttf 79 | # style: italic 80 | # - family: Trajan Pro 81 | # fonts: 82 | # - asset: fonts/TrajanPro.ttf 83 | # - asset: fonts/TrajanPro_Bold.ttf 84 | # weight: 700 85 | # 86 | # For details regarding fonts from package dependencies, 87 | # see https://flutter.dev/custom-fonts/#from-packages 88 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluttercandies/flutter_live_activities/b0c2c0c27df7349b84361b2ed00c0bbfa9e5ed76/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/FlutterLiveActivities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FlutterLiveActivities.swift 3 | // flutter_live_activities 4 | // 5 | // Created by Mike on 2022/11/4. 6 | // 7 | 8 | import ActivityKit 9 | 10 | struct FlutterLiveActivities: ActivityAttributes, Identifiable { 11 | public typealias LiveData = ContentState 12 | 13 | public struct ContentState: Codable, Hashable { 14 | var data: [String: String] 15 | } 16 | 17 | var id = UUID() 18 | } 19 | -------------------------------------------------------------------------------- /ios/Classes/FlutterLiveActivitiesPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FlutterLiveActivitiesPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/Classes/FlutterLiveActivitiesPlugin.m: -------------------------------------------------------------------------------- 1 | #import "FlutterLiveActivitiesPlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "flutter_live_activities-Swift.h" 9 | #endif 10 | 11 | @implementation FlutterLiveActivitiesPlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftFlutterLiveActivitiesPlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ios/Classes/SwiftFlutterLiveActivitiesPlugin.swift: -------------------------------------------------------------------------------- 1 | import ActivityKit 2 | import Flutter 3 | import UIKit 4 | 5 | public class SwiftFlutterLiveActivitiesPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { 6 | private var eventSink: FlutterEventSink? 7 | private var urlScheme: String? 8 | 9 | private var initialUrl: URL? 10 | 11 | public static func register(with registrar: FlutterPluginRegistrar) { 12 | let channel = FlutterMethodChannel(name: "flutter_live_activities", binaryMessenger: registrar.messenger()) 13 | let eventChannel = FlutterEventChannel(name: "flutter_live_activities/event", binaryMessenger: registrar.messenger()) 14 | 15 | let instance = SwiftFlutterLiveActivitiesPlugin() 16 | registrar.addMethodCallDelegate(instance, channel: channel) 17 | eventChannel.setStreamHandler(instance) 18 | registrar.addApplicationDelegate(instance) 19 | } 20 | 21 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 22 | if #available(iOS 16.1, *) { 23 | switch call.method { 24 | case "init": 25 | guard let args = call.arguments as? [String: Any] else { 26 | return 27 | } 28 | if let scheme = args["urlScheme"] as? String { 29 | urlScheme = scheme 30 | } else { 31 | result(FlutterError(code: "DATA_ERROR", message: "'liveId' is invalid", details: nil)) 32 | } 33 | case "getInitUri": 34 | result(initialUrl?.absoluteString) 35 | case "createActivity": 36 | guard let args = call.arguments as? [String: Any] else { 37 | return 38 | } 39 | if let data = args["data"] as? [String: String] { 40 | createActivity(data: data, result: result) 41 | } else { 42 | result(FlutterError(code: "DATA_ERROR", message: "'data' is invalid", details: nil)) 43 | } 44 | case "updateActivity": 45 | guard let args = call.arguments as? [String: Any] else { 46 | return 47 | } 48 | if let liveId = args["liveId"] as? String, let data = args["data"] as? [String: String] { 49 | updateActivity(liveId: liveId, data: data, result: result) 50 | } else { 51 | result(FlutterError(code: "DATA_ERROR", message: "'data' or 'liveId' is invalid", details: nil)) 52 | } 53 | case "endActivity": 54 | guard let args = call.arguments as? [String: Any] else { 55 | return 56 | } 57 | if let liveId = args["liveId"] as? String { 58 | endActivity(liveId: liveId, result: result) 59 | } else { 60 | result(FlutterError(code: "DATA_ERROR", message: "'liveId' is invalid", details: nil)) 61 | } 62 | case "getAllActivities": 63 | getAllActivities(result: result) 64 | case "endAllActivities": 65 | endAllActivities(result: result) 66 | case "getActivityState": 67 | guard let args = call.arguments as? [String: Any] else { 68 | return 69 | } 70 | 71 | if let liveId = args["liveId"] as? String { 72 | getActivityState(liveId: liveId, result: result) 73 | } else { 74 | result(FlutterError(code: "DATA_ERROR", message: "'liveId' is invalid", details: nil)) 75 | } 76 | 77 | case "areActivitiesEnabled": 78 | areActivitiesEnabled(result: result) 79 | case "sendImageToGroup": 80 | guard let args = call.arguments as? [String: Any] else { 81 | result(FlutterError(code: "DATA_ERROR", message: "parameter is invalid", details: nil)) 82 | return 83 | } 84 | 85 | if let data = args as? [String: String] { 86 | receiveImage(data: data, result: result) 87 | } else { 88 | result(FlutterError(code: "DATA_ERROR", message: "parameter is invalid", details: nil)) 89 | } 90 | 91 | default: 92 | break 93 | } 94 | } else { 95 | print("This iOS version is not supported") 96 | result(nil) 97 | } 98 | } 99 | 100 | @available(iOS 16.1, *) 101 | func createActivity(data: [String: String], result: @escaping FlutterResult) { 102 | let attributes = FlutterLiveActivities() 103 | let contentState = FlutterLiveActivities.LiveData(data: data) 104 | 105 | do { 106 | let activity = try Activity.request( 107 | attributes: attributes, 108 | contentState: contentState, 109 | pushType: nil) 110 | result(activity.id) 111 | } catch { 112 | result(FlutterError(code: "LIVE_ACTIVITY_LAUNCH_ERROR", message: "launch live activity error", details: error.localizedDescription)) 113 | } 114 | } 115 | 116 | @available(iOS 16.1, *) 117 | func updateActivity(liveId: String, data: [String: String], result: @escaping FlutterResult) { 118 | Task { 119 | for activity in Activity.activities { 120 | if liveId == activity.id { 121 | let updatedStatus: FlutterLiveActivities.LiveData = .init(data: data) 122 | await activity.update(using: updatedStatus) 123 | result(true) 124 | return 125 | } 126 | } 127 | 128 | result(false) 129 | } 130 | } 131 | 132 | @available(iOS 16.1, *) 133 | func endActivity(liveId: String, result: @escaping FlutterResult) { 134 | Task { 135 | for activity in Activity.activities { 136 | if liveId == activity.id { 137 | await activity.end(dismissalPolicy: .immediate) 138 | result(true) 139 | return 140 | } 141 | } 142 | 143 | result(false) 144 | } 145 | } 146 | 147 | @available(iOS 16.1, *) 148 | func getActivityState(liveId: String, result: @escaping FlutterResult) { 149 | Task { 150 | for activity in Activity.activities { 151 | if liveId == activity.id { 152 | switch activity.activityState { 153 | case .active: 154 | result(0) 155 | case .ended: 156 | result(1) 157 | case .dismissed: 158 | result(2) 159 | @unknown default: 160 | result(3) 161 | } 162 | break 163 | } 164 | } 165 | } 166 | } 167 | 168 | @available(iOS 16.1, *) 169 | func getAllActivities(result: @escaping FlutterResult) { 170 | var list: [String] = [] 171 | for activity in Activity.activities { 172 | list.append(activity.id) 173 | } 174 | result(list.joined(separator: ",")) 175 | } 176 | 177 | @available(iOS 16.1, *) 178 | func endAllActivities(result: @escaping FlutterResult) { 179 | Task { 180 | for activity in Activity.activities { 181 | await activity.end(dismissalPolicy: .immediate) 182 | } 183 | 184 | result(true) 185 | } 186 | } 187 | 188 | @available(iOS 16.1, *) 189 | func areActivitiesEnabled(result: @escaping FlutterResult) { 190 | var hasAuthorization = true 191 | let center = UNUserNotificationCenter.current() 192 | 193 | center.requestAuthorization(options: [.alert, .sound, .badge]) { _, error in 194 | if let error = error { 195 | hasAuthorization = false 196 | result(FlutterError(code: "AUTHORIZATION_ERROR", message: "authorization error", details: error.localizedDescription)) 197 | } 198 | } 199 | 200 | result(ActivityAuthorizationInfo().areActivitiesEnabled && hasAuthorization) 201 | } 202 | 203 | @available(iOS 16.0, *) 204 | private func receiveImage(data: [String: String], result: @escaping FlutterResult) { 205 | guard var groupId = data["groupId"] 206 | else { 207 | result(FlutterError(code: "DATA_ERROR", message: "no groupId", details: nil)) 208 | return 209 | } 210 | 211 | guard var destination = FileManager.default.containerURL( 212 | forSecurityApplicationGroupIdentifier: groupId) 213 | else { 214 | result(FlutterError(code: "DATA_ERROR", message: "no group", details: nil)) 215 | return 216 | } 217 | 218 | do { 219 | if let id = data["id"], let path = data["filePath"] { 220 | destination = destination.appendingPathComponent(id) 221 | 222 | do { 223 | try FileManager.default.removeItem(at: destination) 224 | } catch { 225 | print(error.localizedDescription) 226 | } 227 | 228 | try FileManager.default.moveItem(at: URL(filePath: path), to: destination) 229 | 230 | result(true) 231 | } 232 | } catch { 233 | result(FlutterError(code: "OP_ERROR", message: "receiveImage error", details: error.localizedDescription)) 234 | return 235 | } 236 | } 237 | 238 | public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { 239 | eventSink = events 240 | return nil 241 | } 242 | 243 | public func onCancel(withArguments arguments: Any?) -> FlutterError? { 244 | eventSink = nil 245 | return nil 246 | } 247 | 248 | public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable: Any] = [:]) -> Bool { 249 | let launchUrl = (launchOptions[UIApplication.LaunchOptionsKey.url] as? NSURL)?.absoluteURL 250 | 251 | if launchUrl != nil { 252 | initialUrl = launchUrl?.absoluteURL 253 | } 254 | 255 | return true 256 | } 257 | 258 | public func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { 259 | if isLiveActivitiesUrl(url: url) { 260 | eventSink?.self(url.absoluteString) 261 | return true 262 | } 263 | return false 264 | } 265 | 266 | private func isLiveActivitiesUrl(url: URL) -> Bool { 267 | let components = URLComponents(url: url, resolvingAgainstBaseURL: false) 268 | 269 | if components?.scheme == nil { return false } 270 | 271 | return urlScheme == components?.scheme 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /ios/flutter_live_activities.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_live_activities.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_live_activities' 7 | s.version = '0.0.1' 8 | s.summary = 'A Flutter plugin for Live Activities.' 9 | s.description = <<-DESC 10 | A new Flutter project. 11 | DESC 12 | s.homepage = 'https://github.com/fluttercandies/flutter_live_activities' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'NONE' => 'l18281145312@gmail.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '9.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /lib/flutter_live_activities.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'flutter_live_activities_platform_interface.dart'; 4 | 5 | bool _isAndroid = Platform.isAndroid; 6 | 7 | class FlutterLiveActivities { 8 | FlutterLiveActivities({this.urlScheme = 'fla'}) { 9 | if (!_isAndroid) FlutterLiveActivitiesPlatform.instance.init(urlScheme); 10 | } 11 | 12 | /// The url scheme used to interact with the native platform. 13 | final String urlScheme; 14 | 15 | /// Get launch uri 16 | Future getInitUri() async { 17 | if (_isAndroid) return null; 18 | 19 | final Uri? url = await FlutterLiveActivitiesPlatform.instance.getInitUri(); 20 | if (url?.isScheme(urlScheme) ?? false) return url; 21 | return null; 22 | } 23 | 24 | /// Get all activities id 25 | Future> getAllActivities() async { 26 | if (_isAndroid) return []; 27 | 28 | return FlutterLiveActivitiesPlatform.instance.getAllActivities(); 29 | } 30 | 31 | /// Create an iOS 16.1+ live activity. 32 | /// When the activity is created, an activity id is returned. 33 | /// Data is a map of key/value pairs that will be transmitted to your iOS extension widget. 34 | /// Map is limited to String keys and values for now. 35 | Future createActivity(Map data) async { 36 | if (_isAndroid) return null; 37 | 38 | return FlutterLiveActivitiesPlatform.instance.createActivity(data); 39 | } 40 | 41 | /// Update an iOS 16.1+ live activity. 42 | /// You can get an activity id by calling [createActivity]. 43 | /// Data is a map of key/value pairs that will be transmitted to your iOS extension widget. 44 | /// Map is limited to String keys and values for now. 45 | Future updateActivity(String liveId, Map data) async { 46 | if (_isAndroid) return false; 47 | 48 | return FlutterLiveActivitiesPlatform.instance.updateActivity(liveId, data); 49 | } 50 | 51 | /// End an iOS 16.1+ live activity. 52 | /// You can get an activity id by calling [createActivity]. 53 | Future endActivity(String liveId) async { 54 | if (_isAndroid) return false; 55 | 56 | return FlutterLiveActivitiesPlatform.instance.endActivity(liveId); 57 | } 58 | 59 | /// End an iOS 16.1+ live activity. 60 | /// You can get an activity id by calling [createActivity]. 61 | Future endAllActivities() async { 62 | if (_isAndroid) return false; 63 | 64 | return FlutterLiveActivitiesPlatform.instance.endAllActivities(); 65 | } 66 | 67 | /// Check if iOS 16.1+ live activities are enabled. 68 | /// If they are not enabled, you will not be able to create activities. 69 | Future areActivitiesEnabled() async { 70 | if (_isAndroid) return false; 71 | 72 | return FlutterLiveActivitiesPlatform.instance.areActivitiesEnabled(); 73 | } 74 | 75 | /// Get the state of an iOS 16.1+ live activity. 76 | Stream uriStream() { 77 | if (_isAndroid) return const Stream.empty(); 78 | 79 | return FlutterLiveActivitiesPlatform.instance.uriStream(); 80 | } 81 | 82 | /// Send to Group space 83 | Future sendImageToGroup({ 84 | required String id, 85 | required String filePath, 86 | required String groupId, 87 | }) async { 88 | if (_isAndroid) return false; 89 | 90 | return FlutterLiveActivitiesPlatform.instance.sendImageToGroup( 91 | id: id, 92 | filePath: filePath, 93 | groupId: groupId, 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/flutter_live_activities_method_channel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | 3 | import 'flutter_live_activities_platform_interface.dart'; 4 | import 'src/live_activities_status.dart'; 5 | 6 | /// An implementation of [FlutterLiveActivitiesPlatform] that uses method channels. 7 | class MethodChannelFlutterLiveActivities extends FlutterLiveActivitiesPlatform { 8 | /// The method channel used to interact with the native platform. 9 | final MethodChannel _methodChannel = 10 | const MethodChannel('flutter_live_activities'); 11 | final EventChannel _eventChannel = 12 | const EventChannel('flutter_live_activities/event'); 13 | 14 | @override 15 | void init(String urlScheme) { 16 | _methodChannel.invokeMethod('init', { 17 | 'urlScheme': urlScheme, 18 | }); 19 | } 20 | 21 | @override 22 | Future getInitUri() async { 23 | try { 24 | return Uri.tryParse( 25 | await _methodChannel.invokeMethod('getInitUri') ?? ''); 26 | } catch (e) { 27 | return null; 28 | } 29 | } 30 | 31 | @override 32 | Future> getAllActivities() async { 33 | try { 34 | final String? data = 35 | await _methodChannel.invokeMethod('getAllActivities'); 36 | if (data == null) return []; 37 | return data.split(','); 38 | } catch (e) { 39 | return []; 40 | } 41 | } 42 | 43 | @override 44 | Future createActivity(Map data) async { 45 | return _methodChannel.invokeMethod( 46 | 'createActivity', {'data': data}); 47 | } 48 | 49 | @override 50 | Future updateActivity(String liveId, Map data) async { 51 | return await _methodChannel.invokeMethod('updateActivity', 52 | {'liveId': liveId, 'data': data}) ?? 53 | false; 54 | } 55 | 56 | @override 57 | Future endActivity(String liveId) async { 58 | return await _methodChannel 59 | .invokeMethod('endActivity', { 60 | 'liveId': liveId, 61 | }) ?? 62 | false; 63 | } 64 | 65 | @override 66 | Future getActivityState(String liveId) async { 67 | try { 68 | final int? data = await _methodChannel 69 | .invokeMethod('getActivityState', { 70 | 'liveId': liveId, 71 | }); 72 | 73 | return LiveActivitiesState.values[data ?? 3]; 74 | } catch (e) { 75 | return LiveActivitiesState.unknown; 76 | } 77 | } 78 | 79 | @override 80 | Future endAllActivities() async { 81 | return await _methodChannel.invokeMethod('endAllActivities') ?? false; 82 | } 83 | 84 | @override 85 | Future areActivitiesEnabled() async { 86 | try { 87 | return (await _methodChannel 88 | .invokeMethod('areActivitiesEnabled')) ?? 89 | false; 90 | } catch (e) { 91 | return false; 92 | } 93 | } 94 | 95 | @override 96 | Stream uriStream() { 97 | return _eventChannel.receiveBroadcastStream().map((dynamic eve) { 98 | return Uri.tryParse(eve.toString()); 99 | }); 100 | } 101 | 102 | @override 103 | Future sendImageToGroup({ 104 | required String id, 105 | required String filePath, 106 | required String groupId, 107 | }) async { 108 | return await _methodChannel 109 | .invokeMethod('sendImageToGroup', { 110 | 'id': id, 111 | 'filePath': filePath, 112 | 'groupId': groupId, 113 | }) ?? 114 | false; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/flutter_live_activities_platform_interface.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_live_activities/src/live_activities_status.dart'; 2 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 3 | 4 | import 'flutter_live_activities_method_channel.dart'; 5 | 6 | abstract class FlutterLiveActivitiesPlatform extends PlatformInterface { 7 | /// Constructs a FlutterLiveActivitiesPlatform. 8 | FlutterLiveActivitiesPlatform() : super(token: _token); 9 | 10 | static final Object _token = Object(); 11 | 12 | static FlutterLiveActivitiesPlatform _instance = 13 | MethodChannelFlutterLiveActivities(); 14 | 15 | /// The default instance of [FlutterLiveActivitiesPlatform] to use. 16 | /// 17 | /// Defaults to [MethodChannelFlutterLiveActivities]. 18 | static FlutterLiveActivitiesPlatform get instance => _instance; 19 | 20 | /// Platform-specific implementations should set this with their own 21 | /// platform-specific class that extends [FlutterLiveActivitiesPlatform] when 22 | /// they register themselves. 23 | static set instance(FlutterLiveActivitiesPlatform instance) { 24 | PlatformInterface.verifyToken(instance, _token); 25 | _instance = instance; 26 | } 27 | 28 | void init(String urlScheme) { 29 | throw UnimplementedError('init() has not been implemented.'); 30 | } 31 | 32 | Future getInitUri() { 33 | throw UnimplementedError('getInitUri() has not been implemented.'); 34 | } 35 | 36 | Future> getAllActivities() { 37 | throw UnimplementedError('getAllActivities() has not been implemented.'); 38 | } 39 | 40 | Future createActivity(Map data) { 41 | throw UnimplementedError('createActivity() has not been implemented.'); 42 | } 43 | 44 | Future updateActivity(String liveId, Map data) { 45 | throw UnimplementedError('updateActivity() has not been implemented.'); 46 | } 47 | 48 | Future endActivity(String liveId) { 49 | throw UnimplementedError('endActivity() has not been implemented.'); 50 | } 51 | 52 | Future getActivityState(String liveId) async { 53 | throw UnimplementedError('getActivityState() has not been implemented.'); 54 | } 55 | 56 | Future endAllActivities() { 57 | throw UnimplementedError('endAllActivity() has not been implemented.'); 58 | } 59 | 60 | Future areActivitiesEnabled() { 61 | throw UnimplementedError( 62 | 'areActivitiesEnabled() has not been implemented.'); 63 | } 64 | 65 | Stream uriStream() { 66 | throw UnimplementedError('uriStream() has not been implemented.'); 67 | } 68 | 69 | Future sendImageToGroup({ 70 | required String id, 71 | required String filePath, 72 | required String groupId, 73 | }) { 74 | throw UnimplementedError('sendImageToGroup() has not been implemented.'); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/src/live_activities_status.dart: -------------------------------------------------------------------------------- 1 | /// LiveActivitiesState 2 | /// * [active] : The Live Activity is active, visible to the user, and can receive content updates. 3 | /// * [ended] : The Live Activity is visible, but the user, app, or system ended it, and it won't update its content anymore. 4 | /// * [dismissed] : The Live Activity ended and is no longer visible because the user or the system removed it. 5 | /// * [unknown] 6 | enum LiveActivitiesState { active, ended, dismissed, unknown } 7 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_live_activities 2 | description: Flutter plugin for Live Activities. Use to create, update and handling action for [DynamicIsland UI] and [Lock screen/banner UI] 3 | version: 0.0.5 4 | homepage: https://github.com/fluttercandies/flutter_live_activities 5 | 6 | environment: 7 | sdk: '>=2.18.2 <3.0.0' 8 | flutter: ">=2.5.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | plugin_platform_interface: ^2.0.2 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | flutter_lints: ^2.0.0 19 | 20 | # For information on the generic Dart part of this file, see the 21 | # following page: https://dart.dev/tools/pub/pubspec 22 | 23 | # The following section is specific to Flutter packages. 24 | flutter: 25 | # This section identifies this Flutter project as a plugin project. 26 | # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) 27 | # which should be registered in the plugin registry. This is required for 28 | # using method channels. 29 | # The Android 'package' specifies package in which the registered class is. 30 | # This is required for using method channels on Android. 31 | # The 'ffiPlugin' specifies that native code should be built and bundled. 32 | # This is required for using `dart:ffi`. 33 | # All these are used by the tooling to maintain consistency when 34 | # adding or updating assets for this project. 35 | plugin: 36 | platforms: 37 | ios: 38 | pluginClass: FlutterLiveActivitiesPlugin 39 | 40 | # To add assets to your plugin package, add an assets section, like this: 41 | # assets: 42 | # - images/a_dot_burr.jpeg 43 | # - images/a_dot_ham.jpeg 44 | # 45 | # For details regarding assets in packages, see 46 | # https://flutter.dev/assets-and-images/#from-packages 47 | # 48 | # An image asset can refer to one or more resolution-specific "variants", see 49 | # https://flutter.dev/assets-and-images/#resolution-aware 50 | 51 | # To add custom fonts to your plugin package, add a fonts section here, 52 | # in this "flutter" section. Each entry in this list should have a 53 | # "family" key with the font family name, and a "fonts" key with a 54 | # list giving the asset and other descriptors for the font. For 55 | # example: 56 | # fonts: 57 | # - family: Schyler 58 | # fonts: 59 | # - asset: fonts/Schyler-Regular.ttf 60 | # - asset: fonts/Schyler-Italic.ttf 61 | # style: italic 62 | # - family: Trajan Pro 63 | # fonts: 64 | # - asset: fonts/TrajanPro.ttf 65 | # - asset: fonts/TrajanPro_Bold.ttf 66 | # weight: 700 67 | # 68 | # For details regarding fonts in packages, see 69 | # https://flutter.dev/custom-fonts/#from-packages 70 | --------------------------------------------------------------------------------