diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index e295db6..a4ccc8e 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -13,6 +13,14 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 47F5E43A2BAB5A0700432453 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F5E4392BAB5A0700432453 /* NotificationService.swift */; }; 47F5E43E2BAB5A0700432453 /* OneSignalNotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 47F5E4372BAB5A0600432453 /* OneSignalNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 47F5E44B2BAB641B00432453 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F5E44A2BAB641B00432453 /* WidgetKit.framework */; }; + 47F5E44D2BAB641B00432453 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47F5E44C2BAB641B00432453 /* SwiftUI.framework */; }; + 47F5E4502BAB641B00432453 /* WidgetExtensionBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F5E44F2BAB641B00432453 /* WidgetExtensionBundle.swift */; }; + 47F5E4522BAB641B00432453 /* WidgetExtensionLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F5E4512BAB641B00432453 /* WidgetExtensionLiveActivity.swift */; }; + 47F5E4582BAB641E00432453 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 47F5E4572BAB641E00432453 /* Assets.xcassets */; }; + 47F5E45C2BAB641E00432453 /* WidgetExtensionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 47F5E4492BAB641B00432453 /* WidgetExtensionExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 47F5E4612BAB649200432453 /* WidgetExtensionLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F5E4512BAB641B00432453 /* WidgetExtensionLiveActivity.swift */; }; + 47F5E4632BAB65A400432453 /* LiveActivitiesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F5E4622BAB65A400432453 /* LiveActivitiesManager.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 91623709E4BD78D4B3B9971F /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F8532D5B1AC7F3527112A68 /* Pods_RunnerTests.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -36,6 +44,13 @@ remoteGlobalIDString = 47F5E4362BAB5A0600432453; remoteInfo = OneSignalNotificationServiceExtension; }; + 47F5E45A2BAB641E00432453 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 47F5E4482BAB641B00432453; + remoteInfo = WidgetExtensionExtension; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -45,6 +60,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + 47F5E45C2BAB641E00432453 /* WidgetExtensionExtension.appex in Embed Foundation Extensions */, 47F5E43E2BAB5A0700432453 /* OneSignalNotificationServiceExtension.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; @@ -77,6 +93,14 @@ 47F5E4392BAB5A0700432453 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 47F5E43B2BAB5A0700432453 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47F5E4442BAB5A7200432453 /* OneSignalNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OneSignalNotificationServiceExtension.entitlements; sourceTree = ""; }; + 47F5E4492BAB641B00432453 /* WidgetExtensionExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetExtensionExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 47F5E44A2BAB641B00432453 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + 47F5E44C2BAB641B00432453 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + 47F5E44F2BAB641B00432453 /* WidgetExtensionBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetExtensionBundle.swift; sourceTree = ""; }; + 47F5E4512BAB641B00432453 /* WidgetExtensionLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetExtensionLiveActivity.swift; sourceTree = ""; }; + 47F5E4572BAB641E00432453 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 47F5E4592BAB641E00432453 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 47F5E4622BAB65A400432453 /* LiveActivitiesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivitiesManager.swift; sourceTree = ""; }; 565BFF667D84005411370C35 /* Pods_OneSignalNotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OneSignalNotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6338503BB3331737AE1DCB10 /* Pods-OneSignalNotificationServiceExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneSignalNotificationServiceExtension.profile.xcconfig"; path = "Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.profile.xcconfig"; sourceTree = ""; }; 69664CD2509151665DB22FD7 /* Pods-OneSignalNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OneSignalNotificationServiceExtension.debug.xcconfig"; path = "Target Support Files/Pods-OneSignalNotificationServiceExtension/Pods-OneSignalNotificationServiceExtension.debug.xcconfig"; sourceTree = ""; }; @@ -106,6 +130,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 47F5E4462BAB641B00432453 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 47F5E44D2BAB641B00432453 /* SwiftUI.framework in Frameworks */, + 47F5E44B2BAB641B00432453 /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -143,12 +176,25 @@ path = OneSignalNotificationServiceExtension; sourceTree = ""; }; + 47F5E44E2BAB641B00432453 /* WidgetExtension */ = { + isa = PBXGroup; + children = ( + 47F5E44F2BAB641B00432453 /* WidgetExtensionBundle.swift */, + 47F5E4512BAB641B00432453 /* WidgetExtensionLiveActivity.swift */, + 47F5E4572BAB641E00432453 /* Assets.xcassets */, + 47F5E4592BAB641E00432453 /* Info.plist */, + ); + path = WidgetExtension; + sourceTree = ""; + }; 7355B6E249C5793B83A2648C /* Frameworks */ = { isa = PBXGroup; children = ( 565BFF667D84005411370C35 /* Pods_OneSignalNotificationServiceExtension.framework */, A5B4F4A7B8DEB27C5286E19F /* Pods_Runner.framework */, 3F8532D5B1AC7F3527112A68 /* Pods_RunnerTests.framework */, + 47F5E44A2BAB641B00432453 /* WidgetKit.framework */, + 47F5E44C2BAB641B00432453 /* SwiftUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -170,6 +216,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 47F5E4382BAB5A0700432453 /* OneSignalNotificationServiceExtension */, + 47F5E44E2BAB641B00432453 /* WidgetExtension */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, 9AD2EBBE273BCC14E5333D08 /* Pods */, @@ -183,6 +230,7 @@ 97C146EE1CF9000F007C117D /* Runner.app */, 331C8081294A63A400263BE5 /* RunnerTests.xctest */, 47F5E4372BAB5A0600432453 /* OneSignalNotificationServiceExtension.appex */, + 47F5E4492BAB641B00432453 /* WidgetExtensionExtension.appex */, ); name = Products; sourceTree = ""; @@ -199,6 +247,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + 47F5E4622BAB65A400432453 /* LiveActivitiesManager.swift */, ); path = Runner; sourceTree = ""; @@ -259,6 +308,23 @@ productReference = 47F5E4372BAB5A0600432453 /* OneSignalNotificationServiceExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + 47F5E4482BAB641B00432453 /* WidgetExtensionExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 47F5E45D2BAB641F00432453 /* Build configuration list for PBXNativeTarget "WidgetExtensionExtension" */; + buildPhases = ( + 47F5E4452BAB641B00432453 /* Sources */, + 47F5E4462BAB641B00432453 /* Frameworks */, + 47F5E4472BAB641B00432453 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WidgetExtensionExtension; + productName = WidgetExtensionExtension; + productReference = 47F5E4492BAB641B00432453 /* WidgetExtensionExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -277,6 +343,7 @@ ); dependencies = ( 47F5E43D2BAB5A0700432453 /* PBXTargetDependency */, + 47F5E45B2BAB641E00432453 /* PBXTargetDependency */, ); name = Runner; productName = Runner; @@ -301,6 +368,9 @@ 47F5E4362BAB5A0600432453 = { CreatedOnToolsVersion = 15.2; }; + 47F5E4482BAB641B00432453 = { + CreatedOnToolsVersion = 15.2; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -323,6 +393,7 @@ 97C146ED1CF9000F007C117D /* Runner */, 331C8080294A63A400263BE5 /* RunnerTests */, 47F5E4362BAB5A0600432453 /* OneSignalNotificationServiceExtension */, + 47F5E4482BAB641B00432453 /* WidgetExtensionExtension */, ); }; /* End PBXProject section */ @@ -342,6 +413,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 47F5E4472BAB641B00432453 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 47F5E4582BAB641E00432453 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -489,11 +568,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 47F5E4452BAB641B00432453 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 47F5E4522BAB641B00432453 /* WidgetExtensionLiveActivity.swift in Sources */, + 47F5E4502BAB641B00432453 /* WidgetExtensionBundle.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 47F5E4632BAB65A400432453 /* LiveActivitiesManager.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 47F5E4612BAB649200432453 /* WidgetExtensionLiveActivity.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -511,6 +601,11 @@ target = 47F5E4362BAB5A0600432453 /* OneSignalNotificationServiceExtension */; targetProxy = 47F5E43C2BAB5A0700432453 /* PBXContainerItemProxy */; }; + 47F5E45B2BAB641E00432453 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 47F5E4482BAB641B00432453 /* WidgetExtensionExtension */; + targetProxy = 47F5E45A2BAB641E00432453 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -777,6 +872,126 @@ }; name = Profile; }; + 47F5E45E2BAB641F00432453 /* Debug */ = { + isa = XCBuildConfiguration; + 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_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 99SW8E36CT; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = WidgetExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = WidgetExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterApplicationLa.WidgetExtension; + 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; + }; + 47F5E45F2BAB641F00432453 /* Release */ = { + isa = XCBuildConfiguration; + 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_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 99SW8E36CT; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = WidgetExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = WidgetExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.2; + 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 = com.example.flutterApplicationLa.WidgetExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 47F5E4602BAB641F00432453 /* Profile */ = { + isa = XCBuildConfiguration; + 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_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 99SW8E36CT; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = WidgetExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = WidgetExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.2; + 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 = com.example.flutterApplicationLa.WidgetExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -956,6 +1171,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 47F5E45D2BAB641F00432453 /* Build configuration list for PBXNativeTarget "WidgetExtensionExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 47F5E45E2BAB641F00432453 /* Debug */, + 47F5E45F2BAB641F00432453 /* Release */, + 47F5E4602BAB641F00432453 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 70693e4..0494734 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -3,11 +3,16 @@ import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + + // Register Flutter channels, specifically for Live Activities + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + LiveActivitiesManager.register(controller: controller) + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 0d4e540..b2db60b 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -49,5 +49,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSSupportsLiveActivities + diff --git a/ios/Runner/LiveActivitiesManager.swift b/ios/Runner/LiveActivitiesManager.swift new file mode 100644 index 0000000..7e38566 --- /dev/null +++ b/ios/Runner/LiveActivitiesManager.swift @@ -0,0 +1,71 @@ +import Foundation + +import ActivityKit +import Flutter +import Foundation + +class LiveActivitiesManager { + private static var callbackChannel: FlutterMethodChannel? = nil + private static var managerChannel: FlutterMethodChannel? = nil + + public static func register(controller: FlutterViewController) { + // Setup the iOS native->Flutter channel. This is primarily used to allow iOS to tell Flutter + // when there is a new Live Activity update push token. + // The name here must be equivalent to the name for `_callbackMethodChannel` in `lib/live_activities_manager.dart` + callbackChannel = FlutterMethodChannel( + name: "com.example.flutter_application_la/liveActivitiesCallback", + binaryMessenger: controller.binaryMessenger + ) + + // Setup the Flutter->iOS native channel. Currently supports `startLiveActivity` but can be + // expanded for more if needed. + // The name here must be equivalent to the name for `_managerMethodChannel` in `lib/live_activities_manager.dart` + managerChannel = FlutterMethodChannel( + name: "com.example.flutter_application_la/liveActivitiesManager", + binaryMessenger: controller.binaryMessenger + ) + managerChannel?.setMethodCallHandler(handleMethodCall) + } + + static func handleMethodCall(call: FlutterMethodCall, result: FlutterResult) { + switch call.method { + case "startLiveActivity": + LiveActivitiesManager.startLiveActivity( + data: call.arguments as? Dictionary ?? [String: Any](), + result: result) + break + default: + result(FlutterMethodNotImplemented) + } + } + + static func startLiveActivity(data: [String: Any], result: FlutterResult) { + if #unavailable(iOS 16.1) { + result(FlutterError(code: "1", message: "Live activity supported on 16.1 and higher", details: nil)) + } + + let attributes = WidgetExtensionAttributes(name: data["name"] as? String ?? "LA Title") + + let state = WidgetExtensionAttributes.ContentState( + emoji: data["emoji"] as? String ?? "😀" + ) + + if #available(iOS 16.1, *) { + do { + let newActivity = try Activity.request( + attributes: attributes, + contentState: state, + pushType: .token) + + Task { + for await pushToken in newActivity.pushTokenUpdates { + let token = pushToken.map {String(format: "%02x", $0)}.joined() + callbackChannel?.invokeMethod("updatePushTokenCallback", arguments: ["activityId": data["activityId"], "token": token ]) + } + } + } catch let error { + result(FlutterError(code: "2", message: "Error requesting live activity", details: nil)) + } + } + } +} diff --git a/ios/WidgetExtension/Assets.xcassets/AccentColor.colorset/Contents.json b/ios/WidgetExtension/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/ios/WidgetExtension/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/WidgetExtension/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/WidgetExtension/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/ios/WidgetExtension/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/WidgetExtension/Assets.xcassets/Contents.json b/ios/WidgetExtension/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/ios/WidgetExtension/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/WidgetExtension/Assets.xcassets/WidgetBackground.colorset/Contents.json b/ios/WidgetExtension/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/ios/WidgetExtension/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/WidgetExtension/Info.plist b/ios/WidgetExtension/Info.plist new file mode 100644 index 0000000..0f118fb --- /dev/null +++ b/ios/WidgetExtension/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/ios/WidgetExtension/WidgetExtensionBundle.swift b/ios/WidgetExtension/WidgetExtensionBundle.swift new file mode 100644 index 0000000..fc63d35 --- /dev/null +++ b/ios/WidgetExtension/WidgetExtensionBundle.swift @@ -0,0 +1,9 @@ +import WidgetKit +import SwiftUI + +@main +struct WidgetExtensionBundle: WidgetBundle { + var body: some Widget { + WidgetExtensionLiveActivity() + } +} diff --git a/ios/WidgetExtension/WidgetExtensionLiveActivity.swift b/ios/WidgetExtension/WidgetExtensionLiveActivity.swift new file mode 100644 index 0000000..e024047 --- /dev/null +++ b/ios/WidgetExtension/WidgetExtensionLiveActivity.swift @@ -0,0 +1,51 @@ +import ActivityKit +import WidgetKit +import SwiftUI + +struct WidgetExtensionAttributes: ActivityAttributes { + public struct ContentState: Codable, Hashable { + // Dynamic stateful properties about your activity go here! + var emoji: String + } + + // Fixed non-changing properties about your activity go here! + var name: String +} + +@available(iOS 16.1, *) +struct WidgetExtensionLiveActivity: Widget { + var body: some WidgetConfiguration { + ActivityConfiguration(for: WidgetExtensionAttributes.self) { context in + // Lock screen/banner UI goes here + VStack { + Text("Hello \(context.attributes.name)") + Text(context.state.emoji) + } + .activityBackgroundTint(Color.cyan) + .activitySystemActionForegroundColor(Color.black) + + } dynamicIsland: { context in + DynamicIsland { + // Expanded UI goes here. Compose the expanded UI through + // various regions, like leading/trailing/center/bottom + DynamicIslandExpandedRegion(.leading) { + Text("Leading") + } + DynamicIslandExpandedRegion(.trailing) { + Text("Trailing") + } + DynamicIslandExpandedRegion(.bottom) { + Text("Bottom \(context.state.emoji)") + } + } compactLeading: { + Text("L") + } compactTrailing: { + Text("T \(context.state.emoji)") + } minimal: { + Text(context.state.emoji) + } + .widgetURL(URL(string: "http://www.onesignal.com")) + .keylineTint(Color.red) + } + } +} diff --git a/lib/live_actiivties_manager.dart b/lib/live_actiivties_manager.dart new file mode 100644 index 0000000..1746700 --- /dev/null +++ b/lib/live_actiivties_manager.dart @@ -0,0 +1,34 @@ +import 'dart:developer'; +import 'dart:async'; +import 'package:flutter/services.dart'; +import 'package:onesignal_flutter/onesignal_flutter.dart'; + +// The flutter version of LiveActivitiesManager. The other side of these channels is in `ios/Runner/LiveActivitiesManager.swift`. +class LiveActivitiesManager { + static const MethodChannel _managerMethodChannel = MethodChannel('com.example.flutter_application_la/liveActivitiesManager'); + static const MethodChannel _callbackMethodChannel = MethodChannel('com.example.flutter_application_la/liveActivitiesCallback'); + + static register() { + _callbackMethodChannel.setMethodCallHandler(_handleCallback); + } + + static Future _handleCallback(MethodCall call) async { + var args = call.arguments.cast(); + switch (call.method) { + case 'updatePushTokenCallback': + OneSignal.LiveActivities.enterLiveActivity(args["activityId"], args["token"]); + default: + log("Unrecognized callback method"); + } + + return null; + } + + static Future startLiveActivity(String activityId, String name, String emoji) async { + try { + await _managerMethodChannel.invokeListMethod('startLiveActivity', {'activityId': activityId, 'name': name, 'emoji': emoji}); + } catch (e, st) { + log(e.toString(), stackTrace: st); + } + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index fd8093a..1d47e64 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_application_la/live_actiivties_manager.dart'; import 'package:onesignal_flutter/onesignal_flutter.dart'; void main() { @@ -11,6 +12,8 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { + // Initialize the channels + LiveActivitiesManager.register(); //Remove this method to stop OneSignal Debugging OneSignal.Debug.setLogLevel(OSLogLevel.verbose); @@ -65,17 +68,12 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - int _counter = 0; + final TextEditingController _activityIdController = TextEditingController(text: ''); + final TextEditingController _nameController = TextEditingController(text: 'Test LA Name'); + final TextEditingController _emojiController = TextEditingController(text: '😀'); - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); + void _startLiveActivity() { + LiveActivitiesManager.startLiveActivity(_activityIdController.text, _nameController.text, _emojiController.text); } @override @@ -99,35 +97,52 @@ class _MyHomePageState extends State { body: Center( // Center is a layout widget. It takes a single child and positions it // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + // Column is also a layout widget. It takes a list of children and + // arranges them vertically. By default, it sizes itself to fit its + // children horizontally, and tries to be as tall as its parent. + // + // Column has various properties to control how it sizes itself and + // how it positions its children. Here we use mainAxisAlignment to + // center the children vertically; the main axis here is the vertical + // axis because Columns are vertical (the cross axis would be + // horizontal). + // + // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" + // action in the IDE, or press "p" in the console), to see the + // wireframe for each widget. + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextFormField( + controller: _activityIdController, + decoration: const InputDecoration( + border: UnderlineInputBorder(), + labelText: 'Activity ID:', + ), + ), + TextFormField( + controller: _nameController, + decoration: const InputDecoration( + border: UnderlineInputBorder(), + labelText: 'Name:', + ), + ), + TextFormField( + controller: _emojiController, + decoration: const InputDecoration( + border: UnderlineInputBorder(), + labelText: 'Emoji:', + ), + ), + ], + ) ), ), floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', + onPressed: _startLiveActivity, + tooltip: 'Start Live Activity', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. );