Skip to content

Commit 85bdd8a

Browse files
committed
Detect for timezone changes and update the user
* Unless users switch via logging in and out, we never update timezone (as it is only sent in the Create User request). * Now, we cache timezone ID and detect for changes on cold starts and update the user when it changes. * We also fix a rare issue that comes from upgrading from an old version of player model to user model. When we have a legacy player ID, we fetch its identity rather than creating a user. Thus, in some rare cases, this old player is already missing a timezone, and the SDK never calls Create User to set a timezone. As a result, this user will be missing timezone. * As a one-time migration, we send up the timezone for all users without considering if timezone is indeed missing or not. Note that this update will be combined in the payload of the session_count update. This update is driven by reading the timezone_id from cache, but before this PR, timezone was never cached, so it will return null.
1 parent a1eea2b commit 85bdd8a

File tree

4 files changed

+35
-2
lines changed

4 files changed

+35
-2
lines changed

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSPropertiesModel.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,14 @@ class OSPropertiesModel: OSModel {
6363
}
6464
}
6565

66-
var timezoneId = TimeZone.current.identifier
66+
var timezoneId: String? = TimeZone.current.identifier {
67+
didSet {
68+
guard timezoneId != oldValue else {
69+
return
70+
}
71+
self.set(property: "timezone_id", newValue: timezoneId)
72+
}
73+
}
6774

6875
var tags: [String: String] = [:]
6976
private let tagsLock = NSRecursiveLock()
@@ -90,13 +97,15 @@ class OSPropertiesModel: OSModel {
9097
super.encode(with: coder)
9198
coder.encode(language, forKey: "language")
9299
coder.encode(tags, forKey: "tags")
100+
coder.encode(timezoneId, forKey: "timezoneId")
93101
// ... and more
94102
}
95103
}
96104

97105
required init?(coder: NSCoder) {
98106
super.init(coder: coder)
99107
language = coder.decodeObject(forKey: "language") as? String
108+
timezoneId = coder.decodeObject(forKey: "timezoneId") as? String
100109
guard let tags = coder.decodeObject(forKey: "tags") as? [String: String] else {
101110
// log error
102111
return
@@ -106,6 +115,10 @@ class OSPropertiesModel: OSModel {
106115
// ... and more
107116
}
108117

118+
func update() {
119+
timezoneId = TimeZone.current.identifier
120+
}
121+
109122
/**
110123
Called to clear the model's data in preparation for hydration via a fetch user call.
111124
*/

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSUserInternalImpl.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ protocol OSUserInternal {
3737
var pushSubscriptionModel: OSSubscriptionModel { get }
3838
var identityModel: OSIdentityModel { get }
3939
var propertiesModel: OSPropertiesModel { get }
40+
func update()
4041
// Aliases
4142
func addAliases(_ aliases: [String: String])
4243
func removeAliases(_ labels: [String])
@@ -72,6 +73,11 @@ class OSUserInternalImpl: NSObject, OSUserInternal {
7273
self.pushSubscriptionModel = pushSubscriptionModel
7374
}
7475

76+
func update() {
77+
self.pushSubscriptionModel.update()
78+
self.propertiesModel.update()
79+
}
80+
7581
// MARK: - Aliases
7682

7783
/**

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OneSignalUserManagerImpl.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
256256
subscriptionModelStoreListener.start()
257257
pushSubscriptionModelStoreListener.start()
258258
if hasCachedUser {
259-
_user?.pushSubscriptionModel.update()
259+
_user?.update()
260260
}
261261
}
262262

@@ -294,6 +294,18 @@ public class OneSignalUserManagerImpl: NSObject, OneSignalUserManager {
294294

295295
// 3. Make the request
296296
userExecutor!.fetchIdentityBySubscription(newUser)
297+
298+
// 4. Send any updates to sync the local state
299+
updateLegacyPlayer(newUser)
300+
}
301+
302+
/**
303+
Migrating a legacy player does not result in a Create User call, but certain local data should be sent manually.
304+
*/
305+
private func updateLegacyPlayer(_ user: OSUserInternal) {
306+
if let timezoneId = user.propertiesModel.timezoneId {
307+
updatePropertiesDeltas(property: .timezone_id, value: timezoneId)
308+
}
297309
}
298310

299311
private func createNewUser(externalId: String?, token: String?) -> OSUserInternal {
@@ -567,6 +579,7 @@ extension OneSignalUserManagerImpl {
567579
/// It enqueues an OSDelta to the Operation Repo.
568580
///
569581
/// - Parameter property:Expected inputs are `.session_time"`, `.session_count"`, and `.purchases"`.
582+
/// May be `.timezone_id` or others if the SDK is sending an update for a legacy player.
570583
func updatePropertiesDeltas(property: OSPropertiesSupportedProperty, value: Any, flush: Bool = false) {
571584
guard !OneSignalConfigManager.shouldAwaitAppIdAndLogMissingPrivacyConsent(forMethod: "updatePropertiesDeltas") else {
572585
return

iOS_SDK/OneSignalSDK/OneSignalUser/Source/Support/OSPropertiesSupportedProperty.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum OSPropertiesSupportedProperty: String {
3636
case language
3737
case location
3838
case tags
39+
case timezone_id
3940
// Created manually by User Manager, not through Models
4041
case session_count
4142
case session_time

0 commit comments

Comments
 (0)