From 26d4dcb175782dc0655894f90f4b1bc798d691ef Mon Sep 17 00:00:00 2001 From: Anton Borries Date: Tue, 12 Sep 2023 18:08:18 +0200 Subject: [PATCH] iOS 17 Interactivity (#158) * Add Support for iOS Interactive Widgets --- .github/assets/target_membership.png | Bin 0 -> 9175 bytes .github/workflows/main.yml | 11 +- CHANGELOG.md | 4 + README.md | 301 ++++--- example/.metadata | 24 +- example/analysis_options.yaml | 5 + example/android/app/build.gradle | 6 +- example/integration_test/android_test.dart | 16 +- example/integration_test/ios_test.dart | 44 +- example/ios/.gitignore | 2 + example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Flutter/Debug.xcconfig | 2 +- example/ios/Flutter/Release.xcconfig | 2 +- .../AppIcon.appiconset/Contents.json | 89 +-- .../HomeWidgetExample.entitlements | 10 - .../HomeWidgetExample/HomeWidgetExample.swift | 127 +-- example/ios/HomeWidgetExample/Info.plist | 18 - .../HomeWidgetExampleExtension.entitlements | 2 +- example/ios/Podfile | 9 +- example/ios/Runner.xcodeproj/project.pbxproj | 733 +++++++++++------- .../xcshareddata/xcschemes/Runner.xcscheme | 13 +- example/ios/Runner/AppDelegate.swift | 17 +- .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 1418 bytes example/ios/Runner/BackgroundIntent.swift | 40 + example/ios/Runner/Info.plist | 16 +- example/ios/RunnerTests/RunnerTests.swift | 12 + example/lib/main.dart | 69 +- example/pubspec.yaml | 9 +- ios/Classes/HomeWidgetBackgroundWorker.swift | 95 +++ ios/Classes/SwiftHomeWidgetPlugin.swift | 315 ++++---- lib/home_widget.dart | 17 +- lib/home_widget_callback_dispatcher.dart | 16 +- pubspec.yaml | 10 +- test/background_test.dart | 10 +- test/home_widget_test.dart | 17 +- 48 files changed, 1282 insertions(+), 781 deletions(-) create mode 100644 .github/assets/target_membership.png delete mode 100644 example/ios/HomeWidgetExample/HomeWidgetExample.entitlements create mode 100644 example/ios/Runner/BackgroundIntent.swift create mode 100644 example/ios/RunnerTests/RunnerTests.swift create mode 100644 ios/Classes/HomeWidgetBackgroundWorker.swift diff --git a/.github/assets/target_membership.png b/.github/assets/target_membership.png new file mode 100644 index 0000000000000000000000000000000000000000..56f08d6132e363e62c0da983b46d757e4fbdb4f7 GIT binary patch literal 9175 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 literal 0 HcmV?d00001 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d6e61530..70a34386 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,14 +67,19 @@ jobs: strategy: matrix: device: - - "iPhone 13" + - "iPhone 14" fail-fast: false - runs-on: macos-latest + runs-on: macos-13 steps: - uses: actions/checkout@v2 + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest + - name: Download iOS 17 + run: xcodebuild -downloadPlatform ios - uses: subosito/flutter-action@v1 with: - channel: stable + channel: beta - uses: futureware-tech/simulator-action@v1 id: simulator with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 018557e2..0223a0f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.0-alpha.0 +* Add support for Interactive Widgets on iOS +* Rename `registerBackgroundCallback` to `registerInteractivityCallback` + ## 0.3.0 * Add `renderFlutterWidget` method to save a Flutter Widget as an Image [#126](https://github.com/ABausG/home_widget/pull/126) by [leighajarett](https://github.com/leighajarett) diff --git a/README.md b/README.md index dec5e629..8eb4171f 100644 --- a/README.md +++ b/README.md @@ -17,49 +17,6 @@ HomeWidget does **not** allow writing Widgets with Flutter itself. It still requ ## Platform Setup In order to work correctly there needs to be some platform specific setup. Check below on how to add support for Android and iOS -
Android - -### Create Widget Layout inside `android/app/src/main/res/layout` - -### Create Widget Configuration into `android/app/src/main/res/xml` -```xml - - - -``` - -### Add WidgetReceiver to AndroidManifest -```xml - - - - - - -``` - -### Write your WidgetProvider -For convenience, you can extend from [HomeWidgetProvider](android/src/main/kotlin/es/antonborri/home_widget/HomeWidgetProvider.kt) which gives you access to a SharedPreferences Object with the Data in the `onUpdate` method. -In case you don't want to use the convenience Method you can access the Data using -```kotlin -import es.antonborri.home_widget.HomeWidgetPlugin -... -HomeWidgetPlugin.getData(context) -``` -which will give you access to the same SharedPreferences - -### More Information -For more Information on how to create and configure Android Widgets, check out [this guide](https://developer.android.com/develop/ui/views/appwidgets) on the Android Developers Page. - -
-
iOS ### Add a Widget to your App in Xcode @@ -106,11 +63,56 @@ let data = UserDefaults.init(suiteName:"YOUR_GROUP_ID") ```
+
Android + +### Create Widget Layout inside `android/app/src/main/res/layout` + +### Create Widget Configuration into `android/app/src/main/res/xml` +```xml + + + +``` + +### Add WidgetReceiver to AndroidManifest +```xml + + + + + + +``` + +### Write your WidgetProvider +For convenience, you can extend from [HomeWidgetProvider](android/src/main/kotlin/es/antonborri/home_widget/HomeWidgetProvider.kt) which gives you access to a SharedPreferences Object with the Data in the `onUpdate` method. +In case you don't want to use the convenience Method you can access the Data using +```kotlin +import es.antonborri.home_widget.HomeWidgetPlugin +... +HomeWidgetPlugin.getData(context) +``` +which will give you access to the same SharedPreferences + +### More Information +For more Information on how to create and configure Android Widgets, check out [this guide](https://developer.android.com/develop/ui/views/appwidgets) on the Android Developers Page. + +
+ ## Usage ### Setup +
iOS For iOS, you need to call `HomeWidget.setAppGroupId('YOUR_GROUP_ID');` Without this you won't be able to share data between your App and the Widget and calls to `saveWidgetData` and `getWidgetData` will return an error +
### Save Data In order to save Data call `HomeWidget.saveWidgetData('id', data)` @@ -136,59 +138,105 @@ This name needs to be equal to the Kind specified in you Widget ### Retrieve Data To retrieve the current Data saved in the Widget call `HomeWidget.getWidgetData('id', defaultValue: data)` -### Background Update -As the methods of HomeWidget are static it is possible to use HomeWidget in the background to update the Widget even when the App is in the background. +### Interactive Widgets -The example App is using the [flutter_workmanager](https://pub.dev/packages/workmanager) plugin to achieve this. -Please follow the Setup Instructions for flutter_workmanager (or your preferred background code execution plugin). Most notably make sure that Plugins get registered in iOS in order to be able to communicate with the HomeWidget Plugin. -In case of flutter_workmanager this achieved by adding: -```swift -WorkmanagerPlugin.setPluginRegistrantCallback { registry in - GeneratedPluginRegistrant.register(with: registry) -} -``` -to [AppDelegate.swift](example/ios/Runner/AppDelegate.swift) +Android and iOS (starting with iOS 17) allow widgets to have interactive Elements like Buttons -### Clicking -To detect if the App has been initially started by clicking the Widget you can call `HomeWidget.initiallyLaunchedFromHomeWidget()` if the App was already running in the Background you can receive these Events by listening to `HomeWidget.widgetClicked`. Both methods will provide Uris, so you can easily send back data from the Widget to the App to for example navigate to a content page. +
Dart -In order for these methods to work you need to follow these steps: +1. Write a **static** function that takes a Uri as an argument. This will get called when a user clicks on the View + ```dart + @pragma("vm:entry-point") + FutureOr backgroundCallback(Uri data) async { + // do something with data + ... + } + ``` + `@pragma('vm:entry-point')` must be placed above the `callback` function to avoid tree shaking in release mode. -#### iOS -Add `.widgetUrl` to your WidgetComponent -```swift -Text(entry.message) - .font(.body) - .widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget")) -``` -In order to only detect Widget Links you need to add the queryParameter`homeWidget` to the URL +2. Register the callback function by calling + ```dart + HomeWidget.registerInteractivityCallback(backgroundCallback); + ``` +
-#### Android -Add an `IntentFilter` to the `Activity` Section in your `AndroidManifest` -``` - - - -``` +
iOS -In your WidgetProvider add a PendingIntent to your View using `HomeWidgetLaunchIntent.getActivity` -```kotlin -val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( - context, - MainActivity::class.java, - Uri.parse("homeWidgetExample://message?message=$message")) -setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) -``` +1. Adjust your Podfile to add `home_widget` as a dependency to your WidgetExtension + ``` + target 'YourWidgetExtension' do + use_frameworks! + use_modular_headers! -### Background Click + pod 'home_widget', :path => '.symlinks/plugins/home_widget/ios' +end + ``` +2. To be able to use plugins with the Background Callback add this to your AppDelegate's `application` function + ```swift + if #available(iOS 17, *) { + HomeWidgetBackgroundWorker.setPluginRegistrantCallback { registry in + GeneratedPluginRegistrant.register(with: registry) + } + } + ``` +3. Create a custom `AppIntent` in your App Target (Runner) and make sure to select both your App and your WidgetExtension in the Target Membership panel + + ![Target Membership](https://github.com/ABausG/home_widget/blob/main/.github/assets/target_membership.png?raw=true) + + In this Intent you should import `home_widget` and call `HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!)` in the perform method. `url` and `appGroup` can be either hardcoded or set as parameters from the Widget + ```swift + import AppIntents + import Flutter + import Foundation + import home_widget + + @available(iOS 16, *) + public struct BackgroundIntent: AppIntent { + static public var title: LocalizedStringResource = "HomeWidget Background Intent" + + @Parameter(title: "Widget URI") + var url: URL? + + @Parameter(title: "AppGroup") + var appGroup: String? + + public init() {} + + public init(url: URL?, appGroup: String?) { + self.url = url + self.appGroup = appGroup + } + + public func perform() async throws -> some IntentResult { + await HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!) + + return .result() + } + } + ``` +4. Add a Button to your Widget. This Button might be encapsulated by a Version check. Pass in an instance of the `AppIntent` created in the previous step + ```swift + Button( + intent: BackgroundIntent( + url: URL(string: "homeWidgetExample://titleClicked"), appGroup: widgetGroupId) + ) { + Text(entry.title).bold().font( /*@START_MENU_TOKEN@*/.title /*@END_MENU_TOKEN@*/) + }.buttonStyle(.plain) + ``` +5. With the current setup the Widget is now Interactive as long as the App is still in the background. If you want to have the Widget be able to wake the App up you need to add the following to your `AppIntent` file + ```swift + @available(iOS 16, *) + @available(iOSApplicationExtension, unavailable) + extension BackgroundIntent: ForegroundContinuableIntent {} + ``` + This code tells the system to always perform the Intent in the App and not in a process attached to the Widget. Note however that this will start your Flutter App using the normal main entrypoint meaning your full app might be run in the background. To counter this you should add checks in the very first Widget you build inside `runApp` to only perform necessary calls/setups while the App is launched in the background +
-Android allows interactive elements in HomeScreenWidgets. This allows to for example add a refresh button on a widget. -With home_widget you can use this by following these steps: +
Android -#### Android/Native Part 1. Add the necessary Receiver and Service to you `AndroidManifest.xml` file ``` - + @@ -204,26 +252,13 @@ With home_widget you can use this by following these steps: ) setOnClickPendingIntent(R.id.widget_title, backgroundIntent) ``` +
-#### Dart -4. Write a **static** function that takes a Uri as an argument. This will get called when a user clicks on the View - ```dart - @pragma("vm:entry-point") - void backgroundCallback(Uri data) { - // do something with data - ... - } - ``` - `@pragma('vm:entry-point')` must be placed above the `callback` function to avoid tree shaking in release mode for Android. - -5. Register the callback function by calling - ```dart - HomeWidget.registerBackgroundCallback(backgroundCallback); - ``` - ### Using images of Flutter widgets -In some cases, you may not want to rewrite UI code in the native frameworks for your widgets. +In some cases, you may not want to rewrite UI code in the native frameworks for your widgets. + +
Dart For example, say you have a chart in your Flutter app configured with `CustomPaint`: ```dart @@ -247,9 +282,9 @@ class LineChart extends StatelessWidget { Screenshot 2023-06-07 at 12 33 44 PM -Rewriting the code to create this chart on both Android and iOS might be time consuming. -Instead, you can generate a png file of the Flutter widget and save it to a shared container -between your Flutter app and the home screen widget. +Rewriting the code to create this chart on both Android and iOS might be time consuming. +Instead, you can generate a png file of the Flutter widget and save it to a shared container +between your Flutter app and the home screen widget. ```dart var path = await HomeWidget.renderFlutterWidget( @@ -260,8 +295,9 @@ var path = await HomeWidget.renderFlutterWidget( ``` - `LineChart()` is the widget that will be rendered as an image. - `key` is the key in the key/value storage on the device that stores the path of the file for easy retrieval on the native side +
-#### iOS +
iOS To retrieve the image and display it in a widget, you can use the following SwiftUI code: 1. In your `TimelineEntry` struct add a property to retrieve the path: @@ -295,7 +331,7 @@ To retrieve the image and display it in a widget, you can use the following Swif … } ``` - + 4. Display the chart in the body of the widget's `View`: ```swift VStack { @@ -306,8 +342,9 @@ To retrieve the image and display it in a widget, you can use the following Swif ``` Screenshot 2023-06-07 at 12 57 28 PM +
-#### Android +
Android 1. Add an image UI element to your xml file: ```xml @@ -360,3 +397,51 @@ To retrieve the image and display it in a widget, you can use the following Swif } } ``` +
+ +### Launch App and Detect which Widget was clicked +To detect if the App has been initially started by clicking the Widget you can call `HomeWidget.initiallyLaunchedFromHomeWidget()` if the App was already running in the Background you can receive these Events by listening to `HomeWidget.widgetClicked`. Both methods will provide Uris, so you can easily send back data from the Widget to the App to for example navigate to a content page. + +In order for these methods to work you need to follow these steps: + +
iOS + +Add `.widgetUrl` to your WidgetComponent +```swift +Text(entry.message) + .font(.body) + .widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget")) +``` +In order to only detect Widget Links you need to add the queryParameter`homeWidget` to the URL +
+ +
Android +Add an `IntentFilter` to the `Activity` Section in your `AndroidManifest` +``` + + + +``` + +In your WidgetProvider add a PendingIntent to your View using `HomeWidgetLaunchIntent.getActivity` +```kotlin +val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + context, + MainActivity::class.java, + Uri.parse("homeWidgetExample://message?message=$message")) +setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData) +``` +
+ +### Background Update +As the methods of HomeWidget are static it is possible to use HomeWidget in the background to update the Widget even when the App is in the background. + +The example App is using the [flutter_workmanager](https://pub.dev/packages/workmanager) plugin to achieve this. +Please follow the Setup Instructions for flutter_workmanager (or your preferred background code execution plugin). Most notably make sure that Plugins get registered in iOS in order to be able to communicate with the HomeWidget Plugin. +In case of flutter_workmanager this achieved by adding: +```swift +WorkmanagerPlugin.setPluginRegistrantCallback { registry in + GeneratedPluginRegistrant.register(with: registry) +} +``` +to [AppDelegate.swift](example/ios/Runner/AppDelegate.swift) \ No newline at end of file diff --git a/example/.metadata b/example/.metadata index 3cc7e975..8b8d7d55 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,27 @@ # This file should be version controlled and should not be manually edited. version: - revision: 5a6dfa35caaf7bccb35488dc03677c150ebf2d97 - channel: dev + revision: "123453dc41ef48e717939dd3c012db6a23138895" + channel: "beta" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 123453dc41ef48e717939dd3c012db6a23138895 + base_revision: 123453dc41ef48e717939dd3c012db6a23138895 + - platform: ios + create_revision: 123453dc41ef48e717939dd3c012db6a23138895 + base_revision: 123453dc41ef48e717939dd3c012db6a23138895 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index e69de29b..d6b52f74 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:flutter_lints/flutter.yaml + +linter: + rules: + - require_trailing_commas \ No newline at end of file diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index a2f65472..5c94b8a1 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 33 + compileSdkVersion 34 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -39,8 +39,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "es.antonborri.home_widget_example" - minSdkVersion 16 - targetSdkVersion 33 + minSdkVersion 23 + targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/example/integration_test/android_test.dart b/example/integration_test/android_test.dart index 298a053d..d941319b 100644 --- a/example/integration_test/android_test.dart +++ b/example/integration_test/android_test.dart @@ -13,7 +13,7 @@ void main() { 'nullValueKey': null, }; - final defaultValue = MapEntry('defaultKey', 'defaultValue'); + const defaultValue = MapEntry('defaultKey', 'defaultValue'); setUpAll(() { // Clear all Data @@ -44,8 +44,10 @@ void main() { }); testWidgets('Returns default Value', (tester) async { - final returnValue = await HomeWidget.getWidgetData(defaultValue.key, - defaultValue: defaultValue.value); + final returnValue = await HomeWidget.getWidgetData( + defaultValue.key, + defaultValue: defaultValue.value, + ); expect(returnValue, defaultValue.value); }); @@ -54,13 +56,15 @@ void main() { testWidgets('Update Widget completes', (tester) async { final returnValue = await HomeWidget.updateWidget( name: 'HomeWidgetExampleProvider', - ).timeout(Duration(seconds: 5)); + ).timeout(const Duration(seconds: 5)); expect(returnValue, true); }); testWidgets('Register Background Callback', (tester) async { - await HomeWidget.registerBackgroundCallback(backgroundCallback); + final returnValue = + await HomeWidget.registerInteractivityCallback(backgroundCallback); + expect(returnValue, true); }); testWidgets( @@ -71,4 +75,4 @@ void main() { }); } -void backgroundCallback(Uri? uri) {} +Future backgroundCallback(Uri? uri) async {} diff --git a/example/integration_test/ios_test.dart b/example/integration_test/ios_test.dart index d2297751..7e6679c5 100644 --- a/example/integration_test/ios_test.dart +++ b/example/integration_test/ios_test.dart @@ -1,3 +1,5 @@ +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:home_widget/home_widget.dart'; import 'package:integration_test/integration_test.dart'; @@ -7,8 +9,10 @@ void main() { group('Need Group Id', () { testWidgets('Save Data needs GroupId', (tester) async { - expect(() async => await HomeWidget.saveWidgetData('AnyId', null), - throwsException); + expect( + () async => await HomeWidget.saveWidgetData('AnyId', null), + throwsException, + ); }); }); @@ -21,7 +25,7 @@ void main() { 'nullValueKey': null, }; - final defaultValue = MapEntry('defaultKey', 'defaultValue'); + const defaultValue = MapEntry('defaultKey', 'defaultValue'); setUpAll(() async { // Add Group Id @@ -54,8 +58,10 @@ void main() { }); testWidgets('Returns default Value', (tester) async { - final returnValue = await HomeWidget.getWidgetData(defaultValue.key, - defaultValue: defaultValue.value); + final returnValue = await HomeWidget.getWidgetData( + defaultValue.key, + defaultValue: defaultValue.value, + ); expect(returnValue, defaultValue.value); }); @@ -65,7 +71,7 @@ void main() { final returnValue = await HomeWidget.updateWidget( name: 'HomeWidgetExampleProvider', iOSName: 'HomeWidgetExample', - ).timeout(Duration(seconds: 5)); + ).timeout(const Duration(seconds: 5)); expect(returnValue, true); }); @@ -83,14 +89,32 @@ void main() { group('Register Backgorund Callback', () { testWidgets('RegisterBackgroundCallback completes without error', (tester) async { + final deviceInfo = await DeviceInfoPlugin().iosInfo; + final hasInteractiveWidgets = + double.parse(deviceInfo.systemVersion) >= 17.0; await HomeWidget.setAppGroupId('group.es.antonborri.integrationtest'); - final registerCallbackResult = - await HomeWidget.registerBackgroundCallback(backgroundCallback); - expect(registerCallbackResult, isNull); + if (hasInteractiveWidgets) { + final registerCallbackResult = + await HomeWidget.registerInteractivityCallback( + interactivityCallback, + ); + + expect( + registerCallbackResult, + isTrue, + ); + } else { + expect( + () async => await HomeWidget.registerInteractivityCallback( + interactivityCallback, + ), + throwsA(isA()), + ); + } }); }); }); }); } -void backgroundCallback(Uri? uri) {} +Future interactivityCallback(Uri? uri) async {} diff --git a/example/ios/.gitignore b/example/ios/.gitignore index e96ef602..7a7f9873 100644 --- a/example/ios/.gitignore +++ b/example/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 4f8d4d24..9625e105 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index e8efba11..ec97fc6f 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 399e9340..c4855bfe 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/HomeWidgetExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/HomeWidgetExample/Assets.xcassets/AppIcon.appiconset/Contents.json index 9221b9bb..13613e3e 100644 --- a/example/ios/HomeWidgetExample/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/example/ios/HomeWidgetExample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,93 +1,8 @@ { "images" : [ { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", + "idiom" : "universal", + "platform" : "ios", "size" : "1024x1024" } ], diff --git a/example/ios/HomeWidgetExample/HomeWidgetExample.entitlements b/example/ios/HomeWidgetExample/HomeWidgetExample.entitlements deleted file mode 100644 index 33c66ecd..00000000 --- a/example/ios/HomeWidgetExample/HomeWidgetExample.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.application-groups - - YOUR_APP_GROUP_ID - - - diff --git a/example/ios/HomeWidgetExample/HomeWidgetExample.swift b/example/ios/HomeWidgetExample/HomeWidgetExample.swift index b632a32f..b9c87655 100644 --- a/example/ios/HomeWidgetExample/HomeWidgetExample.swift +++ b/example/ios/HomeWidgetExample/HomeWidgetExample.swift @@ -5,79 +5,96 @@ // Created by Anton Borries on 04.10.20. // -import WidgetKit import SwiftUI +import WidgetKit private let widgetGroupId = "YOUR_APP_GROUP_ID" struct Provider: TimelineProvider { - func placeholder(in context: Context) -> ExampleEntry { - ExampleEntry(date: Date(), title: "Placeholder Title", message: "Placeholder Message") - } - - func getSnapshot(in context: Context, completion: @escaping (ExampleEntry) -> ()) { - let data = UserDefaults.init(suiteName:widgetGroupId) - let entry = ExampleEntry(date: Date(), title: data?.string(forKey: "title") ?? "No Title Set", message: data?.string(forKey: "message") ?? "No Message Set") - completion(entry) - } - - func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { - getSnapshot(in: context) { (entry) in - let timeline = Timeline(entries: [entry], policy: .atEnd) - completion(timeline) - } + func placeholder(in context: Context) -> ExampleEntry { + ExampleEntry(date: Date(), title: "Placeholder Title", message: "Placeholder Message") + } + + func getSnapshot(in context: Context, completion: @escaping (ExampleEntry) -> Void) { + let data = UserDefaults.init(suiteName: widgetGroupId) + let entry = ExampleEntry( + date: Date(), title: data?.string(forKey: "title") ?? "No Title Set", + message: data?.string(forKey: "message") ?? "No Message Set") + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + getSnapshot(in: context) { (entry) in + let timeline = Timeline(entries: [entry], policy: .atEnd) + completion(timeline) } + } } struct ExampleEntry: TimelineEntry { - let date: Date - let title: String - let message: String + let date: Date + let title: String + let message: String } -struct HomeWidgetExampleEntryView : View { - var entry: Provider.Entry - let data = UserDefaults.init(suiteName:widgetGroupId) - let iconPath: String? - - init(entry: Provider.Entry) { - self.entry = entry - iconPath = data?.string(forKey: "dashIcon") - - } - - var body: some View { - VStack.init(alignment: .leading, spacing: /*@START_MENU_TOKEN@*/nil/*@END_MENU_TOKEN@*/, content: { - Text(entry.title).bold().font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/) - Text(entry.message) - .font(.body) - .widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget")) - if (iconPath != nil) { - Image(uiImage: UIImage(contentsOfFile: iconPath!)!).resizable() - .scaledToFill() - .frame(width: 64, height: 64) - } +struct HomeWidgetExampleEntryView: View { + var entry: Provider.Entry + let data = UserDefaults.init(suiteName: widgetGroupId) + let iconPath: String? + + init(entry: Provider.Entry) { + self.entry = entry + iconPath = data?.string(forKey: "dashIcon") + + } + + var body: some View { + VStack.init( + alignment: .center, spacing: /*@START_MENU_TOKEN@*/ nil /*@END_MENU_TOKEN@*/, + content: { + if #available(iOSApplicationExtension 17, *) { + Button( + intent: BackgroundIntent( + url: URL(string: "homeWidgetExample://titleClicked"), appGroup: widgetGroupId) + ) { + Text(entry.title).bold().font( /*@START_MENU_TOKEN@*/.title /*@END_MENU_TOKEN@*/) + }.buttonStyle(.plain).frame(maxWidth: .infinity, alignment: .leading) + } else { + Text(entry.title).bold().font( /*@START_MENU_TOKEN@*/.title /*@END_MENU_TOKEN@*/).frame( + maxWidth: .infinity, alignment: .leading) } - ) - } + Text(entry.message) + .font(.body) + .widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget")) + .frame(maxWidth: .infinity, alignment: .leading) + if iconPath != nil { + Image(uiImage: UIImage(contentsOfFile: iconPath!)!).resizable() + .scaledToFill() + .frame(width: 64, height: 64) + } + } + ) + } } @main struct HomeWidgetExample: Widget { - let kind: String = "HomeWidgetExample" - - var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: Provider()) { entry in - HomeWidgetExampleEntryView(entry: entry) - } - .configurationDisplayName("My Widget") - .description("This is an example widget.") + let kind: String = "HomeWidgetExample" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + HomeWidgetExampleEntryView(entry: entry) } + .configurationDisplayName("My Widget") + .description("This is an example widget.") + } } struct HomeWidgetExample_Previews: PreviewProvider { - static var previews: some View { - HomeWidgetExampleEntryView(entry: ExampleEntry(date: Date(), title: "Example Title", message: "Example Message")) - .previewContext(WidgetPreviewContext(family: .systemSmall)) - } + static var previews: some View { + HomeWidgetExampleEntryView( + entry: ExampleEntry(date: Date(), title: "Example Title", message: "Example Message") + ) + .previewContext(WidgetPreviewContext(family: .systemSmall)) + } } diff --git a/example/ios/HomeWidgetExample/Info.plist b/example/ios/HomeWidgetExample/Info.plist index 40d4f01f..0f118fb7 100644 --- a/example/ios/HomeWidgetExample/Info.plist +++ b/example/ios/HomeWidgetExample/Info.plist @@ -2,24 +2,6 @@ - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - HomeWidgetExample - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 NSExtension NSExtensionPointIdentifier diff --git a/example/ios/HomeWidgetExampleExtension.entitlements b/example/ios/HomeWidgetExampleExtension.entitlements index 33c66ecd..40360484 100644 --- a/example/ios/HomeWidgetExampleExtension.entitlements +++ b/example/ios/HomeWidgetExampleExtension.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - YOUR_APP_GROUP_ID + YOUR_GROUP_ID diff --git a/example/ios/Podfile b/example/ios/Podfile index 5c4ba946..c3fd08a1 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,4 +1,5 @@ -platform :ios, '11.0' +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -31,6 +32,12 @@ target 'Runner' do use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end + target 'HomeWidgetExampleExtension' do + inherit! :search_paths + end end post_install do |installer| diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 5c72903b..5ed35622 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,63 +8,90 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 2F7B53B97E6B7AD80657D043 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF42075A323BE6B4AA8573E8 /* Pods_Runner.framework */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3A6116192AB04E8200DB4FE2 /* BackgroundIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6116182AB04E8200DB4FE2 /* BackgroundIntent.swift */; }; + 3A6116202AB0AAAE00DB4FE2 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6116032AB04E6300DB4FE2 /* WidgetKit.framework */; }; + 3A6116212AB0AAAE00DB4FE2 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6116052AB04E6300DB4FE2 /* SwiftUI.framework */; }; + 3A6116262AB0AAAE00DB4FE2 /* HomeWidgetExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6116252AB0AAAE00DB4FE2 /* HomeWidgetExample.swift */; }; + 3A6116282AB0AAB200DB4FE2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A6116272AB0AAB200DB4FE2 /* Assets.xcassets */; }; + 3A61162C2AB0AAB200DB4FE2 /* HomeWidgetExampleExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3A61161F2AB0AAAE00DB4FE2 /* HomeWidgetExampleExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 3A6116312AB0AABC00DB4FE2 /* BackgroundIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6116182AB04E8200DB4FE2 /* BackgroundIntent.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 5155B7B37DE127C7A013F034 /* Pods_HomeWidgetExampleExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 030DA3A9ACF258C121BB5A45 /* Pods_HomeWidgetExampleExtension.framework */; }; + 72662DC41236D33E5C019692 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7E170B620F10F9C27AFDFD9 /* Pods_RunnerTests.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - A0B4A45E25299C5800536BC1 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0B4A45D25299C5800536BC1 /* WidgetKit.framework */; }; - A0B4A46025299C5800536BC1 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0B4A45F25299C5800536BC1 /* SwiftUI.framework */; }; - A0B4A46325299C5800536BC1 /* HomeWidgetExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0B4A46225299C5800536BC1 /* HomeWidgetExample.swift */; }; - A0B4A46525299C5A00536BC1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A0B4A46425299C5A00536BC1 /* Assets.xcassets */; }; - A0B4A46925299C5A00536BC1 /* HomeWidgetExampleExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A0B4A45C25299C5800536BC1 /* HomeWidgetExampleExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - B3797C4BF19AC03ADF0B604F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD299E5F80735A8790DA86D1 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - A0B4A46725299C5A00536BC1 /* PBXContainerItemProxy */ = { + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 97C146E61CF9000F007C117D /* Project object */; proxyType = 1; - remoteGlobalIDString = A0B4A45B25299C5800536BC1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; + 3A61162A2AB0AAB200DB4FE2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3A61161E2AB0AAAE00DB4FE2; remoteInfo = HomeWidgetExampleExtension; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + 3A6116162AB04E6700DB4FE2 /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; - dstSubfolderSpec = 10; + dstSubfolderSpec = 13; files = ( + 3A61162C2AB0AAB200DB4FE2 /* HomeWidgetExampleExtension.appex in Embed Foundation Extensions */, ); - name = "Embed Frameworks"; + name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; }; - A0B4A46A25299C5A00536BC1 /* Embed App Extensions */ = { + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; - dstSubfolderSpec = 13; + dstSubfolderSpec = 10; files = ( - A0B4A46925299C5A00536BC1 /* HomeWidgetExampleExtension.appex in Embed App Extensions */, ); - name = "Embed App Extensions"; + name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 01168C50DB159FB62C5BA7ED /* Pods-HomeWidgetExampleExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HomeWidgetExampleExtension.release.xcconfig"; path = "Target Support Files/Pods-HomeWidgetExampleExtension/Pods-HomeWidgetExampleExtension.release.xcconfig"; sourceTree = ""; }; + 030DA3A9ACF258C121BB5A45 /* Pods_HomeWidgetExampleExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HomeWidgetExampleExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0E8F435FDB9EB41A4F54B01E /* 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 = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 214A07FC09585E65AA332BAA /* 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 = ""; }; - 2465B732DCE7D216465C0E0A /* 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 = ""; }; + 31DF39DFFF9E35450E4DA650 /* 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 = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3449710F7DA0995136A5B512 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 39C1FCBC895B68E6E02D7E17 /* Pods-HomeWidgetExampleExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HomeWidgetExampleExtension.debug.xcconfig"; path = "Target Support Files/Pods-HomeWidgetExampleExtension/Pods-HomeWidgetExampleExtension.debug.xcconfig"; sourceTree = ""; }; + 3A6115FC2AB04E3E00DB4FE2 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 3A6116032AB04E6300DB4FE2 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + 3A6116052AB04E6300DB4FE2 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + 3A6116182AB04E8200DB4FE2 /* BackgroundIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundIntent.swift; sourceTree = ""; }; + 3A61161F2AB0AAAE00DB4FE2 /* HomeWidgetExampleExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = HomeWidgetExampleExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 3A6116252AB0AAAE00DB4FE2 /* HomeWidgetExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetExample.swift; sourceTree = ""; }; + 3A6116272AB0AAB200DB4FE2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 3A6116292AB0AAB200DB4FE2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 3A6116322AB0AACF00DB4FE2 /* HomeWidgetExampleExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HomeWidgetExampleExtension.entitlements; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 4BF9D47C3AA25B71C6A0FD79 /* 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 = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 8FBC5A5F2E60808EBFC31D5E /* Pods-HomeWidgetExampleExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HomeWidgetExampleExtension.profile.xcconfig"; path = "Target Support Files/Pods-HomeWidgetExampleExtension/Pods-HomeWidgetExampleExtension.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -72,59 +99,73 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - A0B4A45C25299C5800536BC1 /* HomeWidgetExampleExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = HomeWidgetExampleExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - A0B4A45D25299C5800536BC1 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; - A0B4A45F25299C5800536BC1 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; - A0B4A46225299C5800536BC1 /* HomeWidgetExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetExample.swift; sourceTree = ""; }; - A0B4A46425299C5A00536BC1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - A0B4A46625299C5A00536BC1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - A0B4A4762529A24600536BC1 /* HomeWidgetExampleExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HomeWidgetExampleExtension.entitlements; sourceTree = ""; }; - A0B4A4792529A2E200536BC1 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; - A0B4A47D2529CF1000536BC1 /* HomeWidgetExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HomeWidgetExample.entitlements; sourceTree = ""; }; - DD299E5F80735A8790DA86D1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BA09CA1BC28317D02BE522F5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + BEDFE807B7DC5C2DA3DCC38C /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + C8E2EF4BE2CA8D3E8994B3C9 /* 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 = ""; }; + CF42075A323BE6B4AA8573E8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D7E170B620F10F9C27AFDFD9 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { + 3A61161C2AB0AAAE00DB4FE2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3A6116212AB0AAAE00DB4FE2 /* SwiftUI.framework in Frameworks */, + 3A6116202AB0AAAE00DB4FE2 /* WidgetKit.framework in Frameworks */, + 5155B7B37DE127C7A013F034 /* Pods_HomeWidgetExampleExtension.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 66594A161EC2617FB8847215 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - B3797C4BF19AC03ADF0B604F /* Pods_Runner.framework in Frameworks */, + 72662DC41236D33E5C019692 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - A0B4A45925299C5800536BC1 /* Frameworks */ = { + 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A0B4A46025299C5800536BC1 /* SwiftUI.framework in Frameworks */, - A0B4A45E25299C5800536BC1 /* WidgetKit.framework in Frameworks */, + 2F7B53B97E6B7AD80657D043 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 6589C43215B83E64883F01A4 /* Pods */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - 2465B732DCE7D216465C0E0A /* Pods-Runner.debug.xcconfig */, - 4BF9D47C3AA25B71C6A0FD79 /* Pods-Runner.release.xcconfig */, - 214A07FC09585E65AA332BAA /* Pods-Runner.profile.xcconfig */, + 331C807B294A618700263BE5 /* RunnerTests.swift */, ); - path = Pods; + path = RunnerTests; sourceTree = ""; }; - 8BC9E98AADD2D6D0E87ADD17 /* Frameworks */ = { + 3A6116022AB04E6300DB4FE2 /* Frameworks */ = { isa = PBXGroup; children = ( - DD299E5F80735A8790DA86D1 /* Pods_Runner.framework */, - A0B4A45D25299C5800536BC1 /* WidgetKit.framework */, - A0B4A45F25299C5800536BC1 /* SwiftUI.framework */, + 3A6116032AB04E6300DB4FE2 /* WidgetKit.framework */, + 3A6116052AB04E6300DB4FE2 /* SwiftUI.framework */, + 030DA3A9ACF258C121BB5A45 /* Pods_HomeWidgetExampleExtension.framework */, + CF42075A323BE6B4AA8573E8 /* Pods_Runner.framework */, + D7E170B620F10F9C27AFDFD9 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; }; + 3A6116222AB0AAAE00DB4FE2 /* HomeWidgetExample */ = { + isa = PBXGroup; + children = ( + 3A6116252AB0AAAE00DB4FE2 /* HomeWidgetExample.swift */, + 3A6116272AB0AAB200DB4FE2 /* Assets.xcassets */, + 3A6116292AB0AAB200DB4FE2 /* Info.plist */, + ); + path = HomeWidgetExample; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -139,13 +180,14 @@ 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( - A0B4A4762529A24600536BC1 /* HomeWidgetExampleExtension.entitlements */, + 3A6116322AB0AACF00DB4FE2 /* HomeWidgetExampleExtension.entitlements */, 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, - A0B4A46125299C5800536BC1 /* HomeWidgetExample */, + 3A6116222AB0AAAE00DB4FE2 /* HomeWidgetExample */, + 3A6116022AB04E6300DB4FE2 /* Frameworks */, 97C146EF1CF9000F007C117D /* Products */, - 6589C43215B83E64883F01A4 /* Pods */, - 8BC9E98AADD2D6D0E87ADD17 /* Frameworks */, + 331C8082294A63A400263BE5 /* RunnerTests */, + E7469DE9D65A8CE1B09AC1F9 /* Pods */, ); sourceTree = ""; }; @@ -153,7 +195,8 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, - A0B4A45C25299C5800536BC1 /* HomeWidgetExampleExtension.appex */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + 3A61161F2AB0AAAE00DB4FE2 /* HomeWidgetExampleExtension.appex */, ); name = Products; sourceTree = ""; @@ -161,7 +204,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( - A0B4A4792529A2E200536BC1 /* Runner.entitlements */, + 3A6115FC2AB04E3E00DB4FE2 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -170,55 +213,57 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + 3A6116182AB04E8200DB4FE2 /* BackgroundIntent.swift */, ); path = Runner; sourceTree = ""; }; - A0B4A46125299C5800536BC1 /* HomeWidgetExample */ = { + E7469DE9D65A8CE1B09AC1F9 /* Pods */ = { isa = PBXGroup; children = ( - A0B4A46225299C5800536BC1 /* HomeWidgetExample.swift */, - A0B4A46425299C5A00536BC1 /* Assets.xcassets */, - A0B4A46625299C5A00536BC1 /* Info.plist */, - A0B4A47D2529CF1000536BC1 /* HomeWidgetExample.entitlements */, + 39C1FCBC895B68E6E02D7E17 /* Pods-HomeWidgetExampleExtension.debug.xcconfig */, + 01168C50DB159FB62C5BA7ED /* Pods-HomeWidgetExampleExtension.release.xcconfig */, + 8FBC5A5F2E60808EBFC31D5E /* Pods-HomeWidgetExampleExtension.profile.xcconfig */, + C8E2EF4BE2CA8D3E8994B3C9 /* Pods-Runner.debug.xcconfig */, + 31DF39DFFF9E35450E4DA650 /* Pods-Runner.release.xcconfig */, + 0E8F435FDB9EB41A4F54B01E /* Pods-Runner.profile.xcconfig */, + BEDFE807B7DC5C2DA3DCC38C /* Pods-RunnerTests.debug.xcconfig */, + BA09CA1BC28317D02BE522F5 /* Pods-RunnerTests.release.xcconfig */, + 3449710F7DA0995136A5B512 /* Pods-RunnerTests.profile.xcconfig */, ); - path = HomeWidgetExample; + path = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { + 331C8080294A63A400263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - D28D27C01D99FA0B41273269 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 7DEC1846D0083E553565E7AB /* [CP] Embed Pods Frameworks */, - A0B4A46A25299C5A00536BC1 /* Embed App Extensions */, + 0AF15E9C2EE75A4C8DEB38B1 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + 66594A161EC2617FB8847215 /* Frameworks */, ); buildRules = ( ); dependencies = ( - A0B4A46825299C5A00536BC1 /* PBXTargetDependency */, + 331C8086294A63A400263BE5 /* PBXTargetDependency */, ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; }; - A0B4A45B25299C5800536BC1 /* HomeWidgetExampleExtension */ = { + 3A61161E2AB0AAAE00DB4FE2 /* HomeWidgetExampleExtension */ = { isa = PBXNativeTarget; - buildConfigurationList = A0B4A46E25299C5A00536BC1 /* Build configuration list for PBXNativeTarget "HomeWidgetExampleExtension" */; + buildConfigurationList = 3A61162D2AB0AAB200DB4FE2 /* Build configuration list for PBXNativeTarget "HomeWidgetExampleExtension" */; buildPhases = ( - A0B4A45825299C5800536BC1 /* Sources */, - A0B4A45925299C5800536BC1 /* Frameworks */, - A0B4A45A25299C5800536BC1 /* Resources */, + 1CDA60DACEA6FBD6F4352E3D /* [CP] Check Pods Manifest.lock */, + 3A61161B2AB0AAAE00DB4FE2 /* Sources */, + 3A61161C2AB0AAAE00DB4FE2 /* Frameworks */, + 3A61161D2AB0AAAE00DB4FE2 /* Resources */, ); buildRules = ( ); @@ -226,26 +271,55 @@ ); name = HomeWidgetExampleExtension; productName = HomeWidgetExampleExtension; - productReference = A0B4A45C25299C5800536BC1 /* HomeWidgetExampleExtension.appex */; + productReference = 3A61161F2AB0AAAE00DB4FE2 /* HomeWidgetExampleExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 1CE53E05C4E82E592AC0D31F /* [CP] Check Pods Manifest.lock */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 3A6116162AB04E6700DB4FE2 /* Embed Foundation Extensions */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 9740EEB61CF901F6004384FC /* Run Script */, + 884E6D371DAAD272CCC9F23D /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 3A61162B2AB0AAB200DB4FE2 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1200; - LastUpgradeCheck = 1300; + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 3A61161E2AB0AAAE00DB4FE2 = { + CreatedOnToolsVersion = 15.0; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; }; - A0B4A45B25299C5800536BC1 = { - CreatedOnToolsVersion = 12.0.1; - }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; @@ -262,12 +336,28 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, - A0B4A45B25299C5800536BC1 /* HomeWidgetExampleExtension */, + 331C8080294A63A400263BE5 /* RunnerTests */, + 3A61161E2AB0AAAE00DB4FE2 /* HomeWidgetExampleExtension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3A61161D2AB0AAAE00DB4FE2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3A6116282AB0AAB200DB4FE2 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -279,17 +369,75 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - A0B4A45A25299C5800536BC1 /* Resources */ = { - isa = PBXResourcesBuildPhase; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0AF15E9C2EE75A4C8DEB38B1 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( - A0B4A46525299C5A00536BC1 /* Assets.xcassets in Resources */, + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; + 1CDA60DACEA6FBD6F4352E3D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-HomeWidgetExampleExtension-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; + 1CE53E05C4E82E592AC0D31F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -306,7 +454,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 7DEC1846D0083E553565E7AB /* [CP] Embed Pods Frameworks */ = { + 884E6D371DAAD272CCC9F23D /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -338,55 +486,48 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - D28D27C01D99FA0B41273269 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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"; - showEnvVarsInLog = 0; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { + 3A61161B2AB0AAAE00DB4FE2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + 3A6116312AB0AABC00DB4FE2 /* BackgroundIntent.swift in Sources */, + 3A6116262AB0AAAE00DB4FE2 /* HomeWidgetExample.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - A0B4A45825299C5800536BC1 /* Sources */ = { + 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A0B4A46325299C5800536BC1 /* HomeWidgetExample.swift in Sources */, + 3A6116192AB04E8200DB4FE2 /* BackgroundIntent.swift in Sources */, + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - A0B4A46825299C5A00536BC1 /* PBXTargetDependency */ = { + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = A0B4A45B25299C5800536BC1 /* HomeWidgetExampleExtension */; - targetProxy = A0B4A46725299C5A00536BC1 /* PBXContainerItemProxy */; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; + 3A61162B2AB0AAB200DB4FE2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3A61161E2AB0AAAE00DB4FE2 /* HomeWidgetExampleExtension */; + targetProxy = 3A61162A2AB0AAB200DB4FE2 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -451,7 +592,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -468,30 +609,195 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = H54LJFQW93; + DEVELOPMENT_TEAM = T3PND82A9W; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); - INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.exampleHomeWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BEDFE807B7DC5C2DA3DCC38C /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BA09CA1BC28317D02BE522F5 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3449710F7DA0995136A5B512 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 3A61162E2AB0AAB200DB4FE2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 39C1FCBC895B68E6E02D7E17 /* Pods-HomeWidgetExampleExtension.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomeWidgetExampleExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = T3PND82A9W; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomeWidgetExample/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomeWidgetExample; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", + "@executable_path/../../Frameworks", ); - LIBRARY_SEARCH_PATHS = ( + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.exampleHomeWidget.HomeWidgetExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 3A61162F2AB0AAB200DB4FE2 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 01168C50DB159FB62C5BA7ED /* Pods-HomeWidgetExampleExtension.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomeWidgetExampleExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = T3PND82A9W; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomeWidgetExample/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomeWidgetExample; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.homeWidgetExample; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.exampleHomeWidget.HomeWidgetExample; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 3A6116302AB0AAB200DB4FE2 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8FBC5A5F2E60808EBFC31D5E /* Pods-HomeWidgetExampleExtension.profile.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomeWidgetExampleExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = T3PND82A9W; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomeWidgetExample/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomeWidgetExample; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.exampleHomeWidget.HomeWidgetExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Profile; }; @@ -542,7 +848,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -591,7 +897,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -610,28 +916,16 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = H54LJFQW93; + DEVELOPMENT_TEAM = T3PND82A9W; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.homeWidgetExample; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.exampleHomeWidget; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -647,138 +941,45 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = H54LJFQW93; + DEVELOPMENT_TEAM = T3PND82A9W; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); - PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.homeWidgetExample; + PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.exampleHomeWidget; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; - A0B4A46B25299C5A00536BC1 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = HomeWidgetExampleExtension.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = H54LJFQW93; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = HomeWidgetExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.homeWidgetExample.HomeWidgetExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - A0B4A46C25299C5A00536BC1 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = HomeWidgetExampleExtension.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = H54LJFQW93; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = HomeWidgetExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.homeWidgetExample.HomeWidgetExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - A0B4A46D25299C5A00536BC1 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = HomeWidgetExampleExtension.entitlements; - CODE_SIGN_STYLE = Manual; - DEVELOPMENT_TEAM = H54LJFQW93; - GCC_C_LANGUAGE_STANDARD = gnu11; - INFOPLIST_FILE = HomeWidgetExample/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = es.antonborri.homeWidgetExample.HomeWidgetExample; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Profile; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3A61162D2AB0AAB200DB4FE2 /* Build configuration list for PBXNativeTarget "HomeWidgetExampleExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3A61162E2AB0AAB200DB4FE2 /* Debug */, + 3A61162F2AB0AAB200DB4FE2 /* Release */, + 3A6116302AB0AAB200DB4FE2 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -799,16 +1000,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - A0B4A46E25299C5A00536BC1 /* Build configuration list for PBXNativeTarget "HomeWidgetExampleExtension" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - A0B4A46B25299C5A00536BC1 /* Debug */, - A0B4A46C25299C5A00536BC1 /* Release */, - A0B4A46D25299C5A00536BC1 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a3..87131a09 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + + + Bool { GeneratedPluginRegistrant.register(with: self) - - UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*15)) - + + UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60 * 15)) + WorkmanagerPlugin.setPluginRegistrantCallback { registry in + GeneratedPluginRegistrant.register(with: registry) + } + + if #available(iOS 17, *) { + HomeWidgetBackgroundWorker.setPluginRegistrantCallback { registry in GeneratedPluginRegistrant.register(with: registry) + } } - + return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 28c6bf03016f6c994b70f38d1b7346e5831b531f..7353c41ecf9ca08017312dc233d9830079b50717 100644 GIT binary patch delta 279 zcmV+y0qFj;1g8R!8Gi!+006pI?LPnj0Blf9R7L;)|5U~J`u_j-{Qm)0oAmqtj@kOz z^8J|I`-|B6ht~R5kG+%I`zf~eztraM`u^bc{`dO)zUlmg)%x%C`E}6wSI77~z4s`y z^XT{f(eM4n?EUff`e@AgO~UxV*5*r_%Uhbj5N)LaQj!wdIe!-b004GLL_t&-)18pX z4udcZ1u-#g(~z+5JN*AY5?>Gw7hsN~k)CYt4dQDFxbs5*_&e@Hj)wtt(&JE<3Eq*D z;_gQLvqXoKv=I*gWqM9C(Tvu0>=?hTbOp9!6k6AF;>f6|S5%jGEE}TA9h)e`Yuiu8 d7)l?o1NFcJg%EAfM$P~L002ovPDHLkV1g^Dnv?(l delta 550 zcmV+>0@?ki0<;8>8Gi-<0051N9Sr~g00DDSM?wIu&K&6g00HhvL_t(I5v`QFOB_)Y z#?QI;j_a;jjf#Z$YJ7mH(xecJU?W)A`9CN~KrBV85C}GDQ=|;GDFPNjtWty!L{u=? zh>8yo%^GE+J9o~_IZFoiamQVQXP7%LzTbT3F@uf+9x&7cvVV%GdjTaC;zf>@mq<=3 z!c<%*UT)@yJ|0BK6~d4Jx-*KV`ZQ(@VyUPupum=XhInNG#Z_k-X|hK{B}~9IfiWx} zLD5QY6Vm)p0NrWymdkrHPN5Vgwd>5>4HI1=@PA+e^rq~CEj|n2X`??)0mUI*D{KBn zjv{V=y5X9|X@3grkpcXC6oou4ML~ezCc2EtnsQTB4tWNg?4bkf;hG7IMfhgNI(FV5 zGs4|*GyMTIY0$B=_*mso9+>eB z?J{?+FLkYu+4_Uk`r_>LHF~flZm0oBf#vr8%vJ>#p~!KNvqGG3)|f1T_)ydeh8$vDceZ>oNbH^|*hJ*t?Yc*1`WB&W>VYVEzu) zq#7;;VjO)t*nbgf(!`OXJBr45rP>>AQr$6c7slJWvbpNW@KTwna6d?PP>hvXCcp=4 zF;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f<+$JJpcdz delta 1274 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cde12118dda48d71e01fcb589a74d069c5d7cb5..4cd7b0099ca80c806f8fe495613e8d6c69460d76 100644 GIT binary patch delta 266 zcmV+l0rmcY2$}+r8Gi!+003c4mpuRg09{Z_R7L;)|5U~JDYo_jSDX9(|7FYh`2GLd z^Zv2r{H^2sT*&w!Y^SB+`<>qVZqE6)=lqo0`vF#&*75!I`TIh@_d&k*HoEtQyV-iD z%Xz2D9EQRbeYh5Nr~y=#0ZD;^+vz0$004MNL_t(2&&|%+4u6C&2tZM$Wf&dzefR%A z(^3-?6X>hnCz2Ba@RH&`m!pgy?n@#@AuLYB&}Q)FGY`?vcft0!vht0Z@M&ZeNCWXh75gzRTXR8EE3oN&6 Q00000NkvXXt^-0~g5kS`djJ3c delta 1014 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 Zxpx7IC@PekH?;r&002ovPDHLkV1i)CYaajr delta 1916 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 delta 1274 zcmV@pi1MCNO0zH7s z{8#}P0)7Ba8DqYf&QgSne>X__O83t$NZM4&R0{XJq|x}oAU?tcfC@|eNz$04T}34& z8DJf78R&>*Zz`k$q{`#gfGHnx7nlH^G{y`jfER)1<_fNi<9aM%_zrm1C`yPkKma(+ ztQ;y*CR2bbBYz>zG*SVsfpkGU(q>uHZf3iogk_%#9E|5SWeHrmAo>P;ejX7mwq#*} zW25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+X$F_KMdb6sRz!~7K zkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&IDi_4_D!s#MVXp|-XhH;H z#&@_;oApJVd}}5O@b=X_gJboD^-fM@6|#V@sA%X)Rlkd}3MLH0dGXGG&-HX|aD~|M zC)W#H7=H?AbtdaV#dGpubj_O^J-SlWpVNv-5(;wR%mvE9`Qaqo>03b&##eNNf=m#B z9@^lsd8tJ;BvI86kNV zc~0CY(7V{s+h%cWG|y=gt|q`z$l<(@qU=i?9q#uz`G?PgDMK!VMGidHZt*N+1L0ZI zFkH=mFtywc6rJ}C_?)=m)18V!ZQ`*-j(D`gCFK|nt#{bk*%%zuQ7o7kvJgA^=(^7b zzkm5GZ;jxRn{Wup8IOUx8D4uh&(=Ox-7$a;U><*5L^!% zxRlw)vAbh;sdlR||&e}8_8%)c2Fwy=F& zH|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}Jb#viX>Oi;kBKp1x_fc0#UIbIeSJ^EkWFox zijdim{ojmn@#7EC*aY;fC0W*WN+DmQtE06pNK3SfZ^#@2K`6RgEuU_KwJTQ>E?Yar zc_9e#I$F8%>kuy-JI6ocSsYvQGbsxUCx04(w1z-pMRz9`kH5smmF@WHEG?dcYkv){ zV?kn3XB$_3zr*h1Uow)(<5)w5;3Wh1jHI)`ZlXp&!yEV{Y_~@;?CLwq;4eeaGOe6( zEsSSbwSGD0-`dUUl014$1_O8Gi!+006nq0-pc?0H{z*R7L;)|5U~JDYo_jSDXF*|5nEMy6F5^ z$M}8I`uzU?*Yf=uXr;5|{0m;6_Wb|A>ik^D_|)+I$?g3CSDK^3+eX0mD!2CP`2NN0 z{dLg!a?km&%iyTt`yiax0acdp`~T(l{$a`ZF1YpsRg(cvjDG_-U$Er-fz#Bw>2W$eUI#iU z)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G!hkE!s;%oku3;IwG3U^2k zw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn_j%}l|2+O?a>_7qq7W zmx(qtA2nV^tZlLpy_#$U%ZNx5;$`0L&dZ!@e7rFXPGAOup%q`|03hpdtXsPP0000< KMNUMnLSTZ1N;Pr- delta 1891 zcmV-p2b}oI1m_Nr8Gi-<0052=@~r>>2QEoOK~#9!?VW3E6jc<*XLh$yKNt;)Mial3 z7z%<>zxaV5DhMs*(b6YIW1=KP6Jj(m21QYbiJ}su&;o5EN=$%gptMj6p|(7#AOTUJ zlt8fsX(iGq?ZQ50=XmbU+~w|cmz~|6$KBbz$-g^IcV>Hk`+q<8%-p?uMi3G-0B~!5 ze-yPCwFPw?HGmpMc~K)7BCq;C528+>zC*o^8h^XKC)IFgkv#xzm!ewK7j|kRa9dFo zC>MoDSR@P2#cWSU{i1oH5K2-Xb3jRz>|h7VOh0K` zhq^--L3H}A0r)nr z;Tr|-kPjB1s=ItpnS`oT%|U=a4oK-ZFIE^YBLH{u2#~@%%D^K)$`9*Tg(~9M-B+Zj z;~H?4LVsEt0eFtN4&>H(DZ@KpI6RhBKLL21CxC`J&m4Gc^9wwMZU#7SR1+KtuhSZM z+yLY}Vekzw6T_ApfEkuB_yU;e&a)L@rX~z70A_N+upOXN!qygmPDmKG0d%7CECcAI zgkd>ArzH$a0XjKsO$X@IgkcH5Y;m3`0G*yNOn(KK4GF_EfL4aB5i1j9o&Z{vFk~k> z&?@K2jQcJO%W!cddG(_DyfSoO55bUMHtbDF8DPkwF^~Ql#Eq4w15k{h%ML5Ar&pzi zl-D7v8kQXQ!&RRgKCW#5DZB$$6?mjWm50rRw*ukK>P-GkA|k69h{NARc>e}uLx+U4 z0DqE>7pa}9Fez+Vc-3jb`%i^uulglFoMzAVR|2%rf= zf#;74FXF^Ku_4+G&-4$KVy%YP>%2rxu2VG_cdm?XRjEhF&wPXJ># z_Q2+jGs=l~Fyx#MmGn+PZ0`@kBfGp|fO;Vov<$;z`(+sSZ7;Y=zXaF(8rb@CuQDV^ zq3i(2LfqO%AS!Ss>V%j7%>{6mtbYQrtQK5V4InPq0NZSaXv+f2U=&2}Z6OvkBfNHi z{LSaVJ!d5dC2K*ft_L^DRk;boQhOoVw!~Kt#0b2vd%!(&DF|~u1F@nG#LA5zR&7Fv z4GKgXooMSKb1g)6Obo-rgpuEP20T;W0Aa>55KC4gtQrKkAq-Hgs@FigV1GG8+rQ=z z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRet3L_uNyQ*c zE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=kyx=~RKa4{iT zm{_>_vSCm?$Ej=i6@=m%@PE9t1zZaoM}@2|h!#1K02~31S_I<0ZV=|K0}n!RRX6Ac zXmMf*5P-dLW}WPVsCKq)-x(0*txpZ2xrv3cxJ%l=7lpoNCyG< zK92ySAcmb-3m&}s@VwXv9(0#p<>B-5$bMxT;rk;OmENa6eM4D&LVo~01soUL39?R{ zyFLt3m|v?rCK7#KNu9E9Q4KV-pEUv^{rrClE&X&9I4-e7%pu_31#zGTOfC=ab%w20R*zBP+uT#l2{a~~~0wuG%6 zco*tVxK&e>%SJj*K!2tq*_h&ES5S9@TKb8WzpK;`&b9dNdxh4S)z%Q)o`aYWUh}9L z(`p!#WO5IxI|nf?yz{90R93Ed6@2qim*}Zjj$H&Esd`?JsFJUnDfiAgF_eYiWR3GC z>M9SHDylEWrA(%mfm~;u7OU9!Wz^!7Z%jZF zi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i0WYBP d*#0Ks^FNSabJA*5${_#%002ovPDHLkV1gB0Vle;! diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index a6d6b8609df07bf62e5100a53a01510388bd2b22..0ec303439225b78712f49115768196d8d76f6790 100644 GIT binary patch delta 850 zcmV-Y1Fih&6y64q8Gi!+000iU#^3+|0OwFlR7L;)|5U~J09TtSw)Xt~|5(QO`~Ck( z!T0|D|3<*~RmJ%E{r+;#`2ba!klFf7!uJMSo%Q?vP{jByxcAZE>;OrUCbaZYjJo^$ z{nGILmD~Da$@upC{`C6(Ey4dPw)Pyc^>5DkHoEo!QcuK-Jwl-l}t(fQKv z{dds$V#@dygS`PvhX6is7Z+@*x-d;$ zb=6f@U3Jw}_s+W3%*+b9H_vS)-R#9?zrXogeLVI2We2RFTTAL}&3C8PS~<5D&v@UI z+`s*$wqQ=yd$laNUY-|ovcS9~n_90tFUdl#qq0tEUXle|k{Op|DHpSrbxEeZ5~$>o%>OSe z^=41qvh3LlC2xXzu+-2eQoqs1^L>7ylB$bCP);(%(xYZL1 cY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f@rA97ytkO literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index a6d6b8609df07bf62e5100a53a01510388bd2b22..0ec303439225b78712f49115768196d8d76f6790 100644 GIT binary patch delta 850 zcmV-Y1Fih&6y64q8Gi!+000iU#^3+|0OwFlR7L;)|5U~J09TtSw)Xt~|5(QO`~Ck( z!T0|D|3<*~RmJ%E{r+;#`2ba!klFf7!uJMSo%Q?vP{jByxcAZE>;OrUCbaZYjJo^$ z{nGILmD~Da$@upC{`C6(Ey4dPw)Pyc^>5DkHoEo!QcuK-Jwl-l}t(fQKv z{dds$V#@dygS`PvhX6is7Z+@*x-d;$ zb=6f@U3Jw}_s+W3%*+b9H_vS)-R#9?zrXogeLVI2We2RFTTAL}&3C8PS~<5D&v@UI z+`s*$wqQ=yd$laNUY-|ovcS9~n_90tFUdl#qq0tEUXle|k{Op|DHpSrbxEeZ5~$>o%>OSe z^=41qvh3LlC2xXzu+-2eQoqs1^L>7ylB$bCP);(%(xYZL1 cY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f@rA97ytkO literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..e9f5fea27c705180eb716271f41b582e76dcbd90 100644 GIT binary patch delta 1668 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..84ac32ae7d989f82d5e46a60405adcc8279e8001 100644 GIT binary patch delta 749 zcmVg;Ps8|O$@u8^{Z_{KM!@$5TAfS6_e#O{MZfpz`2O`0$7~@NRr(1{THzH08y3x{{PYM{eL;T_A9^tcF_4Sxb`8l z_9V3RD6;a(-0A^Pjsi!1?)d#Ap4Tk3^CP0(07;VpJ7@tgQ}z4)*zx@&yZwC9`DV-b z0ZobH_5IB4{KxD3;p_6%|f=bdFhu+F!zMZ2UFj;GUKX7tI;hv3{q~!*pMj75WP_c}> z6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FMs~w_u?Av_yNBmRxVYrpi(M% zFMP21g+hmocQp3ay*Su=qM6He)*HaaTg$E^sym`(t%s3A)x!M+vfjXUBEpK6X9%iU zU!u9jj3(-$dM~sJ%Liy#?|+!6IY#MTau#O6vVj`yh_7%Ni!?!VS+MPTO(_fG+1<#p zqu;A#i+_(N%CmVnYvb>#nA{>Q%3E`Ds7<~jZMywn@h2t>G-LrYy7?Dj{aZqhQd6tzX%(Trn+ z)HNF}%-F{rr=m*0{=a;s#YDL00000NkvXXu0mjfaGjYE delta 1884 zcmV-i2c!7<1>g>l8Gi-<0076AQ7Zrd2Pa8HK~#9!?VNjT6h$1z_m0EFf5bmb1dTDK zp;kdKV1h(V(8Sc1M<37!RE>znAk{x4#zX@eOeE1j3~!+nB5IL z<xS}u?#DBMB>w^b($1Z)`9G?eP95EKi& z$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD?Uu$P4(=PGA0ShFasNfcIHTL?9WjB9#(2xSLC z`0%$#9DW9F;B4mbU{BlaYx!SjF!QSeF~(msQRxwboh5B_O$BWOQja)GboJz$&!?mgB&3$ytsA zvns&b3Cl5Hx#%p%faR*Q906u&fbXy$maV`n?S>A)vJIH!F-vxCrY+rq5_JA(GcOgu7(Ky4X3ATR9z8*%k&<5qYeV&4Y`~}XYmK(j{)!g8d2UgHXIINM!Rvn zKtEq~Foe0s!U{kux~F6Y7Sp+2f|*Cc${S{@oh8D0=XhB8Ec-w9CflfL+te4ium2cU zoPTCj_m<3d#gjK=<*8R`HP^C$lOPM5d~UhKhRRmvv{LI za^|oavk1$QiEApSrP@~Jjbg`<*dW4TO@DPEEX$Tg$xh?Y>Qd}y@kaH~IT8!lLpS^J zR7(&wZSI6+>Eb)tX>9Z?GX#q$u z4I>7e#b7ojyJ1grOh!^}s8S#ubi^Jkd1?UK)3mp6rI^_zxRY zrx6_QmhoWoDR`fp4R7gu6@OBFGu7IDVR6~nJsB{^f5jHn<{WJ&&f^X?3f8TIk3#U& zu1*Q-e@;snJxNx8-PBnpI|uFTKN!+Lp;fPfZ+eqqU^Y1|#DJY~126?zOx-+d>%4*? z&o`TbrXSNXZW^!P0t2>@$6&aiBtUDh2wLXLD9&a(1J=k_FK|iGbAQ@x4Qmx}Ms+*; zze&q6bH(=wYuXHfz0H6<05!LkE4rl~v^!bj=^9d+vI5fN<;GP>*Pas=q2l9RxDkk` zPRk&EQI+t_0$Y%nKE)Ma)W?jaA@4Z{h zTk*7;;#lG?hvTN_On=Jaxp%bdE;mDq(q#dgdYF|-?wrMeI4h`$idZ6^VyXZVlaCd0 z;i)OYR3npf@9>00Gqn##Zb4HRurgaWFCzL9u6@J@sse>Z1XznxWvSy%Td32I3!#YN zXt9v0)RQtDDZRd?#WY?~KF7A0UcR{jt9 W+;fr}hV%pg0000&=UXv0SHh`R7L;)|5U~JDYo_jSDRDC`1<|-SjPDL z{{Q{{{{H{}09Kk-#rR9Y_viNgVafPO!S|ls`uzR=MZfp^{QU=8od8La1X`Tr_Wmff z_5e$ivgQ1@=KMy$_g9a+`TPAle6cOJ_Fc#L7qIpvwDkd1mw$fK`6IOUD75rX!}mad zv(fMTE4=(Nx%L54lL1hVF1YpqNrC`FddBPg#_Ietx%Lrkq5wX00X1L{S%Cm9QY*av z#_Rh5PKy9KYTWbvz3BX9%J>0Hi1+#X{rLA{m%$Kamk?i!03AC38#Yrxs)5QTeTVRiEmz~MKK1WAjCw(c-JK6eox;2O)?`?TG`AHia671e^vgmp!llK zp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?tc*y?iZ$PR7_ceEIapF3KB14K0Pog?7wtd+^xgUCa_GVmlD z<^nU>AU_Yn-JU?NFdu|wf^bTCNf-wSBYVZltDdvGBln-YrbeGvJ!|s{#`gjN@yAMb zM6cjFz0eFECCsc|_8hTa3*9-JQGehksdoVP^K4m?&wpA~+|b%{EP5D-+7h)6CE; z*{>BP=GRR3Ea}xyV*bqry{l^J=0#DaC4ej;1qs8_by?H6Tr@7hl>UKNZt)^B&yl;)&oqzLg zcfZxpE?3k%_iTOVywh%`XVN-E#COl+($9{v(pqSQcrz=)>G!!3HeNxbXGM@})1|9g zG4*@(OBaMvY0P0_TfMFPh fVHk#CZX3S=^^2mI>Ux-D00000NkvXXu0mjfzK(<8 literal 3294 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 cX)(b1KSk$MOV07*qoM6N<$f&{Qds= z{r_0T`1}6fwc-8!#-TGX}_?g)CZq4{k!uZ_g@DrQdoW0kI zu+W69&uN^)W`CK&06mMNcYMVF00dG=L_t(|+U?wHQxh>12H+Dm+1+fh+IF>G0SjJM zkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJTkdTm&kdTm&kdTm&kdP`e zsgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>VI$fQI%^ugM`#6By?GeadWcu z0gy9!D`m!H>Bd!JW(@avE8`|5XX(0PN}!8K>`dkavs;rHL+wy96QGNT=S@#7%xtlm zIW!++@*2zm-Py#Zr`DzqsLm!b{iskFNULSqE9A>SqHem>o31A%XL>S_5?=;V_i_y+ z(xxXhnt#r-l1Y8_*h`r?8Tr|)(RAiO)4jQR`13X0mx07C&p@KBP_2s``KEhv^|*8c z$$_T(v6^1Ig=#R}sE{vjA?ErGDZGUsyoJuWdJMc7Nb1^KF)-u<7q zPy$=;)0>vuWuK2hQhswLf!9yg`88u&eBbR8uhod?Nw09AXH}-#qOLLxeT2%C;R)QQ$Za#qp~cM&YVmS4i-*Fpd!cC zBXc?(4wcg>sHmXGd^VdE<5QX{Kyz$;$sCPl(_*-P2Iw?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF34$0Z;QO!J zOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUCUoZo%k(yku QW&i*H07*qoM6N<$g47z!?*IS* literal 3612 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 iW8 some IntentResult { + await HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!) + + return .result() + } +} + +/// This is required if you want to have the widget be interactive even when the app is fully suspended. +/// Note that this will launch your App so on the Flutter side you should check for the current Lifecycle State before doing heavy tasks +@available(iOS 17, *) +@available(iOSApplicationExtension, unavailable) +extension BackgroundIntent: ForegroundContinuableIntent {} diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index 654a338f..e359d25a 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -2,8 +2,12 @@ + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -22,10 +26,8 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS - UIBackgroundModes - - fetch - + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -43,11 +45,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 4499b85e..f474dd5e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -34,9 +34,7 @@ void callbackDispatcher() { /// Called when Doing Background Work initiated from Widget @pragma("vm:entry-point") -void backgroundCallback(Uri? data) async { - print(data); - +Future interactiveCallback(Uri? data) async { if (data?.host == 'titleclicked') { final greetings = [ 'Hello', @@ -46,25 +44,29 @@ void backgroundCallback(Uri? data) async { 'Ciao', '哈洛', '안녕하세요', - 'xin chào' + 'xin chào', ]; final selectedGreeting = greetings[Random().nextInt(greetings.length)]; - + await HomeWidget.setAppGroupId('YOUR_GROUP_ID'); await HomeWidget.saveWidgetData('title', selectedGreeting); await HomeWidget.updateWidget( - name: 'HomeWidgetExampleProvider', iOSName: 'HomeWidgetExample'); + name: 'HomeWidgetExampleProvider', + iOSName: 'HomeWidgetExample', + ); } } void main() { WidgetsFlutterBinding.ensureInitialized(); Workmanager().initialize(callbackDispatcher, isInDebugMode: kDebugMode); - runApp(MaterialApp(home: MyApp())); + runApp(const MaterialApp(home: MyApp())); } class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + @override - _MyAppState createState() => _MyAppState(); + State createState() => _MyAppState(); } class _MyAppState extends State { @@ -75,7 +77,7 @@ class _MyAppState extends State { void initState() { super.initState(); HomeWidget.setAppGroupId('YOUR_GROUP_ID'); - HomeWidget.registerBackgroundCallback(backgroundCallback); + HomeWidget.registerInteractivityCallback(interactiveCallback); } @override @@ -98,11 +100,11 @@ class _MyAppState extends State { HomeWidget.saveWidgetData('title', _titleController.text), HomeWidget.saveWidgetData('message', _messageController.text), HomeWidget.renderFlutterWidget( - Icon( + const Icon( Icons.flutter_dash, size: 200, ), - logicalSize: Size(200, 200), + logicalSize: const Size(200, 200), key: 'dashIcon', ), ]); @@ -114,7 +116,9 @@ class _MyAppState extends State { Future _updateWidget() async { try { return HomeWidget.updateWidget( - name: 'HomeWidgetExampleProvider', iOSName: 'HomeWidgetExample'); + name: 'HomeWidgetExampleProvider', + iOSName: 'HomeWidgetExample', + ); } on PlatformException catch (exception) { debugPrint('Error Updating Widget. $exception'); } @@ -125,9 +129,10 @@ class _MyAppState extends State { return Future.wait([ HomeWidget.getWidgetData('title', defaultValue: 'Default Title') .then((value) => _titleController.text = value ?? ''), - HomeWidget.getWidgetData('message', - defaultValue: 'Default Message') - .then((value) => _messageController.text = value ?? ''), + HomeWidget.getWidgetData( + 'message', + defaultValue: 'Default Message', + ).then((value) => _messageController.text = value ?? ''), ]); } on PlatformException catch (exception) { debugPrint('Error Getting Data. $exception'); @@ -146,17 +151,21 @@ class _MyAppState extends State { void _launchedFromWidget(Uri? uri) { if (uri != null) { showDialog( - context: context, - builder: (buildContext) => AlertDialog( - title: Text('App started from HomeScreenWidget'), - content: Text('Here is the URI: $uri'), - )); + context: context, + builder: (buildContext) => AlertDialog( + title: const Text('App started from HomeScreenWidget'), + content: Text('Here is the URI: $uri'), + ), + ); } } void _startBackgroundUpdate() { - Workmanager().registerPeriodicTask('1', 'widgetBackgroundUpdate', - frequency: Duration(minutes: 15)); + Workmanager().registerPeriodicTask( + '1', + 'widgetBackgroundUpdate', + frequency: const Duration(minutes: 15), + ); } void _stopBackgroundUpdate() { @@ -173,39 +182,39 @@ class _MyAppState extends State { child: Column( children: [ TextField( - decoration: InputDecoration( + decoration: const InputDecoration( hintText: 'Title', ), controller: _titleController, ), TextField( - decoration: InputDecoration( + decoration: const InputDecoration( hintText: 'Body', ), controller: _messageController, ), ElevatedButton( onPressed: _sendAndUpdate, - child: Text('Send Data to Widget'), + child: const Text('Send Data to Widget'), ), ElevatedButton( onPressed: _loadData, - child: Text('Load Data'), + child: const Text('Load Data'), ), ElevatedButton( onPressed: _checkForWidgetLaunch, - child: Text('Check For Widget Launch'), + child: const Text('Check For Widget Launch'), ), if (Platform.isAndroid) ElevatedButton( onPressed: _startBackgroundUpdate, - child: Text('Update in background'), + child: const Text('Update in background'), ), if (Platform.isAndroid) ElevatedButton( onPressed: _stopBackgroundUpdate, - child: Text('Stop updating in background'), - ) + child: const Text('Stop updating in background'), + ), ], ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 4e9dabb9..7f757721 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -9,17 +9,16 @@ environment: dependencies: flutter: sdk: flutter - workmanager: - git: - url: https://github.com/sunalwaysknows/flutter_workmanager - ref: f37742bcf612c51e9571d623138a21a90a5992ea + workmanager: ^0.5.1 home_widget: path: ../ - cupertino_icons: ^1.0.5 + cupertino_icons: ^1.0.6 dev_dependencies: + flutter_lints: ^2.0.1 + device_info_plus: ^9.0.3 integration_test: sdk: flutter flutter_test: diff --git a/ios/Classes/HomeWidgetBackgroundWorker.swift b/ios/Classes/HomeWidgetBackgroundWorker.swift new file mode 100644 index 00000000..82cc6549 --- /dev/null +++ b/ios/Classes/HomeWidgetBackgroundWorker.swift @@ -0,0 +1,95 @@ +// +// HomeWidgetBackgroundIntent.swift +// home_widget +// +// Created by Anton Borries on 25.08.23. +// + +import Flutter +import Foundation +import Swift + +@available(iOS 17, *) +public struct HomeWidgetBackgroundWorker { + + static let dispatcherKey: String = "home_widget.internal.background.dispatcher" + static let callbackKey: String = "home_widget.internal.background.callback" + + static var isSetupCompleted: Bool = false + static var engine: FlutterEngine? + static var channel: FlutterMethodChannel? + static var queue: [(URL?, String)] = [] + + private static var registerPlugins: FlutterPluginRegistrantCallback? + + public static func setPluginRegistrantCallback(registerPlugins: FlutterPluginRegistrantCallback) { + self.registerPlugins = registerPlugins + } + + /// Call this method to invoke the callback registered in your Flutter App. + /// The url you provide will be used as arguments in the callback function in dart + /// The AppGroup is necessary to retrieve the dart callbacks + static public func run(url: URL?, appGroup: String) async { + if isSetupCompleted { + let preferences = UserDefaults.init(suiteName: appGroup) + + let dispatcher = preferences?.object(forKey: dispatcherKey) as! Int64 + NSLog("Dispatcher: \(dispatcher)") + queue.append((url, appGroup)) + } else { + await sendEvent(url: url, appGroup: appGroup) + } + } + + static func setupEngine(dispatcher: Int64) { + engine = FlutterEngine( + name: "home_widget_background", project: nil, allowHeadlessExecution: true) + + channel = FlutterMethodChannel( + name: "home_widget/background", binaryMessenger: engine!.binaryMessenger, + codec: FlutterStandardMethodCodec.sharedInstance() + ) + let flutterCallbackInfo = FlutterCallbackCache.lookupCallbackInformation(dispatcher) + let callbackName = flutterCallbackInfo?.callbackName + let callbackLibrary = flutterCallbackInfo?.callbackLibraryPath + + let started = engine?.run( + withEntrypoint: flutterCallbackInfo?.callbackName, + libraryURI: flutterCallbackInfo?.callbackLibraryPath) + if registerPlugins != nil { + registerPlugins?(engine!) + } else { + HomeWidgetPlugin.register(with: engine!.registrar(forPlugin: "home_widget")!) + } + + channel?.setMethodCallHandler(handle) + } + + public static func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "HomeWidget.backgroundInitialized": + while !queue.isEmpty { + isSetupCompleted = true + let entry = queue.removeFirst() + Task { + await sendEvent(url: entry.0, appGroup: entry.1) + } + } + result(true) + default: + result(FlutterMethodNotImplemented) + } + } + + static func sendEvent(url: URL?, appGroup: String) async { + let preferences = UserDefaults.init(suiteName: appGroup) + let callback = preferences?.object(forKey: callbackKey) as! Int64 + + channel?.invokeMethod( + "", + arguments: [ + callback, + url?.absoluteString, + ]) + } +} diff --git a/ios/Classes/SwiftHomeWidgetPlugin.swift b/ios/Classes/SwiftHomeWidgetPlugin.swift index a4941557..c8afcf4a 100644 --- a/ios/Classes/SwiftHomeWidgetPlugin.swift +++ b/ios/Classes/SwiftHomeWidgetPlugin.swift @@ -3,146 +3,195 @@ import UIKit import WidgetKit public class SwiftHomeWidgetPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { - - private static var groupId : String? - - private var initialUrl : URL? - private var latestUrl : URL? { - didSet { - if(latestUrl != nil) { - eventSink?.self(latestUrl?.absoluteString) - } - } + + private static var groupId: String? + + private var initialUrl: URL? + private var latestUrl: URL? { + didSet { + if latestUrl != nil { + eventSink?.self(latestUrl?.absoluteString) + } } - - private var eventSink : FlutterEventSink? - - private let notInitializedError = FlutterError( + } + + private var eventSink: FlutterEventSink? + + private let notInitializedError = FlutterError( code: "-7", message: "AppGroupId not set. Call setAppGroupId first", details: nil) - - public static func register(with registrar: FlutterPluginRegistrar) { - let instance = SwiftHomeWidgetPlugin() - - let channel = FlutterMethodChannel(name: "home_widget", binaryMessenger: registrar.messenger()) - registrar.addMethodCallDelegate(instance, channel: channel) - - let eventChannel = FlutterEventChannel(name: "home_widget/updates", binaryMessenger: registrar.messenger()) - eventChannel.setStreamHandler(instance) - - registrar.addApplicationDelegate(instance) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - if call.method == "setAppGroupId" { - guard let args = call.arguments else { - return - } - if let myArgs = args as? [String: Any?], - let groupId = myArgs["groupId"] as? String{ - SwiftHomeWidgetPlugin.groupId = groupId - result(true) - } else { - result(FlutterError(code: "-6", message: "InvalidArguments setAppGroupId must be called with a group id", details: nil)) - } - }else if call.method == "saveWidgetData" { - if (SwiftHomeWidgetPlugin.groupId == nil) { - result(notInitializedError) - return - } - guard let args = call.arguments else { - return - } - if let myArgs = args as? [String: Any?], - let id = myArgs["id"] as? String, - let data = myArgs["data"] { - let preferences = UserDefaults.init(suiteName: SwiftHomeWidgetPlugin.groupId) - if(data != nil) { - preferences?.setValue(data, forKey: id) - } else { - preferences?.removeObject(forKey: id) - } - result(true) - } else { - result(FlutterError(code: "-1", message: "InvalidArguments saveWidgetData must be called with id and data", details: nil)) - } - } else if call.method == "getWidgetData" { - if (SwiftHomeWidgetPlugin.groupId == nil) { - result(notInitializedError) - return - } - guard let args = call.arguments else { - return - } - if let myArgs = args as? [String: Any?], - let id = myArgs["id"] as? String, - let defaultValue = myArgs["defaultValue"] { - let preferences = UserDefaults.init(suiteName: SwiftHomeWidgetPlugin.groupId) - result(preferences?.value(forKey: id) ?? defaultValue) - } else { - result(FlutterError(code: "-2", message: "InvalidArguments getWidgetData must be called with id", details: nil)) - } - } else if call.method == "updateWidget" { - - guard let args = call.arguments else { - return - } - if let myArgs = args as? [String: Any?], - let name = (myArgs["ios"] ?? myArgs["name"]) as? String{ - if #available(iOS 14.0, *) { - #if arch(arm64) || arch(i386) || arch(x86_64) - WidgetCenter.shared.reloadTimelines(ofKind:name) - result(true) - #endif - } else { - result(FlutterError(code: "-4", message: "Widgets are only available on iOS 14.0 and above", details: nil)) - } - } else { - result(FlutterError(code: "-3", message: "InvalidArguments updateWidget must be called with name", details: nil)) - } - } else if call.method == "initiallyLaunchedFromHomeWidget" { - if (SwiftHomeWidgetPlugin.groupId == nil) { - result(notInitializedError) - return - } - result(initialUrl?.absoluteString) - } else if call.method == "registerBackgroundCallback" { - result(nil) + + public static func register(with registrar: FlutterPluginRegistrar) { + let instance = SwiftHomeWidgetPlugin() + + let channel = FlutterMethodChannel(name: "home_widget", binaryMessenger: registrar.messenger()) + registrar.addMethodCallDelegate(instance, channel: channel) + + let eventChannel = FlutterEventChannel( + name: "home_widget/updates", binaryMessenger: registrar.messenger()) + eventChannel.setStreamHandler(instance) + + registrar.addApplicationDelegate(instance) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + if call.method == "setAppGroupId" { + guard let args = call.arguments else { + return + } + if let myArgs = args as? [String: Any?], + let groupId = myArgs["groupId"] as? String + { + SwiftHomeWidgetPlugin.groupId = groupId + result(true) + } else { + result( + FlutterError( + code: "-6", message: "InvalidArguments setAppGroupId must be called with a group id", + details: nil)) + } + } else if call.method == "saveWidgetData" { + if SwiftHomeWidgetPlugin.groupId == nil { + result(notInitializedError) + return + } + guard let args = call.arguments else { + return + } + if let myArgs = args as? [String: Any?], + let id = myArgs["id"] as? String, + let data = myArgs["data"] + { + let preferences = UserDefaults.init(suiteName: SwiftHomeWidgetPlugin.groupId) + if data != nil { + preferences?.setValue(data, forKey: id) } else { - result(FlutterMethodNotImplemented) + preferences?.removeObject(forKey: id) } - } - - public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { - eventSink = events - return nil - } - - public func onCancel(withArguments arguments: Any?) -> FlutterError? { - eventSink = nil - return nil - } + result(true) + } else { + result( + FlutterError( + code: "-1", message: "InvalidArguments saveWidgetData must be called with id and data", + details: nil)) + } + } else if call.method == "getWidgetData" { + if SwiftHomeWidgetPlugin.groupId == nil { + result(notInitializedError) + return + } + guard let args = call.arguments else { + return + } + if let myArgs = args as? [String: Any?], + let id = myArgs["id"] as? String, + let defaultValue = myArgs["defaultValue"] + { + let preferences = UserDefaults.init(suiteName: SwiftHomeWidgetPlugin.groupId) + result(preferences?.value(forKey: id) ?? defaultValue) + } else { + result( + FlutterError( + code: "-2", message: "InvalidArguments getWidgetData must be called with id", + details: nil)) + } + } else if call.method == "updateWidget" { - - public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable : Any] = [:]) -> Bool { - let launchUrl = (launchOptions[UIApplication.LaunchOptionsKey.url] as? NSURL)?.absoluteURL - if(launchUrl != nil && isWidgetUrl(url: launchUrl!)) { - initialUrl = launchUrl?.absoluteURL - latestUrl = initialUrl + guard let args = call.arguments else { + return + } + if let myArgs = args as? [String: Any?], + let name = (myArgs["ios"] ?? myArgs["name"]) as? String + { + if #available(iOS 14.0, *) { + #if arch(arm64) || arch(i386) || arch(x86_64) + WidgetCenter.shared.reloadTimelines(ofKind: name) + result(true) + #endif + } else { + result( + FlutterError( + code: "-4", message: "Widgets are only available on iOS 14.0 and above", details: nil) + ) } - return true + } else { + result( + FlutterError( + code: "-3", message: "InvalidArguments updateWidget must be called with name", + details: nil)) + } + } else if call.method == "initiallyLaunchedFromHomeWidget" { + if SwiftHomeWidgetPlugin.groupId == nil { + result(notInitializedError) + return + } + result(initialUrl?.absoluteString) + } else if call.method == "registerBackgroundCallback" { + if SwiftHomeWidgetPlugin.groupId == nil { + result(notInitializedError) + return + } + if #available(iOS 17.0, *) { + let callbackHandels = call.arguments as! [Int64] + let dispatcher = callbackHandels[0] + let callback = callbackHandels[1] + let preferences = UserDefaults.init(suiteName: SwiftHomeWidgetPlugin.groupId) + preferences?.setValue(dispatcher, forKey: HomeWidgetBackgroundWorker.dispatcherKey) + preferences?.setValue(callback, forKey: HomeWidgetBackgroundWorker.callbackKey) + HomeWidgetBackgroundWorker.setupEngine(dispatcher: dispatcher) + + result(true) + return + } else { + result( + FlutterError( + code: "-5", + message: + "Interactivity is only available on iOS 17.0", + details: nil)) + } + + } else { + result(FlutterMethodNotImplemented) } - - public func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { - if(isWidgetUrl(url: url)) { - latestUrl = url - return true - } - return false + } + + public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) + -> FlutterError? + { + eventSink = events + return nil + } + + public func onCancel(withArguments arguments: Any?) -> FlutterError? { + eventSink = nil + return nil + } + + public func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [AnyHashable: Any] = [:] + ) -> Bool { + let launchUrl = (launchOptions[UIApplication.LaunchOptionsKey.url] as? NSURL)?.absoluteURL + if launchUrl != nil && isWidgetUrl(url: launchUrl!) { + initialUrl = launchUrl?.absoluteURL + latestUrl = initialUrl } - - private func isWidgetUrl(url: URL) -> Bool { - let components = URLComponents.init(url: url, resolvingAgainstBaseURL: false) - return components?.queryItems?.contains(where: {(item) in item.name == "homeWidget"}) ?? false - + return true + } + + public func application( + _ application: UIApplication, open url: URL, + options: [UIApplication.OpenURLOptionsKey: Any] = [:] + ) -> Bool { + if isWidgetUrl(url: url) { + latestUrl = url + return true } + return false + } + + private func isWidgetUrl(url: URL) -> Bool { + let components = URLComponents.init(url: url, resolvingAgainstBaseURL: false) + return components?.queryItems?.contains(where: { (item) in item.name == "homeWidget" }) ?? false + } } diff --git a/lib/home_widget.dart b/lib/home_widget.dart index b613c752..3cdeaf4b 100644 --- a/lib/home_widget.dart +++ b/lib/home_widget.dart @@ -97,12 +97,23 @@ class HomeWidget { } /// Register a callback that gets called when clicked on a specific View in a HomeWidget - /// supported only on Android + /// This enables having Interactive Widgets that can call Dart Code /// More Info on setting this up in the README - static Future registerBackgroundCallback(Function(Uri?) callback) { + @Deprecated('Use `registerInteractivityCallback` instead') + static Future registerBackgroundCallback( + FutureOr Function(Uri?) callback, + ) => + registerInteractivityCallback(callback); + + /// Register a callback that gets called when clicked on a specific View in a HomeWidget + /// This enables having Interactive Widgets that can call Dart Code + /// More Info on setting this up in the README + static Future registerInteractivityCallback( + FutureOr Function(Uri?) callback, + ) { final args = [ ui.PluginUtilities.getCallbackHandle(callbackDispatcher)?.toRawHandle(), - ui.PluginUtilities.getCallbackHandle(callback)?.toRawHandle() + ui.PluginUtilities.getCallbackHandle(callback)?.toRawHandle(), ]; return _channel.invokeMethod('registerBackgroundCallback', args); } diff --git a/lib/home_widget_callback_dispatcher.dart b/lib/home_widget_callback_dispatcher.dart index 9ea4be5d..7c81dc47 100644 --- a/lib/home_widget_callback_dispatcher.dart +++ b/lib/home_widget_callback_dispatcher.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:ui'; import 'package:flutter/cupertino.dart'; @@ -5,7 +6,7 @@ import 'package:flutter/services.dart'; /// Dispatcher used for calling dart code from Native Code while in the background @pragma("vm:entry-point") -void callbackDispatcher() { +Future callbackDispatcher() async { const backgroundChannel = MethodChannel('home_widget/background'); WidgetsFlutterBinding.ensureInitialized(); @@ -14,14 +15,17 @@ void callbackDispatcher() { final callback = PluginUtilities.getCallbackFromHandle( CallbackHandle.fromRawHandle(args[0]), - ); + ) as FutureOr Function(Uri?); - final rawUri = args[1] as String; + final rawUri = args[1] as String?; - final uri = Uri.parse(rawUri); + Uri? uri; + if (rawUri != null) { + uri = Uri.parse(rawUri); + } - callback?.call(uri); + await callback.call(uri); }); - backgroundChannel.invokeMethod('HomeWidget.backgroundInitialized'); + await backgroundChannel.invokeMethod('HomeWidget.backgroundInitialized'); } diff --git a/pubspec.yaml b/pubspec.yaml index 8defa1b9..1f35f963 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: home_widget description: A plugin to provide a common interface for creating HomeScreen Widgets for Android and iOS. -version: 0.3.0 +version: 0.4.0-alpha.0 repository: https://github.com/ABausG/home_widget environment: @@ -10,15 +10,15 @@ environment: dependencies: flutter: sdk: flutter - path_provider: ^2.0.15 - path_provider_foundation: ^2.2.3 + path_provider: ^2.1.1 + path_provider_foundation: ^2.3.1 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.1 + flutter_lints: ^2.0.3 golden_toolkit: ^0.15.0 - mocktail: ^0.3.0 + mocktail: ^1.0.0 path_provider_platform_interface: plugin_platform_interface: diff --git a/test/background_test.dart b/test/background_test.dart index 89d7ed25..0dd60429 100644 --- a/test/background_test.dart +++ b/test/background_test.dart @@ -15,18 +15,20 @@ void main() { const testUri = 'homeWidget://homeWidgetTest'; tester.binding.defaultBinaryMessenger - // ignore: body_might_complete_normally_nullable - .setMockMethodCallHandler(backgroundChannel, (call) { + .setMockMethodCallHandler(backgroundChannel, (call) async { if (call.method == 'HomeWidget.backgroundInitialized') { emitEvent( tester, backgroundChannel.codec .encodeMethodCall(MethodCall('', [callbackHandle, testUri])), ); + return true; + } else { + return null; } }); - callbackDispatcher(); + await callbackDispatcher(); final receivedUri = await completer.future; @@ -42,6 +44,6 @@ void emitEvent(WidgetTester tester, ByteData? event) { ); } -void testCallback(Uri? uri) { +Future testCallback(Uri? uri) async { completer.complete(uri); } diff --git a/test/home_widget_test.dart b/test/home_widget_test.dart index 07b94ca4..33dd5724 100644 --- a/test/home_widget_test.dart +++ b/test/home_widget_test.dart @@ -142,6 +142,7 @@ void main() { final callbackHandle = PluginUtilities.getCallbackHandle(testCallback)?.toRawHandle(); + // ignore: deprecated_member_use_from_same_package expect(await HomeWidget.registerBackgroundCallback(testCallback), true); final argument = await passedArguments.future; @@ -150,6 +151,20 @@ void main() { expect(argument[1], callbackHandle); }); + test('Register Interactivity Callback passes Handles', () async { + final dispatcherHandle = + PluginUtilities.getCallbackHandle(callbackDispatcher)?.toRawHandle(); + final callbackHandle = + PluginUtilities.getCallbackHandle(testCallback)?.toRawHandle(); + + expect(await HomeWidget.registerInteractivityCallback(testCallback), true); + + final argument = await passedArguments.future; + + expect(argument[0], dispatcherHandle); + expect(argument[1], callbackHandle); + }); + group('Widget Clicked', () { test('Send Uris to Stream', () async { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger @@ -327,6 +342,6 @@ void emitEvent(ByteData? event) { ); } -void testCallback(Uri? uri) { +Future testCallback(Uri? uri) async { debugPrint('Called TestCallback'); }