diff --git a/FirebaseMessaging.podspec b/FirebaseMessaging.podspec index ea99ba09367..ae7ea5fe061 100644 --- a/FirebaseMessaging.podspec +++ b/FirebaseMessaging.podspec @@ -37,6 +37,8 @@ device, and it is completely free. base_dir = "FirebaseMessaging/" s.source_files = [ + base_dir + 'Sources/**/*', + base_dir + 'Sources/LiveActivities/*.{swift,h,m}', base_dir + 'Sources/**/*.{c,m,h}', base_dir + 'Sources/Protogen/nanopb/*.h', base_dir + 'Interop/*.h', @@ -49,6 +51,9 @@ device, and it is completely free. "#{s.module_name}_Privacy" => 'FirebaseMessaging/Sources/Resources/PrivacyInfo.xcprivacy' } s.library = 'sqlite3' +# s.prepare_command = <<-CMD +# echo "Bridging header has been created" +# CMD s.pod_target_xcconfig = { 'GCC_C_LANGUAGE_STANDARD' => 'c99', 'GCC_PREPROCESSOR_DEFINITIONS' => @@ -56,6 +61,7 @@ device, and it is completely free. 'PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1', # Unit tests do library imports using repo-root relative paths. 'HEADER_SEARCH_PATHS' => '"${PODS_TARGET_SRCROOT}"', +# 'SWIFT_OBJC_BRIDGING_HEADER' => '$(PODS_TARGET_SRCROOT)/FirebaseMessaging/Sources/LiveActivities/FirebaseMessaging-Bridging-Header.h', } s.ios.framework = 'SystemConfiguration' s.tvos.framework = 'SystemConfiguration' diff --git a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj index 6e3f4f37392..7b37ef02bec 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj @@ -3,10 +3,27 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ + 2DAD06BA071A722236250BE2 /* Pods_NotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60ED05C1D0C16706EAD1555D /* Pods_NotificationServiceExtension.framework */; }; + 400CC08C2C48300C00CF1777 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 400CC08B2C48300C00CF1777 /* WidgetKit.framework */; }; + 400CC08E2C48300C00CF1777 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 400CC08D2C48300C00CF1777 /* SwiftUI.framework */; }; + 400CC0912C48300C00CF1777 /* SampleLiveActivityBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0902C48300C00CF1777 /* SampleLiveActivityBundle.swift */; }; + 400CC0932C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */; }; + 400CC0952C48300C00CF1777 /* SampleLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0942C48300C00CF1777 /* SampleLiveActivity.swift */; }; + 400CC0972C48300C00CF1777 /* AppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0962C48300C00CF1777 /* AppIntent.swift */; }; + 400CC0992C48300D00CF1777 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 400CC0982C48300D00CF1777 /* Assets.xcassets */; }; + 400CC09D2C48300D00CF1777 /* SampleLiveActivityExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 400CC0A22C4830F400CF1777 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 400CC0A12C4830F400CF1777 /* GoogleService-Info.plist */; }; + 400CC0A62C48347700CF1777 /* SampleLiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */; }; + 400CC0A72C4834E000CF1777 /* SampleLiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */; }; + 400CC0A82C4835DB00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */; }; + 406330BA2C48397A00F8C9BC /* LiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 406330B92C48397A00F8C9BC /* LiveActivityView.swift */; }; + 406330BB2C4839F200F8C9BC /* LiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 406330B92C48397A00F8C9BC /* LiveActivityView.swift */; }; + 406330BC2C483A1F00F8C9BC /* SampleLiveActivityLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */; }; + 406330BD2C483A2600F8C9BC /* SampleLiveActivityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */; }; 519448F4258AEF6F00297021 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519448F3258AEF6F00297021 /* NotificationService.swift */; }; 519448F8258AEF6F00297021 /* NotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 519448F1258AEF6F00297021 /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5194490E258AF0B200297021 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5194490D258AF0B200297021 /* Assets.xcassets */; }; @@ -41,9 +58,19 @@ 51C21D212667FBCE0079AEEE /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 51C21D202667FBCE0079AEEE /* GoogleService-Info.plist */; }; 51C24C622589603800236F25 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C24C602589603800236F25 /* LaunchScreen.storyboard */; }; 51C24C652589606B00236F25 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 51C24C642589606B00236F25 /* logo.png */; }; + 7E49101BD3AE69BDA5BD6694 /* Pods_AppClips.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C3D3BC5D3F838EACB114372 /* Pods_AppClips.framework */; }; + 900887ABCA7B64EE026E0B4C /* Pods_AdvancedSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB563BBBA0F9C123DE99E4E2 /* Pods_AdvancedSample.framework */; }; + D43F963F2DB04638A9D07823 /* Pods_SampleWatchWatchKitExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97D5845E08EDF27DCE9C66FD /* Pods_SampleWatchWatchKitExtension.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 400CC09B2C48300D00CF1777 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 51A1F39025883DCE0025932B /* Project object */; + proxyType = 1; + remoteGlobalIDString = 400CC0892C48300C00CF1777; + remoteInfo = SampleLiveActivityExtension; + }; 519448F6258AEF6F00297021 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 51A1F39025883DCE0025932B /* Project object */; @@ -82,6 +109,7 @@ dstSubfolderSpec = 13; files = ( 519448F8258AEF6F00297021 /* NotificationServiceExtension.appex in Embed App Extensions */, + 400CC09D2C48300D00CF1777 /* SampleLiveActivityExtension.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -122,6 +150,23 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 031E5BFFB105C716E88E02FB /* Pods-AppClips.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppClips.release.xcconfig"; path = "Target Support Files/Pods-AppClips/Pods-AppClips.release.xcconfig"; sourceTree = ""; }; + 1057679BBEE14D968391C25C /* Pods-NotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debug.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debug.xcconfig"; sourceTree = ""; }; + 110F225F548F9768FE18ACE8 /* Pods-SampleWatchWatchKitExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SampleWatchWatchKitExtension.debug.xcconfig"; path = "Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension.debug.xcconfig"; sourceTree = ""; }; + 3C3D3BC5D3F838EACB114372 /* Pods_AppClips.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppClips.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SampleLiveActivityExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 400CC08B2C48300C00CF1777 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + 400CC08D2C48300C00CF1777 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + 400CC0902C48300C00CF1777 /* SampleLiveActivityBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivityBundle.swift; sourceTree = ""; }; + 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivityLiveActivity.swift; sourceTree = ""; }; + 400CC0942C48300C00CF1777 /* SampleLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivity.swift; sourceTree = ""; }; + 400CC0962C48300C00CF1777 /* AppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntent.swift; sourceTree = ""; }; + 400CC0982C48300D00CF1777 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 400CC09A2C48300D00CF1777 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 400CC0A12C4830F400CF1777 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleLiveActivityView.swift; sourceTree = ""; }; + 406330B92C48397A00F8C9BC /* LiveActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiveActivityView.swift; path = ../../Shared/LiveActivityView.swift; sourceTree = ""; }; + 48B90EC6F2056164C3F3866A /* Pods-AdvancedSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AdvancedSample.release.xcconfig"; path = "Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample.release.xcconfig"; sourceTree = ""; }; 519448DE2589900400297021 /* AdvancedSample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AdvancedSample.entitlements; sourceTree = ""; }; 519448F1258AEF6F00297021 /* NotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 519448F3258AEF6F00297021 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; @@ -160,13 +205,30 @@ 51C21D202667FBCE0079AEEE /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../Shared/GoogleService-Info.plist"; sourceTree = ""; }; 51C24C612589603800236F25 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = ../../Shared/Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51C24C642589606B00236F25 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logo.png; path = ../../Shared/logo.png; sourceTree = ""; }; + 60ED05C1D0C16706EAD1555D /* Pods_NotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 846C8434B0C28C746C69E901 /* Pods-AdvancedSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AdvancedSample.debug.xcconfig"; path = "Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample.debug.xcconfig"; sourceTree = ""; }; + 97D5845E08EDF27DCE9C66FD /* Pods_SampleWatchWatchKitExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SampleWatchWatchKitExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AD41B86F67525EE6DD3E9DF1 /* Pods-AppClips.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppClips.debug.xcconfig"; path = "Target Support Files/Pods-AppClips/Pods-AppClips.debug.xcconfig"; sourceTree = ""; }; + B6210F6B8F72F6B5F01C30C2 /* Pods-NotificationServiceExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.release.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.xcconfig"; sourceTree = ""; }; + E2FD8F3FE033F3A974972EF4 /* Pods-SampleWatchWatchKitExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SampleWatchWatchKitExtension.release.xcconfig"; path = "Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension.release.xcconfig"; sourceTree = ""; }; + FB563BBBA0F9C123DE99E4E2 /* Pods_AdvancedSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AdvancedSample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 400CC0872C48300C00CF1777 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 400CC08E2C48300C00CF1777 /* SwiftUI.framework in Frameworks */, + 400CC08C2C48300C00CF1777 /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 519448EE258AEF6F00297021 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2DAD06BA071A722236250BE2 /* Pods_NotificationServiceExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -174,6 +236,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 7E49101BD3AE69BDA5BD6694 /* Pods_AppClips.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -181,6 +244,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D43F963F2DB04638A9D07823 /* Pods_SampleWatchWatchKitExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -188,6 +252,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 900887ABCA7B64EE026E0B4C /* Pods_AdvancedSample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -208,6 +273,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 400CC08F2C48300C00CF1777 /* SampleLiveActivity */ = { + isa = PBXGroup; + children = ( + 400CC0902C48300C00CF1777 /* SampleLiveActivityBundle.swift */, + 400CC0922C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift */, + 400CC0942C48300C00CF1777 /* SampleLiveActivity.swift */, + 400CC0962C48300C00CF1777 /* AppIntent.swift */, + 400CC0982C48300D00CF1777 /* Assets.xcassets */, + 400CC09A2C48300D00CF1777 /* Info.plist */, + 400CC0A52C48347700CF1777 /* SampleLiveActivityView.swift */, + ); + path = SampleLiveActivity; + sourceTree = ""; + }; 519448F2258AEF6F00297021 /* NotificationServiceExtension */ = { isa = PBXGroup; children = ( @@ -221,6 +300,7 @@ isa = PBXGroup; children = ( 51944B27258B091A00297021 /* GoogleService-Info.plist */, + 400CC0A12C4830F400CF1777 /* GoogleService-Info.plist */, 5194490D258AF0B200297021 /* Assets.xcassets */, 51944912258AF0B200297021 /* LaunchScreen.storyboard */, 51944915258AF0B200297021 /* Info.plist */, @@ -279,8 +359,10 @@ 51944906258AF0B100297021 /* AppClips */, 51944952258AF2CF00297021 /* SampleWatchWatchKitApp */, 51944961258AF2D000297021 /* SampleWatchWatchKitExtension */, + 400CC08F2C48300C00CF1777 /* SampleLiveActivity */, 51A1F39925883DCE0025932B /* Products */, 864AA12EFC2050F8D9683C4F /* Pods */, + A47E2AF9ACFCAF48FDA4541E /* Frameworks */, ); sourceTree = ""; }; @@ -293,6 +375,7 @@ 5194494B258AF2CF00297021 /* SampleWatch.app */, 5194494E258AF2CF00297021 /* SampleWatchWatchKitApp.app */, 5194495D258AF2D000297021 /* SampleWatchWatchKitExtension.appex */, + 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */, ); name = Products; sourceTree = ""; @@ -313,6 +396,7 @@ 51A1F3A925883DCF0025932B /* Info.plist */, 51944B9C258B136000297021 /* Assets.xcassets */, 51A1F3A325883DCF0025932B /* Preview Content */, + 406330B92C48397A00F8C9BC /* LiveActivityView.swift */, ); path = AdvancedSample; sourceTree = ""; @@ -328,20 +412,60 @@ 864AA12EFC2050F8D9683C4F /* Pods */ = { isa = PBXGroup; children = ( + 846C8434B0C28C746C69E901 /* Pods-AdvancedSample.debug.xcconfig */, + 48B90EC6F2056164C3F3866A /* Pods-AdvancedSample.release.xcconfig */, + AD41B86F67525EE6DD3E9DF1 /* Pods-AppClips.debug.xcconfig */, + 031E5BFFB105C716E88E02FB /* Pods-AppClips.release.xcconfig */, + 1057679BBEE14D968391C25C /* Pods-NotificationServiceExtension.debug.xcconfig */, + B6210F6B8F72F6B5F01C30C2 /* Pods-NotificationServiceExtension.release.xcconfig */, + 110F225F548F9768FE18ACE8 /* Pods-SampleWatchWatchKitExtension.debug.xcconfig */, + E2FD8F3FE033F3A974972EF4 /* Pods-SampleWatchWatchKitExtension.release.xcconfig */, ); path = Pods; sourceTree = ""; }; + A47E2AF9ACFCAF48FDA4541E /* Frameworks */ = { + isa = PBXGroup; + children = ( + FB563BBBA0F9C123DE99E4E2 /* Pods_AdvancedSample.framework */, + 3C3D3BC5D3F838EACB114372 /* Pods_AppClips.framework */, + 60ED05C1D0C16706EAD1555D /* Pods_NotificationServiceExtension.framework */, + 97D5845E08EDF27DCE9C66FD /* Pods_SampleWatchWatchKitExtension.framework */, + 400CC08B2C48300C00CF1777 /* WidgetKit.framework */, + 400CC08D2C48300C00CF1777 /* SwiftUI.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 400CC0892C48300C00CF1777 /* SampleLiveActivityExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 400CC09E2C48300D00CF1777 /* Build configuration list for PBXNativeTarget "SampleLiveActivityExtension" */; + buildPhases = ( + 400CC0862C48300C00CF1777 /* Sources */, + 400CC0872C48300C00CF1777 /* Frameworks */, + 400CC0882C48300C00CF1777 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SampleLiveActivityExtension; + productName = SampleLiveActivityExtension; + productReference = 400CC08A2C48300C00CF1777 /* SampleLiveActivityExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 519448F0258AEF6F00297021 /* NotificationServiceExtension */ = { isa = PBXNativeTarget; buildConfigurationList = 519448FC258AEF6F00297021 /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */; buildPhases = ( + 8C560F09F5DF1FB1E11C350A /* [CP] Check Pods Manifest.lock */, 519448ED258AEF6F00297021 /* Sources */, 519448EE258AEF6F00297021 /* Frameworks */, 519448EF258AEF6F00297021 /* Resources */, + C3375D38323C9A9C2D0748C2 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -356,9 +480,11 @@ isa = PBXNativeTarget; buildConfigurationList = 5194491A258AF0B200297021 /* Build configuration list for PBXNativeTarget "AppClips" */; buildPhases = ( + 876710BB6E9D2E92C107B36D /* [CP] Check Pods Manifest.lock */, 51944901258AF0B100297021 /* Sources */, 51944902258AF0B100297021 /* Frameworks */, 51944903258AF0B100297021 /* Resources */, + CA9B73000A77BFF7704A11DF /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -409,9 +535,11 @@ isa = PBXNativeTarget; buildConfigurationList = 51944978258AF2D000297021 /* Build configuration list for PBXNativeTarget "SampleWatchWatchKitExtension" */; buildPhases = ( + 92C865B7E5D6E882C28136ED /* [CP] Check Pods Manifest.lock */, 51944959258AF2D000297021 /* Sources */, 5194495A258AF2D000297021 /* Frameworks */, 5194495B258AF2D000297021 /* Resources */, + BEB20BDE02E635E8C44CCFA5 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -426,17 +554,20 @@ isa = PBXNativeTarget; buildConfigurationList = 51A1F3AC25883DCF0025932B /* Build configuration list for PBXNativeTarget "AdvancedSample" */; buildPhases = ( + A97065E4891968053C6EC4C3 /* [CP] Check Pods Manifest.lock */, 51A1F39425883DCE0025932B /* Sources */, 51A1F39525883DCE0025932B /* Frameworks */, 51A1F39625883DCE0025932B /* Resources */, 519448F9258AEF6F00297021 /* Embed App Extensions */, 5194491D258AF0B200297021 /* Embed App Clips */, + A76C37BD4CD3617B5F47C659 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( 519448F7258AEF6F00297021 /* PBXTargetDependency */, 51944918258AF0B200297021 /* PBXTargetDependency */, + 400CC09C2C48300D00CF1777 /* PBXTargetDependency */, ); name = AdvancedSample; productName = AdvancedSample; @@ -449,9 +580,12 @@ 51A1F39025883DCE0025932B /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1230; + LastSwiftUpdateCheck = 1540; LastUpgradeCheck = 1220; TargetAttributes = { + 400CC0892C48300C00CF1777 = { + CreatedOnToolsVersion = 15.4; + }; 519448F0258AEF6F00297021 = { CreatedOnToolsVersion = 12.3; }; @@ -491,11 +625,20 @@ 5194494A258AF2CF00297021 /* SampleWatch */, 5194494D258AF2CF00297021 /* SampleWatchWatchKitApp */, 5194495C258AF2D000297021 /* SampleWatchWatchKitExtension */, + 400CC0892C48300C00CF1777 /* SampleLiveActivityExtension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 400CC0882C48300C00CF1777 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 400CC0992C48300D00CF1777 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 519448EF258AEF6F00297021 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -509,6 +652,7 @@ files = ( 51944914258AF0B200297021 /* LaunchScreen.storyboard in Resources */, 51944B28258B091A00297021 /* GoogleService-Info.plist in Resources */, + 400CC0A22C4830F400CF1777 /* GoogleService-Info.plist in Resources */, 51944911258AF0B200297021 /* Preview Assets.xcassets in Resources */, 5194490E258AF0B200297021 /* Assets.xcassets in Resources */, ); @@ -553,7 +697,178 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 876710BB6E9D2E92C107B36D /* [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-AppClips-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; + }; + 8C560F09F5DF1FB1E11C350A /* [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-NotificationServiceExtension-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; + }; + 92C865B7E5D6E882C28136ED /* [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-SampleWatchWatchKitExtension-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; + }; + A76C37BD4CD3617B5F47C659 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AdvancedSample/Pods-AdvancedSample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + A97065E4891968053C6EC4C3 /* [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-AdvancedSample-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; + }; + BEB20BDE02E635E8C44CCFA5 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SampleWatchWatchKitExtension/Pods-SampleWatchWatchKitExtension-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + C3375D38323C9A9C2D0748C2 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + CA9B73000A77BFF7704A11DF /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AppClips/Pods-AppClips-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AppClips/Pods-AppClips-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AppClips/Pods-AppClips-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ + 400CC0862C48300C00CF1777 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 400CC0A72C4834E000CF1777 /* SampleLiveActivityView.swift in Sources */, + 400CC0912C48300C00CF1777 /* SampleLiveActivityBundle.swift in Sources */, + 400CC0972C48300C00CF1777 /* AppIntent.swift in Sources */, + 400CC0952C48300C00CF1777 /* SampleLiveActivity.swift in Sources */, + 400CC0932C48300C00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 519448ED258AEF6F00297021 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -566,12 +881,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 406330BD2C483A2600F8C9BC /* SampleLiveActivityView.swift in Sources */, 51944924258AF0F500297021 /* AppDelegate.swift in Sources */, 51944930258AF10200297021 /* UserSettings.swift in Sources */, 51944932258AF10200297021 /* TopicView.swift in Sources */, + 406330BC2C483A1F00F8C9BC /* SampleLiveActivityLiveActivity.swift in Sources */, 51944931258AF10200297021 /* Identity.swift in Sources */, 51944928258AF0F900297021 /* SceneDelegate.swift in Sources */, 5194492C258AF0FD00297021 /* ContentView.swift in Sources */, + 406330BB2C4839F200F8C9BC /* LiveActivityView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -591,17 +909,25 @@ buildActionMask = 2147483647; files = ( 51A1F3B125883E370025932B /* AppDelegate.swift in Sources */, + 400CC0A62C48347700CF1777 /* SampleLiveActivityView.swift in Sources */, 51A1F3B525883E630025932B /* SceneDelegate.swift in Sources */, + 406330BA2C48397A00F8C9BC /* LiveActivityView.swift in Sources */, 51A1F3CB25883EFF0025932B /* TopicView.swift in Sources */, 51A1F3B825883E810025932B /* ContentView.swift in Sources */, 51A1F3CA25883EFF0025932B /* UserSettings.swift in Sources */, 51A1F3C625883EF60025932B /* Identity.swift in Sources */, + 400CC0A82C4835DB00CF1777 /* SampleLiveActivityLiveActivity.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 400CC09C2C48300D00CF1777 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 400CC0892C48300C00CF1777 /* SampleLiveActivityExtension */; + targetProxy = 400CC09B2C48300D00CF1777 /* PBXContainerItemProxy */; + }; 519448F7258AEF6F00297021 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 519448F0258AEF6F00297021 /* NotificationServiceExtension */; @@ -652,8 +978,78 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 400CC09F2C48300D00CF1777 /* 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_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SampleLiveActivity/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = SampleLiveActivity; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev.SampleLiveActivity; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 400CC0A02C48300D00CF1777 /* 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_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SampleLiveActivity/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = SampleLiveActivity; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev.SampleLiveActivity; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 519448FA258AEF6F00297021 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 1057679BBEE14D968391C25C /* Pods-NotificationServiceExtension.debug.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; @@ -676,6 +1072,7 @@ }; 519448FB258AEF6F00297021 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B6210F6B8F72F6B5F01C30C2 /* Pods-NotificationServiceExtension.release.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Manual; @@ -698,6 +1095,7 @@ }; 5194491B258AF0B200297021 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = AD41B86F67525EE6DD3E9DF1 /* Pods-AppClips.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -708,7 +1106,7 @@ DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = AppClips/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -723,6 +1121,7 @@ }; 5194491C258AF0B200297021 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 031E5BFFB105C716E88E02FB /* Pods-AppClips.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -733,7 +1132,7 @@ DEVELOPMENT_TEAM = EQHXZ8M8AV; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = AppClips/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 14.3; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -822,6 +1221,7 @@ }; 51944976258AF2D000297021 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 110F225F548F9768FE18ACE8 /* Pods-SampleWatchWatchKitExtension.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CODE_SIGN_ENTITLEMENTS = SampleWatchWatchKitExtension/SampleWatchWatchKitExtension.entitlements; @@ -849,6 +1249,7 @@ }; 51944977258AF2D000297021 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E2FD8F3FE033F3A974972EF4 /* Pods-SampleWatchWatchKitExtension.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CODE_SIGN_ENTITLEMENTS = SampleWatchWatchKitExtension/SampleWatchWatchKitExtension.entitlements; @@ -925,7 +1326,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -980,7 +1381,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.2; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -992,6 +1393,7 @@ }; 51A1F3AD25883DCF0025932B /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 846C8434B0C28C746C69E901 /* Pods-AdvancedSample.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1017,6 +1419,7 @@ }; 51A1F3AE25883DCF0025932B /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 48B90EC6F2056164C3F3866A /* Pods-AdvancedSample.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -1043,6 +1446,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 400CC09E2C48300D00CF1777 /* Build configuration list for PBXNativeTarget "SampleLiveActivityExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 400CC09F2C48300D00CF1777 /* Debug */, + 400CC0A02C48300D00CF1777 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 519448FC258AEF6F00297021 /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist index 2688b32b32f..6901699a310 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist +++ b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample/Info.plist @@ -20,6 +20,8 @@ 1 LSRequiresIPhoneOS + NSSupportsLiveActivities + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/FirebaseMessaging/Apps/AdvancedSample/Podfile b/FirebaseMessaging/Apps/AdvancedSample/Podfile index b5d8b6cb485..e58554029ee 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/Podfile +++ b/FirebaseMessaging/Apps/AdvancedSample/Podfile @@ -29,7 +29,7 @@ target 'AppClips' do end target 'SampleWatchWatchKitExtension' do - platform :watchos, '6.0' + platform :watchos, '7.0' shared_pods end diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift new file mode 100644 index 00000000000..a0135df3007 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import WidgetKit +import AppIntents + +struct ConfigurationAppIntent: WidgetConfigurationIntent { + static var title: LocalizedStringResource = "Configuration" + static var description = IntentDescription("This is an example widget.") + + // An example configurable parameter. + @Parameter(title: "Favorite Emoji", default: "😃") + var favoriteEmoji: String +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000000..eb878970081 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AppIcon.appiconset/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..13613e3ee1a --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/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/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json new file mode 100644 index 00000000000..73c00596a7f --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 00000000000..eb878970081 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist new file mode 100644 index 00000000000..0f118fb75e4 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift new file mode 100644 index 00000000000..5da53bb3d7c --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift @@ -0,0 +1,91 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import WidgetKit +import SwiftUI + +struct Provider: AppIntentTimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) + } + + func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { + SimpleEntry(date: Date(), configuration: configuration) + } + + func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate, configuration: configuration) + entries.append(entry) + } + + return Timeline(entries: entries, policy: .atEnd) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let configuration: ConfigurationAppIntent +} + +struct SampleLiveActivityEntryView : View { + var entry: Provider.Entry + + var body: some View { + VStack { + Text("Time:") + Text(entry.date, style: .time) + + Text("Favorite Emoji:") + Text(entry.configuration.favoriteEmoji) + } + } +} + +struct SampleLiveActivity: Widget { + let kind: String = "SampleLiveActivity" + + var body: some WidgetConfiguration { + AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in + SampleLiveActivityEntryView(entry: entry) + .containerBackground(.fill.tertiary, for: .widget) + } + } +} + +extension ConfigurationAppIntent { + fileprivate static var smiley: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "😀" + return intent + } + + fileprivate static var starEyes: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "🤩" + return intent + } +} + +#Preview(as: .systemSmall) { + SampleLiveActivity() +} timeline: { + SimpleEntry(date: .now, configuration: .smiley) + SimpleEntry(date: .now, configuration: .starEyes) +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift new file mode 100644 index 00000000000..6edb990aac9 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import WidgetKit +import SwiftUI + +@main +struct SampleLiveActivityBundle: WidgetBundle { + var body: some Widget { + SampleLiveActivity() + SampleLiveActivityLiveActivity() + } +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift new file mode 100644 index 00000000000..31c8b2591b8 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift @@ -0,0 +1,108 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import ActivityKit +import WidgetKit +import SwiftUI + +struct SampleLiveActivityAttributes: ActivityAttributes { + public struct ContentState: Codable, Hashable { + enum LVStatus: Float, Codable, Hashable { + case started = 0 + case inProgress = 1 + case completed = 2 + + var description: String { + switch self { + case .started: + return "Your Live Activity is started!" + case .inProgress: + return "Your Live Activity is in progress!" + case .completed: + return "Your Live activity is completed!" + } + } + } + + let status: LVStatus + } + + // Fixed non-changing properties about your activity go here! + var lvInstanceNumber: Double +} + +struct SampleLiveActivityLiveActivity: Widget { + var body: some WidgetConfiguration { + ActivityConfiguration(for: SampleLiveActivityAttributes.self) { context in + // Lock screen/banner UI goes here + VStack { + SampleLiveActivityView(context: context) + } + .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") + // more content + } + } compactLeading: { + Text("L") + } compactTrailing: { + Text("T") + } minimal: { + Text("M") + } + .widgetURL(URL(string: "http://www.apple.com")) + .keylineTint(Color.red) + } + } +} + +extension SampleLiveActivityAttributes { + fileprivate static var preview: SampleLiveActivityAttributes { + SampleLiveActivityAttributes(lvInstanceNumber: 1) + } +} + +extension SampleLiveActivityAttributes.ContentState { + fileprivate static var stateStarted: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status:LVStatus.started) + } + + fileprivate static var stateInProgress: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status:LVStatus.inProgress) + } + + fileprivate static var stateCompleted: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status:LVStatus.completed) + } +} + +#Preview("Notification", as: .content, using: SampleLiveActivityAttributes.preview) { + SampleLiveActivityLiveActivity() +} contentStates: { + SampleLiveActivityAttributes.ContentState.stateStarted + SampleLiveActivityAttributes.ContentState.stateInProgress + SampleLiveActivityAttributes.ContentState.stateCompleted +} diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift new file mode 100644 index 00000000000..fbfa010dc70 --- /dev/null +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift @@ -0,0 +1,43 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI +import WidgetKit + +struct SampleLiveActivityView: View { + + let context: ActivityViewContext< SampleLiveActivityAttributes> + + var body: some View { + VStack { + HStack { + Image(systemName: "cup.and.saucer") + ProgressView(value: context.state.status.rawValue, total: 2) + .tint(.black) + .background(Color.brown) + Image(systemName: "cup.and.saucer.fill") + } + .padding(16) + + Text("\(context.state.status.description)") + .font(.system(size: 18, weight: .semibold)) + .padding(.bottom) + Text("Instance No: " + String(context.attributes.lvInstanceNumber)) + .font(.system(size: 18, weight: .semibold)) + .padding(.bottom) + Spacer() + } + .background(Color.brown.opacity(0.6)) + } +} diff --git a/FirebaseMessaging/Apps/Shared/ContentView.swift b/FirebaseMessaging/Apps/Shared/ContentView.swift index 6d9cb526f38..f6430eaa257 100644 --- a/FirebaseMessaging/Apps/Shared/ContentView.swift +++ b/FirebaseMessaging/Apps/Shared/ContentView.swift @@ -24,106 +24,110 @@ struct ContentView: View { @EnvironmentObject var settings: UserSettings @State private var log: String = "" - var body: some View { - NavigationView { - // Outer stack containing the list and the buttons. - VStack { - List { - VStack(alignment: .leading) { - Text("InstallationsID") - .font(.subheadline) - .fontWeight(.semibold) - - Text(identity.installationsID ?? "None").foregroundColor(.green) - } - - VStack(alignment: .leading) { - Text("Token") - .font(.subheadline) - .fontWeight(.semibold) - Text(identity.token ?? "None") - .foregroundColor(.green) - // Increase the layout priority to allow more than one line to be shown. Without this, - // the - // simulator renders a single truncated line even though the Preview renders it - // appropriately. Potentially a bug in the simulator? - .layoutPriority(1) - .lineLimit(7) - } - NavigationLink(destination: SettingsView()) { - Text("Settings") - .fontWeight(.semibold) - } - NavigationLink(destination: TopicView()) { - Text("Topic") - .fontWeight(.semibold) - } - - // MARK: Action buttons - - VStack(alignment: .leading) { - Text("getToken") - .fontWeight(.semibold) - HStack { - Button(action: getIDAndToken) { - HStack { - Image(systemName: "arrow.clockwise.circle.fill") - Text("FID & Token") - .fontWeight(.semibold) - } - } - Button(action: getFCMToken) { - HStack { - Image(systemName: "arrow.clockwise.circle.fill").font(.body) - Text("getToken") - .fontWeight(.semibold) - } - } - } - }.font(.system(size: 14)) - - VStack(alignment: .leading) { - Text("deleteToken") - .fontWeight(.semibold) - HStack { - Button(action: deleteFCMToken) { - HStack { - Image(systemName: "trash.fill") - Text("deleteToken") - .fontWeight(.semibold) + var body: some View { + NavigationView { + // Outer stack containing the list and the buttons. + VStack { + List { + VStack(alignment: .leading) { + Text("InstallationsID") + .font(.subheadline) + .fontWeight(.semibold) + + Text(identity.installationsID ?? "None").foregroundColor(.green) + } + + VStack(alignment: .leading) { + Text("Token") + .font(.subheadline) + .fontWeight(.semibold) + Text(identity.token ?? "None") + .foregroundColor(.green) + // Increase the layout priority to allow more than one line to be shown. Without this, + // the + // simulator renders a single truncated line even though the Preview renders it + // appropriately. Potentially a bug in the simulator? + .layoutPriority(1) + .lineLimit(7) + } + NavigationLink(destination: SettingsView()) { + Text("Settings") + .fontWeight(.semibold) + } + NavigationLink(destination: TopicView()) { + Text("Topic") + .fontWeight(.semibold) + } + NavigationLink(destination: LiveActivityView()) { + Text("Live Activity") + .fontWeight(.semibold) + } + + // MARK: Action buttons + + VStack(alignment: .leading) { + Text("getToken") + .fontWeight(.semibold) + HStack { + Button(action: getIDAndToken) { + HStack { + Image(systemName: "arrow.clockwise.circle.fill") + Text("FID & Token") + .fontWeight(.semibold) + } + } + Button(action: getFCMToken) { + HStack { + Image(systemName: "arrow.clockwise.circle.fill").font(.body) + Text("getToken") + .fontWeight(.semibold) + } + } + } + }.font(.system(size: 14)) + + VStack(alignment: .leading) { + Text("deleteToken") + .fontWeight(.semibold) + HStack { + Button(action: deleteFCMToken) { + HStack { + Image(systemName: "trash.fill") + Text("deleteToken") + .fontWeight(.semibold) + } + } + } + }.font(.system(size: 14)) + + VStack(alignment: .leading) { + Text("delete") + .fontWeight(.semibold) + HStack { + Button(action: deleteFCM) { + HStack { + Image(systemName: "trash.fill") + Text("FM.delete") + .fontWeight(.semibold) + } + } + Button(action: deleteFID) { + HStack { + Image(systemName: "trash.fill") + Text("FIS.delete") + .fontWeight(.semibold) + } + } + } + }.font(.system(size: 14)) + Text("\(log)") + .lineLimit(10) + .multilineTextAlignment(.leading) } - } - } - }.font(.system(size: 14)) - - VStack(alignment: .leading) { - Text("delete") - .fontWeight(.semibold) - HStack { - Button(action: deleteFCM) { - HStack { - Image(systemName: "trash.fill") - Text("FM.delete") - .fontWeight(.semibold) - } - } - Button(action: deleteFID) { - HStack { - Image(systemName: "trash.fill") - Text("FIS.delete") - .fontWeight(.semibold) - } - } - } - }.font(.system(size: 14)) - Text("\(log)") - .lineLimit(10) - .multilineTextAlignment(.leading) + .navigationBarTitle("Firebase Messaging") + }.buttonStyle(IdentityButtonStyle()) } - .navigationBarTitle("Firebase Messaging") - }.buttonStyle(IdentityButtonStyle()) } - } func getIDAndToken() { Messaging.messaging().token { token, error in diff --git a/FirebaseMessaging/Apps/Shared/LiveActivityView.swift b/FirebaseMessaging/Apps/Shared/LiveActivityView.swift new file mode 100644 index 00000000000..68784f910e5 --- /dev/null +++ b/FirebaseMessaging/Apps/Shared/LiveActivityView.swift @@ -0,0 +1,150 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftUI +import ActivityKit +import SampleLiveActivityExtension +import FirebaseMessaging + +struct LiveActivityView: View { + + @State var activityTokenDict = [String:String]() + + var body: some View { + VStack{ + Button("Refresh List") { + Task{ + refreshAcitivtyList() + } + }.padding(10) + + Button("Cancel all running Activities") { + cancelAllRunningActivities() + }.padding(10) + + Button("Start Live Activity with push") { + startLiveActivity(supportPush: true) + }.padding(10) + + Button("Start Live Activity without push") { + startLiveActivity(supportPush: false) + }.padding(10) + + List{ + ForEach(activityTokenDict.keys.sorted(),id: \.self){ key in + VStack{ + Text("ActivityId: " + key).frame(maxWidth: .infinity,alignment: .leading) + + Button("Copy"){ + UIPasteboard.general.string = activityTokenDict[key]! + }.frame(alignment: .trailing) + + Text("Push Token: " + activityTokenDict[key]!).frame(maxWidth: .infinity, alignment: .leading) + }.padding(10) + } + } + }.onAppear{ + refreshAcitivtyList() + } + } + + private func refreshAcitivtyList(){ + Task{ + activityTokenDict.removeAll() + + let ptsToken = Activity.pushToStartToken + + if(ptsToken != nil){ + let ptsTokenString = getFormatedToken(token: ptsToken!) + activityTokenDict["PTS"] = ptsTokenString + }else{ + activityTokenDict["PTS"] = "Not available yet.!" + Task{ + for await ptsToken in Activity.pushToStartTokenUpdates { + let ptsTokenString = getFormatedToken(token: ptsToken) + activityTokenDict["PTS"] = ptsTokenString + refreshAcitivtyList() + } + } + } + + let activities = Activity.activities + for activity in activities { + if(activity.pushToken != nil){ + let activityToken = getFormatedToken(token: activity.pushToken!) + activityTokenDict[activity.id] = activityToken + }else{ + activityTokenDict[activity.id] = "Not available yet!" + } + } + } + } + + func getFormatedToken(token:Data) -> String{ + return token.reduce("") { + $0 + String(format: "%02x", $1) + } + } + + private func startLiveActivity(supportPush:Bool) { + let lAttributes = SampleLiveActivityAttributes(lvInstanceNumber: Date().timeIntervalSince1970) + let initialState = SampleLiveActivityAttributes.ContentState(status: .started) + let content = ActivityContent(state: initialState, staleDate: nil, relevanceScore: 1.0) + + if(supportPush){ + let activity = try? Activity.request( + attributes: lAttributes, + content: content, + pushType: .token + ) + + if(activity != nil){ + Task{ + for await pushToken in activity!.pushTokenUpdates { + let activityToken = getFormatedToken(token: pushToken) + activityTokenDict[activity!.id] = activityToken + refreshAcitivtyList() + } + } + } + }else{ + let activity = try? Activity.request( + attributes: lAttributes, + content: content, + pushType: .none + ) + } + + refreshAcitivtyList() + } + + func cancelAllRunningActivities() { + Task{ + for activity in Activity.activities { + let initialContentState = SampleLiveActivityAttributes.ContentState(status: .started) + + await activity.end( + ActivityContent(state: initialContentState, staleDate: Date()), + dismissalPolicy: .immediate + ) + } + + refreshAcitivtyList() + } + } +} + +#Preview { + LiveActivityView() +} diff --git a/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj index dd736c2b203..4224b6e136b 100644 --- a/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/SwiftUISample/SwiftUISample.xcodeproj/project.pbxproj @@ -15,9 +15,12 @@ 5134F860277EAEC600AEE915 /* SwiftUISampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5134F85F277EAEC600AEE915 /* SwiftUISampleApp.swift */; }; 5134F867277EAEC900AEE915 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5134F866277EAEC900AEE915 /* Preview Assets.xcassets */; }; 5134F86E277EAEF800AEE915 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5134F86D277EAEF800AEE915 /* GoogleService-Info.plist */; }; + CD7B98AE712C5BD92A57F49B /* Pods_SwiftUISample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23CD43CFCEE7C6924EB885EB /* Pods_SwiftUISample.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 06DCB10835EADC7F2DB36057 /* Pods-SwiftUISample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftUISample.debug.xcconfig"; path = "Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample.debug.xcconfig"; sourceTree = ""; }; + 23CD43CFCEE7C6924EB885EB /* Pods_SwiftUISample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftUISample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5104EF052787BC590026A7C4 /* Identity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Identity.swift; path = ../../Shared/Identity.swift; sourceTree = ""; }; 5104EF062787BC590026A7C4 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContentView.swift; path = ../../Shared/ContentView.swift; sourceTree = ""; }; 5104EF072787BC590026A7C4 /* UserSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UserSettings.swift; path = ../../Shared/UserSettings.swift; sourceTree = ""; }; @@ -29,6 +32,7 @@ 5134F86D277EAEF800AEE915 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../Shared/GoogleService-Info.plist"; sourceTree = ""; }; 5134F86F277EAF0A00AEE915 /* SwiftUISample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftUISample.entitlements; sourceTree = ""; }; 5134F870277EAF1600AEE915 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 79C933138349C96A477A368A /* Pods-SwiftUISample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftUISample.release.xcconfig"; path = "Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -36,18 +40,28 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CD7B98AE712C5BD92A57F49B /* Pods_SwiftUISample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4B9D6C361383C06EE523D776 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 23CD43CFCEE7C6924EB885EB /* Pods_SwiftUISample.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 5134F853277EAEC600AEE915 = { isa = PBXGroup; children = ( 5134F85E277EAEC600AEE915 /* SwiftUISample */, 5134F85D277EAEC600AEE915 /* Products */, A18B84A7C0849ACD661DA216 /* Pods */, + 4B9D6C361383C06EE523D776 /* Frameworks */, ); sourceTree = ""; }; @@ -87,6 +101,8 @@ A18B84A7C0849ACD661DA216 /* Pods */ = { isa = PBXGroup; children = ( + 06DCB10835EADC7F2DB36057 /* Pods-SwiftUISample.debug.xcconfig */, + 79C933138349C96A477A368A /* Pods-SwiftUISample.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -98,9 +114,11 @@ isa = PBXNativeTarget; buildConfigurationList = 5134F86A277EAEC900AEE915 /* Build configuration list for PBXNativeTarget "SwiftUISample" */; buildPhases = ( + FB277254786D33A1256CB1E5 /* [CP] Check Pods Manifest.lock */, 5134F858277EAEC600AEE915 /* Sources */, 5134F859277EAEC600AEE915 /* Frameworks */, 5134F85A277EAEC600AEE915 /* Resources */, + 87E3D238B4B412EC4E446F6E /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -157,6 +175,48 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 87E3D238B4B412EC4E446F6E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwiftUISample/Pods-SwiftUISample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + FB277254786D33A1256CB1E5 /* [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-SwiftUISample-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 PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 5134F858277EAEC600AEE915 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -291,6 +351,7 @@ }; 5134F86B277EAEC900AEE915 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 06DCB10835EADC7F2DB36057 /* Pods-SwiftUISample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -325,6 +386,7 @@ }; 5134F86C277EAEC900AEE915 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 79C933138349C96A477A368A /* Pods-SwiftUISample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; diff --git a/FirebaseMessaging/Sources/LiveActivities/LiveActivityManager.swift b/FirebaseMessaging/Sources/LiveActivities/LiveActivityManager.swift new file mode 100644 index 00000000000..4c7b2f19bef --- /dev/null +++ b/FirebaseMessaging/Sources/LiveActivities/LiveActivityManager.swift @@ -0,0 +1,69 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +import ActivityKit +import UIKit + +/** + Live activity manager class for FCM SDK + + Functionalities: + - Keeps track of live activity updates (starting and ending) + - Keeps track of live activity token updates and push to start token updates. + - Uploads the updated tokens to FCM backend when needed. + + */ +@available(iOS 16.1, *) +public class LiveActivityManager{ + + // To keep track of registered Live Acitvities so that they can be invalidated + private static var acitivityWrappers = [LiveActivityTypeWrapper]() + + // Class to manage Live Activity tokens + private static let tokenManager:LiveActivityTokenManager = LiveActivityTokenManager.getInstance() + + // Log tag for printing logs + public static let LOG_TAG = "LAM# " + + public static func liveActivityRegsistration() -> RegistrationRequest{ + return RegistrationRequest() + } + + static func invalidateActivities(){ + Task{ + var refreshedIds :[String] = [] + for activityWrapper in acitivityWrappers{ + activityWrapper.invalidateActivities() + refreshedIds.append(contentsOf:activityWrapper.getActiveActivityIds()) + } + + await tokenManager.invalidateWith(activityIds: refreshedIds) + + NSLog(LOG_TAG + "Invalidated") + } + } + + static func setActivityWrappers(wrappers: [LiveActivityTypeWrapper]){ + acitivityWrappers = wrappers + } + + public static func getLiveAcitivityTokens() async -> [String:String] { + let tokens = await tokenManager.getTokens() + return tokens.mapValues { $0 }; + } + +} diff --git a/FirebaseMessaging/Sources/LiveActivities/LiveActivityRegistrationRequest.swift b/FirebaseMessaging/Sources/LiveActivities/LiveActivityRegistrationRequest.swift new file mode 100644 index 00000000000..641404b53cb --- /dev/null +++ b/FirebaseMessaging/Sources/LiveActivities/LiveActivityRegistrationRequest.swift @@ -0,0 +1,59 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +import ActivityKit + +/** + Builder class to accept Live activity Registration requests + */ +@available(iOS 16.1, *) +public class RegistrationRequest{ + + let tokenManager:LiveActivityTokenManager = LiveActivityTokenManager.getInstance() + var acitivityDict = [String:LiveActivityTypeWrapper]() + + public func add(type: T.Type) -> RegistrationRequest{ + let key = String(describing: type) + acitivityDict[key] = LiveActivityTypeWrapperImpl() + return self + } + + /** + Registers the live activities and returns the Push to start id if supported. + + PTS id is returned only if iOS 17.2 or above and atleast one Live activity type is registered with FCM + */ + public func register() -> String?{ + var wrappers = [LiveActivityTypeWrapper]() + var ptsTokenId:String? = nil + + if(!acitivityDict.isEmpty){ + ptsTokenId = tokenManager.ptsTokenId + acitivityDict.first?.value.initPTSToken(ptsTokenId: ptsTokenId) + + for wrapper in acitivityDict.values{ + wrappers.append(wrapper) + wrapper.listenForActivityUpdates() + } + } + + LiveActivityManager.setActivityWrappers(wrappers: wrappers) + LiveActivityManager.invalidateActivities() + + return ptsTokenId + } +} diff --git a/FirebaseMessaging/Sources/LiveActivities/LiveActivityTokenManager.swift b/FirebaseMessaging/Sources/LiveActivities/LiveActivityTokenManager.swift new file mode 100644 index 00000000000..e37cad02d8b --- /dev/null +++ b/FirebaseMessaging/Sources/LiveActivities/LiveActivityTokenManager.swift @@ -0,0 +1,141 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation + +/** + Token manager class which is synchronized. + */ +@available(iOS 16.1, *) +actor LiveActivityTokenManager{ + + private let TOKENS_DEFAULTS_KEY = "TOKENS_DEFAULTS_KEY" + private var activityTokens : [String:String] + private let userDefaults = UserDefaults(suiteName: "LAM")! + private static let shared = LiveActivityTokenManager() + public let ptsTokenId:String? + + /** + Returns the singleton instance of token manager. + */ + public static func getInstance() -> LiveActivityTokenManager{ + return shared + } + + private init(){ + self.activityTokens = userDefaults.dictionary(forKey: TOKENS_DEFAULTS_KEY) as? [String: String] ?? [:] + + if #available(iOS 17.2, *) { + //Initializing PTS token id only if iOS 17.2 or above + let PTS_TOKEN_ID_DEFAULTS_KEY = "PTS_TOKEN_ID_DEFAULTS_KEY" + var ptsId = userDefaults.string(forKey: PTS_TOKEN_ID_DEFAULTS_KEY) + if(ptsId == nil || ptsId == ""){ + ptsId = UUID().uuidString + userDefaults.set(ptsId, forKey: PTS_TOKEN_ID_DEFAULTS_KEY) + } + ptsTokenId = ptsId + }else{ + ptsTokenId = nil + } + } + + func getPTSTokenId() -> String?{ + return ptsTokenId + } + + func getTokens() -> [String:String]{ + return activityTokens + } + + func saveTokensToUserDefaults(){ + userDefaults.set(activityTokens, forKey: TOKENS_DEFAULTS_KEY) + } + + func haveTokenFor(activityId:String) -> Bool{ + return activityTokens.keys.contains(activityId) + } + + func checkAndUpdateTokenFor(activityId:String,activityToken:String){ + if(activityId=="" || activityToken == ""){ + return + } + + if (haveTokenFor(activityId: activityId)){ + let oldToken = activityTokens[activityId] + + if(oldToken == nil || oldToken == "" || oldToken != activityToken){ + //Token needs update + updateToken(id: activityId, token: activityToken, reason: .ActivityTokenUpdated) + } + }else{ + //New token + updateToken(id: activityId, token: activityToken, reason: .ActivityTokenAdded) + } + + } + + func checkAndRemoveTokenFor(activityId:String){ + if(activityTokens.keys.contains(activityId)){ + // Remove token + let token = activityTokens[activityId]! + updateToken(id: activityId, token: token, reason: .ActivityTokenRemoved) + } + } + + func invalidateWith(activityIds: [String]){ + //Checking and removing ended acitivities + for acitivtyId in activityTokens.keys{ + if(acitivtyId == ptsTokenId){ + //PTS tokens are meant to be updated and not removed. + continue + } + if(!activityIds.contains(where: {$0==acitivtyId})){ + checkAndRemoveTokenFor(activityId: acitivtyId) + } + } + } + + func updateToken(id:String,token:String,reason:TokenUpdateReason){ + NSLog(LiveActivityManager.LOG_TAG + "Token Update : " + String(describing: reason)) + if(reason == .ActivityTokenRemoved){ + activityTokens.removeValue(forKey: id) + saveTokensToUserDefaults() + // No need for FCM backend update. So returning. + return + } + + activityTokens[id] = token + saveTokensToUserDefaults() + + uploadToken(id: id, token: token) + } + + func uploadToken(id:String,token:String){ + NSLog(LiveActivityManager.LOG_TAG + "Token Upload:: Id: " + id + " token: " + token) + //TODO: Code for token upload to FCM backend. + + + } + + /** + Reasons for token update + */ + enum TokenUpdateReason { + case ActivityTokenRemoved + case ActivityTokenAdded + case ActivityTokenUpdated + } +} diff --git a/FirebaseMessaging/Sources/LiveActivities/LiveActivityTypeWrapper.swift b/FirebaseMessaging/Sources/LiveActivities/LiveActivityTypeWrapper.swift new file mode 100644 index 00000000000..89eeb880828 --- /dev/null +++ b/FirebaseMessaging/Sources/LiveActivities/LiveActivityTypeWrapper.swift @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation + +/** + Protocol class invalidate and fetch details of Live activity instance fir a specific live activity type. + */ +protocol LiveActivityTypeWrapper { + /** + Invalidate the local live activity records by syncing with Activitykit apis. + */ + func invalidateActivities() + /** + Gets the list of active live activity ids + */ + func getActiveActivityIds() -> [String] + /** + Initializes PTS token + */ + func initPTSToken(ptsTokenId:String?) + /** + Listens for live activity updates + */ + func listenForActivityUpdates() +} diff --git a/FirebaseMessaging/Sources/LiveActivities/LiveActivityTypeWrapperImpl.swift b/FirebaseMessaging/Sources/LiveActivities/LiveActivityTypeWrapperImpl.swift new file mode 100644 index 00000000000..bbdbef1e056 --- /dev/null +++ b/FirebaseMessaging/Sources/LiveActivities/LiveActivityTypeWrapperImpl.swift @@ -0,0 +1,142 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +import ActivityKit + +/** + Wrapper class to hold Live activity type. + + This class is responsible for listening to live activity updates and token changes. + */ +@available(iOS 16.1, *) +class LiveActivityTypeWrapperImpl: LiveActivityTypeWrapper { + + private let tokenManager = LiveActivityTokenManager.getInstance() + private var listeningStatus = [String:Bool]() + + //Helper functions + + func getFormatedToken(token:Data) -> String{ + return token.reduce("") { + $0 + String(format: "%02x", $1) + } + } + + func checkAndAddActivity(activity:Activity){ + if (hasListenerSetFor(activityId: activity.id)){ + //We have already subscribed to activity and token updates for this live activity instance. + return + } + + listeningStatus[activity.id] = true + + Task{ + Task{ + if(activity.pushToken != nil){ + let activityToken = getFormatedToken(token: activity.pushToken!) + checkAndUpdateToken(activityId: activity.id, activityToken: activityToken) + } + for await pushToken in activity.pushTokenUpdates { + let activityToken = getFormatedToken(token: pushToken) + checkAndUpdateToken(activityId: activity.id, activityToken: activityToken) + } + } + Task{ + for await activityState in activity.activityStateUpdates { + if(activityState == ActivityState.ended || activity.activityState==ActivityState.dismissed){ + checkAndRemoveActivityToken(activityId: activity.id) + } + } + } + } + } + + func hasListenerSetFor(activityId:String) -> Bool{ + if(listeningStatus.keys.contains(activityId)){ + return listeningStatus[activityId]! + } + + return false + } + + func checkAndUpdateToken(activityId:String,activityToken:String) { + Task{ + await tokenManager.checkAndUpdateTokenFor(activityId: activityId, activityToken: activityToken) + } + } + + func checkAndRemoveActivityToken(activityId:String){ + Task{ + await tokenManager.checkAndRemoveTokenFor(activityId:activityId) + } + } + + //Protocol Functions + + /** + Requests for Push to start live activity token and listen for its updates. + */ + func initPTSToken(ptsTokenId:String?){ + if #available(iOS 17.2, *) { + Task{ + let ptsToken = Activity.pushToStartToken + if(ptsToken != nil){ + let ptsTokenString = getFormatedToken(token: ptsToken!) + checkAndUpdateToken(activityId: ptsTokenId!, activityToken: ptsTokenString) + } + + for await pushToken in Activity.pushToStartTokenUpdates { + let activityToken = getFormatedToken(token: pushToken) + //PTS token is saved against registration id + checkAndUpdateToken(activityId: ptsTokenId!, activityToken: activityToken) + } + } + } + } + + /** + Listens for live activity updates happening in the app for the current type. + */ + func listenForActivityUpdates(){ + Task{ + for await activity in Activity.activityUpdates { + if(activity.activityState==ActivityState.ended || activity.activityState==ActivityState.dismissed){ + checkAndRemoveActivityToken(activityId: activity.id) + }else if(activity.activityState==ActivityState.active){ + checkAndAddActivity(activity: activity) + } + } + } + } + + func invalidateActivities() { + Task{ + let activities = Activity.activities + + // Checking and adding new activities + for activity in activities { + checkAndAddActivity(activity:activity) + } + } + } + + func getActiveActivityIds() -> [String] { + let activities = Activity.activities + let activityIds = activities.map { $0.id } + return activityIds + } +}