Skip to content

Commit 9a95762

Browse files
committed
Initial Live acitivty integration changes
1 parent d9bcd14 commit 9a95762

File tree

5 files changed

+450
-0
lines changed

5 files changed

+450
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2017 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import Foundation
18+
import ActivityKit
19+
import UIKit
20+
21+
/**
22+
Live activity manager class for FCM SDK
23+
24+
Functionalities:
25+
- Keeps track of live activity updates (starting and ending)
26+
- Keeps track of live activity token updates and push to start token updates.
27+
- Uploads the updated tokens to FCM backend when needed.
28+
29+
*/
30+
@available(iOS 16.1, *)
31+
public class LiveActivityManager{
32+
33+
// To keep track of registered Live Acitvities so that they can be invalidated
34+
private static var acitivityWrappers = [LiveActivityTypeWrapper]()
35+
36+
// Class to manage Live Activity tokens
37+
private static let tokenManager:LiveActivityTokenManager = LiveActivityTokenManager.getInstance()
38+
39+
// Log tag for printing logs
40+
public static let LOG_TAG = "LAM# "
41+
42+
public static func liveActivityRegsistration() -> RegistrationRequest{
43+
return RegistrationRequest()
44+
}
45+
46+
static func invalidateActivities(){
47+
Task{
48+
var refreshedIds :[String] = []
49+
for activityWrapper in acitivityWrappers{
50+
activityWrapper.invalidateActivities()
51+
refreshedIds.append(contentsOf:activityWrapper.getActiveActivityIds())
52+
}
53+
54+
await tokenManager.invalidateWith(activityIds: refreshedIds)
55+
56+
NSLog(LOG_TAG + "Invalidated")
57+
}
58+
}
59+
60+
static func setActivityWrappers(wrappers: [LiveActivityTypeWrapper]){
61+
acitivityWrappers = wrappers
62+
}
63+
64+
public static func getLiveAcitivityTokens() async -> [String:String] {
65+
let tokens = await tokenManager.getTokens()
66+
return tokens.mapValues { $0 };
67+
}
68+
69+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2017 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import Foundation
18+
import ActivityKit
19+
20+
/**
21+
Builder class to accept Live activity Registration requests
22+
*/
23+
@available(iOS 16.1, *)
24+
public class RegistrationRequest{
25+
26+
let tokenManager:LiveActivityTokenManager = LiveActivityTokenManager.getInstance()
27+
var acitivityDict = [String:LiveActivityTypeWrapper]()
28+
29+
public func add<T: ActivityAttributes>(type: T.Type) -> RegistrationRequest{
30+
let key = String(describing: type)
31+
acitivityDict[key] = LiveActivityTypeWrapperImpl<T>()
32+
return self
33+
}
34+
35+
/**
36+
Registers the live activities and returns the Push to start id if supported.
37+
38+
PTS id is returned only if iOS 17.2 or above and atleast one Live activity type is registered with FCM
39+
*/
40+
public func register() -> String?{
41+
var wrappers = [LiveActivityTypeWrapper]()
42+
var ptsTokenId:String? = nil
43+
44+
if(!acitivityDict.isEmpty){
45+
ptsTokenId = tokenManager.ptsTokenId
46+
acitivityDict.first?.value.initPTSToken(ptsTokenId: ptsTokenId)
47+
48+
for wrapper in acitivityDict.values{
49+
wrappers.append(wrapper)
50+
wrapper.listenForActivityUpdates()
51+
}
52+
}
53+
54+
LiveActivityManager.setActivityWrappers(wrappers: wrappers)
55+
LiveActivityManager.invalidateActivities()
56+
57+
return ptsTokenId
58+
}
59+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright 2017 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import Foundation
18+
19+
/**
20+
Token manager class which is synchronized.
21+
*/
22+
@available(iOS 16.1, *)
23+
actor LiveActivityTokenManager{
24+
25+
private let TOKENS_DEFAULTS_KEY = "TOKENS_DEFAULTS_KEY"
26+
private var activityTokens : [String:String]
27+
private let userDefaults = UserDefaults(suiteName: "LAM")!
28+
private static let shared = LiveActivityTokenManager()
29+
public let ptsTokenId:String?
30+
31+
/**
32+
Returns the singleton instance of token manager.
33+
*/
34+
public static func getInstance() -> LiveActivityTokenManager{
35+
return shared
36+
}
37+
38+
private init(){
39+
self.activityTokens = userDefaults.dictionary(forKey: TOKENS_DEFAULTS_KEY) as? [String: String] ?? [:]
40+
41+
if #available(iOS 17.2, *) {
42+
//Initializing PTS token id only if iOS 17.2 or above
43+
let PTS_TOKEN_ID_DEFAULTS_KEY = "PTS_TOKEN_ID_DEFAULTS_KEY"
44+
var ptsId = userDefaults.string(forKey: PTS_TOKEN_ID_DEFAULTS_KEY)
45+
if(ptsId == nil || ptsId == ""){
46+
ptsId = UUID().uuidString
47+
userDefaults.set(ptsId, forKey: PTS_TOKEN_ID_DEFAULTS_KEY)
48+
}
49+
ptsTokenId = ptsId
50+
}else{
51+
ptsTokenId = nil
52+
}
53+
}
54+
55+
func getPTSTokenId() -> String?{
56+
return ptsTokenId
57+
}
58+
59+
func getTokens() -> [String:String]{
60+
return activityTokens
61+
}
62+
63+
func saveTokensToUserDefaults(){
64+
userDefaults.set(activityTokens, forKey: TOKENS_DEFAULTS_KEY)
65+
}
66+
67+
func haveTokenFor(activityId:String) -> Bool{
68+
return activityTokens.keys.contains(activityId)
69+
}
70+
71+
func checkAndUpdateTokenFor(activityId:String,activityToken:String){
72+
if(activityId=="" || activityToken == ""){
73+
return
74+
}
75+
76+
if (haveTokenFor(activityId: activityId)){
77+
let oldToken = activityTokens[activityId]
78+
79+
if(oldToken == nil || oldToken == "" || oldToken != activityToken){
80+
//Token needs update
81+
updateToken(id: activityId, token: activityToken, reason: .ActivityTokenUpdated)
82+
}
83+
}else{
84+
//New token
85+
updateToken(id: activityId, token: activityToken, reason: .ActivityTokenAdded)
86+
}
87+
88+
}
89+
90+
func checkAndRemoveTokenFor(activityId:String){
91+
if(activityTokens.keys.contains(activityId)){
92+
// Remove token
93+
let token = activityTokens[activityId]!
94+
updateToken(id: activityId, token: token, reason: .ActivityTokenRemoved)
95+
}
96+
}
97+
98+
func invalidateWith(activityIds: [String]){
99+
//Checking and removing ended acitivities
100+
for acitivtyId in activityTokens.keys{
101+
if(acitivtyId == ptsTokenId){
102+
//PTS tokens are meant to be updated and not removed.
103+
continue
104+
}
105+
if(!activityIds.contains(where: {$0==acitivtyId})){
106+
checkAndRemoveTokenFor(activityId: acitivtyId)
107+
}
108+
}
109+
}
110+
111+
func updateToken(id:String,token:String,reason:TokenUpdateReason){
112+
NSLog(LiveActivityManager.LOG_TAG + "Token Update : " + String(describing: reason))
113+
if(reason == .ActivityTokenRemoved){
114+
activityTokens.removeValue(forKey: id)
115+
saveTokensToUserDefaults()
116+
// No need for FCM backend update. So returning.
117+
return
118+
}
119+
120+
activityTokens[id] = token
121+
saveTokensToUserDefaults()
122+
123+
uploadToken(id: id, token: token)
124+
}
125+
126+
func uploadToken(id:String,token:String){
127+
NSLog(LiveActivityManager.LOG_TAG + "Token Upload:: Id: " + id + " token: " + token)
128+
//TODO: Code for token upload to FCM backend.
129+
130+
131+
}
132+
133+
/**
134+
Reasons for token update
135+
*/
136+
enum TokenUpdateReason {
137+
case ActivityTokenRemoved
138+
case ActivityTokenAdded
139+
case ActivityTokenUpdated
140+
}
141+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2017 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import Foundation
18+
19+
/**
20+
Protocol class invalidate and fetch details of Live activity instance fir a specific live activity type.
21+
*/
22+
protocol LiveActivityTypeWrapper {
23+
/**
24+
Invalidate the local live activity records by syncing with Activitykit apis.
25+
*/
26+
func invalidateActivities()
27+
/**
28+
Gets the list of active live activity ids
29+
*/
30+
func getActiveActivityIds() -> [String]
31+
/**
32+
Initializes PTS token
33+
*/
34+
func initPTSToken(ptsTokenId:String?)
35+
/**
36+
Listens for live activity updates
37+
*/
38+
func listenForActivityUpdates()
39+
}

0 commit comments

Comments
 (0)