From 070b4335c85ee7c705e6628d68d0bfa383084f32 Mon Sep 17 00:00:00 2001 From: Eldhose Mathokkil Babu Date: Wed, 17 Jul 2024 11:19:08 -0700 Subject: [PATCH 1/6] Adding support for Live activties in Advanced sample app (cherry picked from commit b14986632afeea86f9eecff567f16051edd413b4) --- .../AdvancedSample.xcodeproj/project.pbxproj | 424 +++++++++++++++++- .../AdvancedSample/AdvancedSample/Info.plist | 2 + .../SampleLiveActivity/AppIntent.swift | 25 ++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 + .../SampleLiveActivity/Info.plist | 11 + .../SampleLiveActivity.swift | 91 ++++ .../SampleLiveActivityBundle.swift | 24 + .../SampleLiveActivityLiveActivity.swift | 108 +++++ .../SampleLiveActivityView.swift | 43 ++ .../Apps/Shared/ContentView.swift | 198 ++++---- .../Apps/Shared/LiveActivityView.swift | 150 +++++++ .../SwiftUISample.xcodeproj/project.pbxproj | 62 +++ 15 files changed, 1076 insertions(+), 103 deletions(-) create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/Info.plist create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift create mode 100644 FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift create mode 100644 FirebaseMessaging/Apps/Shared/LiveActivityView.swift 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/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; From d9db7e5a1d45c9e8cd05966feab5da3c66429c44 Mon Sep 17 00:00:00 2001 From: Eldhose Mathokkil Babu Date: Wed, 2 Oct 2024 12:08:18 -0700 Subject: [PATCH 2/6] Updating version --- FirebaseMessaging/Apps/AdvancedSample/Podfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 800e8431e11fc694c99de469de75dcb3ae19c102 Mon Sep 17 00:00:00 2001 From: Eldhose Mathokkil Babu Date: Tue, 12 Nov 2024 13:33:43 -0800 Subject: [PATCH 3/6] Updating Readne with live activity term --- FirebaseMessaging/Apps/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseMessaging/Apps/README.md b/FirebaseMessaging/Apps/README.md index fc2591f76cb..f80410f3200 100644 --- a/FirebaseMessaging/Apps/README.md +++ b/FirebaseMessaging/Apps/README.md @@ -7,7 +7,7 @@ the sample code. The one inside the AdvancedSample folder is a test app based on the test app in the Sample folder. Both Apps share most of the code in the main target. The AdvancedSample app provides advanced app extensions features, such as Notification Service Extension, Shared -Extension, App Clips and a watchOS app. The advanced sample app has more +Extension, App Clips, Live Activites and a watchOS app. The advanced sample app has more targets than the Sample app and requires your own provisioning profiles and certificates for each extension target to be setup so that it can be run on a real device. From e0df3f61a123202e6502adeda0634e23cd63c0ac Mon Sep 17 00:00:00 2001 From: Eldhose Mathokkil Babu Date: Tue, 12 Nov 2024 13:42:32 -0800 Subject: [PATCH 4/6] Formating --- .../SampleLiveActivity/AppIntent.swift | 12 +- .../SampleLiveActivity.swift | 110 ++++---- .../SampleLiveActivityBundle.swift | 10 +- .../SampleLiveActivityLiveActivity.swift | 144 +++++------ .../SampleLiveActivityView.swift | 45 ++-- .../Apps/Shared/ContentView.swift | 202 +++++++-------- .../Apps/Shared/LiveActivityView.swift | 241 +++++++++--------- 7 files changed, 388 insertions(+), 376 deletions(-) diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift index a0135df3007..ba9a861efe3 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/AppIntent.swift @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -import WidgetKit import AppIntents +import WidgetKit struct ConfigurationAppIntent: WidgetConfigurationIntent { - static var title: LocalizedStringResource = "Configuration" - static var description = IntentDescription("This is an example widget.") + 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 + // An example configurable parameter. + @Parameter(title: "Favorite Emoji", default: "😃") + var favoriteEmoji: String } diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift index 5da53bb3d7c..424dac7c8ac 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivity.swift @@ -12,80 +12,90 @@ // See the License for the specific language governing permissions and // limitations under the License. -import WidgetKit import SwiftUI +import WidgetKit struct Provider: AppIntentTimelineProvider { - func placeholder(in context: Context) -> SimpleEntry { - SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) - } + 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] = [] + func snapshot(for configuration: ConfigurationAppIntent, + in context: Context) async -> SimpleEntry { + SimpleEntry(date: Date(), configuration: configuration) + } - // 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) - } + func timeline(for configuration: ConfigurationAppIntent, + in context: Context) async -> Timeline { + var entries: [SimpleEntry] = [] - return Timeline(entries: entries, policy: .atEnd) + // 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 + let date: Date + let configuration: ConfigurationAppIntent } -struct SampleLiveActivityEntryView : View { - var entry: Provider.Entry +struct SampleLiveActivityEntryView: View { + var entry: Provider.Entry - var body: some View { - VStack { - Text("Time:") - Text(entry.date, style: .time) + var body: some View { + VStack { + Text("Time:") + Text(entry.date, style: .time) - Text("Favorite Emoji:") - Text(entry.configuration.favoriteEmoji) - } + Text("Favorite Emoji:") + Text(entry.configuration.favoriteEmoji) } + } } struct SampleLiveActivity: Widget { - let kind: String = "SampleLiveActivity" + 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) - } + 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 - } +private extension ConfigurationAppIntent { + static var smiley: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "😀" + return intent + } + + static var starEyes: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "🤩" + return intent + } } #Preview(as: .systemSmall) { - SampleLiveActivity() + SampleLiveActivity() } timeline: { - SimpleEntry(date: .now, configuration: .smiley) - SimpleEntry(date: .now, configuration: .starEyes) + 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 index 6edb990aac9..06cd5847cee 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityBundle.swift @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import WidgetKit import SwiftUI +import WidgetKit @main struct SampleLiveActivityBundle: WidgetBundle { - var body: some Widget { - SampleLiveActivity() - SampleLiveActivityLiveActivity() - } + var body: some Widget { + SampleLiveActivity() + SampleLiveActivityLiveActivity() + } } diff --git a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift index 31c8b2591b8..6c84ad58f7e 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityLiveActivity.swift @@ -13,96 +13,96 @@ // limitations under the License. import ActivityKit -import WidgetKit import SwiftUI +import WidgetKit 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!" - } - } + 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 + 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) + 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) + } 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) - } +private extension SampleLiveActivityAttributes { + 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) - } +private extension SampleLiveActivityAttributes.ContentState { + static var stateStarted: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status: LVStatus.started) + } + + static var stateInProgress: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status: LVStatus.inProgress) + } + + static var stateCompleted: SampleLiveActivityAttributes.ContentState { + SampleLiveActivityAttributes.ContentState(status: LVStatus.completed) + } } #Preview("Notification", as: .content, using: SampleLiveActivityAttributes.preview) { - SampleLiveActivityLiveActivity() + SampleLiveActivityLiveActivity() } contentStates: { - SampleLiveActivityAttributes.ContentState.stateStarted - SampleLiveActivityAttributes.ContentState.stateInProgress - SampleLiveActivityAttributes.ContentState.stateCompleted + 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 index fbfa010dc70..dc2728b9f3d 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift +++ b/FirebaseMessaging/Apps/AdvancedSample/SampleLiveActivity/SampleLiveActivityView.swift @@ -16,28 +16,27 @@ 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)) + let context: ActivityViewContext + + 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 f6430eaa257..e83beac7e87 100644 --- a/FirebaseMessaging/Apps/Shared/ContentView.swift +++ b/FirebaseMessaging/Apps/Shared/ContentView.swift @@ -24,110 +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) - } - 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) + 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) } - .navigationBarTitle("Firebase Messaging") - }.buttonStyle(IdentityButtonStyle()) + } + } + }.font(.system(size: 14)) + Text("\(log)") + .lineLimit(10) + .multilineTextAlignment(.leading) } + .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 index 68784f910e5..e91bd4fd08f 100644 --- a/FirebaseMessaging/Apps/Shared/LiveActivityView.swift +++ b/FirebaseMessaging/Apps/Shared/LiveActivityView.swift @@ -12,139 +12,142 @@ // See the License for the specific language governing permissions and // limitations under the License. -import SwiftUI import ActivityKit -import SampleLiveActivityExtension import FirebaseMessaging +import SampleLiveActivityExtension +import SwiftUI 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() + @State var activityTokenDict = [String: String]() + + var body: some View { + VStack { + Button("Refresh List") { + Task { + 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!" - } - } + }.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() } - - func getFormatedToken(token:Data) -> String{ - return token.reduce("") { - $0 + String(format: "%02x", $1) + } + + 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!" + } + } } - - 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 getFormatedToken(token: Data) -> String { + return token.reduce("") { + $0 + String(format: "%02x", $1) } - - func cancelAllRunningActivities() { - Task{ - for activity in Activity.activities { - let initialContentState = SampleLiveActivityAttributes.ContentState(status: .started) - - await activity.end( - ActivityContent(state: initialContentState, staleDate: Date()), - dismissalPolicy: .immediate - ) - } - + } + + 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() + LiveActivityView() } From e231f7062b8db8e687a671df98a6f88c4fc236a7 Mon Sep 17 00:00:00 2001 From: Eldhose Mathokkil Babu Date: Wed, 13 Nov 2024 17:08:22 -0800 Subject: [PATCH 5/6] Adding conditional compilation for Live activity (Enabling only for Advanced test app) --- .../AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj | 2 ++ FirebaseMessaging/Apps/Shared/ContentView.swift | 2 ++ 2 files changed, 4 insertions(+) diff --git a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj index 7b37ef02bec..3487b7fbbd5 100644 --- a/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj +++ b/FirebaseMessaging/Apps/AdvancedSample/AdvancedSample.xcodeproj/project.pbxproj @@ -1409,6 +1409,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D LIVE_ACTIVITY_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Firebase iOS App Extensions Dev"; @@ -1435,6 +1436,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D LIVE_ACTIVITY_ENABLED"; PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.extensions.dev; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Firebase iOS App Extensions Dev"; diff --git a/FirebaseMessaging/Apps/Shared/ContentView.swift b/FirebaseMessaging/Apps/Shared/ContentView.swift index e83beac7e87..e8763e49a60 100644 --- a/FirebaseMessaging/Apps/Shared/ContentView.swift +++ b/FirebaseMessaging/Apps/Shared/ContentView.swift @@ -58,10 +58,12 @@ struct ContentView: View { Text("Topic") .fontWeight(.semibold) } +#if LIVE_ACTIVITY_ENABLED NavigationLink(destination: LiveActivityView()) { Text("Live Activity") .fontWeight(.semibold) } +#endif // MARK: Action buttons From 401f5c1531dd5b857b91e0ca891486dc4df17f55 Mon Sep 17 00:00:00 2001 From: Eldhose Mathokkil Babu Date: Wed, 13 Nov 2024 17:09:11 -0800 Subject: [PATCH 6/6] Formating --- FirebaseMessaging/Apps/Shared/ContentView.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/FirebaseMessaging/Apps/Shared/ContentView.swift b/FirebaseMessaging/Apps/Shared/ContentView.swift index e8763e49a60..37e9cb867f3 100644 --- a/FirebaseMessaging/Apps/Shared/ContentView.swift +++ b/FirebaseMessaging/Apps/Shared/ContentView.swift @@ -58,12 +58,12 @@ struct ContentView: View { Text("Topic") .fontWeight(.semibold) } -#if LIVE_ACTIVITY_ENABLED - NavigationLink(destination: LiveActivityView()) { - Text("Live Activity") - .fontWeight(.semibold) - } -#endif + #if LIVE_ACTIVITY_ENABLED + NavigationLink(destination: LiveActivityView()) { + Text("Live Activity") + .fontWeight(.semibold) + } + #endif // MARK: Action buttons