Skip to content

Commit ea6c30c

Browse files
committed
Recreate a push subscription when we detect it is removed
* On a new session, we fetch the user. If we detect our push subscription missing from the user (indicating the push subscription may be deleted), we send a create subscription request for the device's push sub.
1 parent 2fe55b3 commit ea6c30c

File tree

4 files changed

+74
-33
lines changed

4 files changed

+74
-33
lines changed

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSSubscriptionModel.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,26 @@ class OSSubscriptionModel: OSModel {
349349
}
350350
}
351351
}
352+
353+
// Using snake_case so we can use this in request bodies
354+
public func jsonRepresentation() -> [String: Any] {
355+
var json: [String: Any] = [:]
356+
json["id"] = self.subscriptionId
357+
json["type"] = self.type.rawValue
358+
json["token"] = self.address
359+
json["enabled"] = self.enabled
360+
json["test_type"] = self.testType
361+
json["device_os"] = self.deviceOs
362+
json["sdk"] = self.sdk
363+
json["device_model"] = self.deviceModel
364+
json["app_version"] = self.appVersion
365+
json["net_type"] = self.netType
366+
// notificationTypes defaults to -1 instead of nil, don't send if it's -1
367+
if self.notificationTypes != -1 {
368+
json["notification_types"] = self.notificationTypes
369+
}
370+
return json
371+
}
352372
}
353373

354374
// Push Subscription related

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSSubscriptionOperationExecutor.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
201201
processRequestQueue()
202202
}
203203

204+
// Bypasses the operation repo to create a push subscription request
205+
func createPushSubscription(subscriptionModel: OSSubscriptionModel, identityModel: OSIdentityModel) {
206+
let request = OSRequestCreateSubscription(subscriptionModel: subscriptionModel, identityModel: identityModel)
207+
addRequestQueue.append(request)
208+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
209+
}
210+
204211
func processRequestQueue() {
205212
let requestQueue: [OneSignalRequest] = addRequestQueue + removeRequestQueue + updateRequestQueue
206213

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSUserRequests.swift

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,8 @@ class OSUserExecutor {
504504
}
505505
}
506506

507-
static func fetchUser(aliasLabel: String, aliasId: String, identityModel: OSIdentityModel) {
508-
let request = OSRequestFetchUser(identityModel: identityModel, aliasLabel: aliasLabel, aliasId: aliasId)
507+
static func fetchUser(aliasLabel: String, aliasId: String, identityModel: OSIdentityModel, onNewSession: Bool = false) {
508+
let request = OSRequestFetchUser(identityModel: identityModel, aliasLabel: aliasLabel, aliasId: aliasId, onNewSession: onNewSession)
509509

510510
appendToQueue(request)
511511

@@ -528,6 +528,28 @@ class OSUserExecutor {
528528
// Clear local data in preparation for hydration
529529
OneSignalUserManagerImpl.sharedInstance.clearUserData()
530530
parseFetchUserResponse(response: response, identityModel: request.identityModel, originalPushToken: OneSignalUserManagerImpl.sharedInstance.token)
531+
532+
// If this is a on-new-session's fetch user call, check that the subscription still exists
533+
if request.onNewSession,
534+
OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel),
535+
let subId = OneSignalUserManagerImpl.sharedInstance.user.pushSubscriptionModel.subscriptionId,
536+
let subscriptionObjects = parseSubscriptionObjectResponse(response)
537+
{
538+
var subscriptionExists = false
539+
for subModel in subscriptionObjects {
540+
if subModel["id"] as? String == subId {
541+
subscriptionExists = true
542+
break
543+
}
544+
}
545+
546+
if !subscriptionExists {
547+
// This subscription probably has been deleted
548+
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSUserExecutor.executeFetchUserRequest found this device's push subscription gone, now send the push subscription to server.")
549+
OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil
550+
OneSignalUserManagerImpl.sharedInstance.createPushSubscriptionRequest()
551+
}
552+
}
531553
}
532554
executePendingRequests()
533555
} onFailure: { error in
@@ -594,23 +616,7 @@ class OSRequestCreateUser: OneSignalRequest, OSUserRequest {
594616
// When reading from the cache, update the push subscription model
595617
func updatePushSubscriptionModel(_ pushSubscriptionModel: OSSubscriptionModel) {
596618
self.pushSubscriptionModel = pushSubscriptionModel
597-
// Push Subscription Object
598-
var pushSubscriptionObject: [String: Any] = [:]
599-
pushSubscriptionObject["id"] = pushSubscriptionModel.subscriptionId
600-
pushSubscriptionObject["type"] = pushSubscriptionModel.type.rawValue
601-
pushSubscriptionObject["token"] = pushSubscriptionModel.address
602-
pushSubscriptionObject["enabled"] = pushSubscriptionModel.enabled
603-
pushSubscriptionObject["test_type"] = pushSubscriptionModel.testType
604-
pushSubscriptionObject["device_os"] = pushSubscriptionModel.deviceOs
605-
pushSubscriptionObject["sdk"] = pushSubscriptionModel.sdk
606-
pushSubscriptionObject["device_model"] = pushSubscriptionModel.deviceModel
607-
pushSubscriptionObject["app_version"] = pushSubscriptionModel.appVersion
608-
pushSubscriptionObject["net_type"] = pushSubscriptionModel.netType
609-
// notificationTypes defaults to -1 instead of nil, don't send if it's -1
610-
if pushSubscriptionModel.notificationTypes != -1 {
611-
pushSubscriptionObject["notification_types"] = pushSubscriptionModel.notificationTypes
612-
}
613-
self.parameters?["subscriptions"] = [pushSubscriptionObject]
619+
self.parameters?["subscriptions"] = [pushSubscriptionModel.jsonRepresentation()]
614620
}
615621

616622
init(identityModel: OSIdentityModel, propertiesModel: OSPropertiesModel, pushSubscriptionModel: OSSubscriptionModel, originalPushToken: String?) {
@@ -836,7 +842,8 @@ class OSRequestFetchUser: OneSignalRequest, OSUserRequest {
836842
let identityModel: OSIdentityModel
837843
let aliasLabel: String
838844
let aliasId: String
839-
845+
let onNewSession: Bool
846+
840847
func prepareForExecution() -> Bool {
841848
guard let appId = OneSignalConfigManager.getAppId() else {
842849
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the fetch user request due to null app ID.")
@@ -847,10 +854,11 @@ class OSRequestFetchUser: OneSignalRequest, OSUserRequest {
847854
return true
848855
}
849856

850-
init(identityModel: OSIdentityModel, aliasLabel: String, aliasId: String) {
857+
init(identityModel: OSIdentityModel, aliasLabel: String, aliasId: String, onNewSession: Bool) {
851858
self.identityModel = identityModel
852859
self.aliasLabel = aliasLabel
853860
self.aliasId = aliasId
861+
self.onNewSession = onNewSession
854862
self.stringDescription = "OSRequestFetchUser with aliasLabel: \(aliasLabel) aliasId: \(aliasId)"
855863
super.init()
856864
self.method = GET
@@ -861,6 +869,7 @@ class OSRequestFetchUser: OneSignalRequest, OSUserRequest {
861869
coder.encode(aliasLabel, forKey: "aliasLabel")
862870
coder.encode(aliasId, forKey: "aliasId")
863871
coder.encode(identityModel, forKey: "identityModel")
872+
coder.encode(onNewSession, forKey: "onNewSession")
864873
coder.encode(method.rawValue, forKey: "method") // Encodes as String
865874
coder.encode(timestamp, forKey: "timestamp")
866875
}
@@ -879,6 +888,7 @@ class OSRequestFetchUser: OneSignalRequest, OSUserRequest {
879888
self.identityModel = identityModel
880889
self.aliasLabel = aliasLabel
881890
self.aliasId = aliasId
891+
self.onNewSession = coder.decodeBool(forKey: "onNewSession")
882892
self.stringDescription = "OSRequestFetchUser with aliasLabel: \(aliasLabel) aliasId: \(aliasId)"
883893
super.init()
884894
self.method = HTTPMethod(rawValue: rawMethod)
@@ -1107,8 +1117,9 @@ class OSRequestUpdateProperties: OneSignalRequest, OSUserRequest {
11071117
}
11081118

11091119
/**
1110-
Current uses of this request are for adding Email and SMS subscriptions. Push subscriptions won't be created using
1111-
this request because they will be created with ``OSRequestCreateUser``.
1120+
Primary uses of this request are for adding Email and SMS subscriptions. Push subscriptions typically won't be created using
1121+
this request because they will be created with ``OSRequestCreateUser``. However, if we detect that this device's
1122+
push subscription is ever deleted, we will make a request to create it again.
11121123
*/
11131124
class OSRequestCreateSubscription: OneSignalRequest, OSUserRequest {
11141125
var sentToClient = false
@@ -1137,15 +1148,7 @@ class OSRequestCreateSubscription: OneSignalRequest, OSUserRequest {
11371148
self.identityModel = identityModel
11381149
self.stringDescription = "OSRequestCreateSubscription with subscriptionModel: \(subscriptionModel.address ?? "nil")"
11391150
super.init()
1140-
1141-
var subscriptionParams: [String: Any] = [:]
1142-
subscriptionParams["type"] = subscriptionModel.type.rawValue
1143-
subscriptionParams["token"] = subscriptionModel.address
1144-
// 1/5/2023: For email and SMS, either send `enabled` AND `notification_types` or don't send either
1145-
// TODO: ^ Backend changes may require us to come back and change this request's payload.
1146-
// TODO: Since this is not used for push, don't send either of those. Revisit if we ever create push subscriptions with this request.
1147-
1148-
self.parameters = ["subscription": subscriptionParams]
1151+
self.parameters = ["subscription": subscriptionModel.jsonRepresentation()]
11491152
self.method = POST
11501153
_ = prepareForExecution() // sets the path property
11511154
}

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OneSignalUserManagerImpl.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,17 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
445445
changeNotifier: OSEventProducer())
446446
}
447447

448+
func createPushSubscriptionRequest() {
449+
// subscriptionExecutor should exist as this should be called after `start()` has been called
450+
if let subscriptionExecutor = self.subscriptionExecutor,
451+
let subscriptionModel = pushSubscriptionModel
452+
{
453+
subscriptionExecutor.createPushSubscription(subscriptionModel: subscriptionModel, identityModel: user.identityModel)
454+
} else {
455+
OneSignalLog.onesignalLog(.LL_ERROR, message: "OneSignalUserManagerImpl.createPushSubscriptionRequest cannot be executed due to missing subscriptionExecutor.")
456+
}
457+
}
458+
448459
@objc
449460
public func getTags() -> [String: String]? {
450461
guard let user = _user else {
@@ -521,7 +532,7 @@ extension OneSignalUserManagerImpl {
521532
// Fetch the user's data if there is a onesignal_id
522533
// TODO: What if onesignal_id is missing, because we may init a user from cache but it may be missing onesignal_id. Is this ok.
523534
if let onesignalId = onesignalId {
524-
OSUserExecutor.fetchUser(aliasLabel: OS_ONESIGNAL_ID, aliasId: onesignalId, identityModel: user.identityModel)
535+
OSUserExecutor.fetchUser(aliasLabel: OS_ONESIGNAL_ID, aliasId: onesignalId, identityModel: user.identityModel, onNewSession: true)
525536
}
526537
}
527538

0 commit comments

Comments
 (0)