Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
3C14E3A12AFAE461006ED053 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3C14E3A02AFAE461006ED053 /* PrivacyInfo.xcprivacy */; };
3C14E3A42AFAE54C006ED053 /* OneSignalSwiftInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC08AFF2947D4E900C81DA3 /* OneSignalSwiftInterface.swift */; };
3C19C6322E919F0C00D6731E /* OSRequestLiveActivityClicked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C19C6312E919F0C00D6731E /* OSRequestLiveActivityClicked.swift */; };
3C23A21B2FCE0A52001D32E3 /* OneSignalIdentifiersFallbackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C23A21A2FCE0A52001D32E3 /* OneSignalIdentifiersFallbackTests.swift */; };
3C23A21D2FCE0A83001D32E3 /* OSModelStoreRefreshTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C23A21C2FCE0A83001D32E3 /* OSModelStoreRefreshTests.swift */; };
3C23A21F2FCE0AA1001D32E3 /* OSResilientStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C23A21E2FCE0AA1001D32E3 /* OSResilientStorageTests.swift */; };
3C24B0EC2BD09D7A0052E771 /* OneSignalCoreObjCTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C24B0EB2BD09D7A0052E771 /* OneSignalCoreObjCTests.m */; };
3C277D7E2BD76E0000857606 /* OSIdentityModelRepo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C277D7D2BD76E0000857606 /* OSIdentityModelRepo.swift */; };
3C2C7DC8288F3C020020F9AE /* OSSubscriptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C2C7DC7288F3C020020F9AE /* OSSubscriptionModel.swift */; };
Expand Down Expand Up @@ -180,6 +183,7 @@
3CC890352C5BF9A7002CB4CC /* UserConcurrencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CC890342C5BF9A7002CB4CC /* UserConcurrencyTests.swift */; };
3CC9A6342AFA1FDE008F68FD /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3CC9A6332AFA1FDD008F68FD /* PrivacyInfo.xcprivacy */; };
3CC9A6362AFA26E7008F68FD /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3CC9A6352AFA26E7008F68FD /* PrivacyInfo.xcprivacy */; };
3CCC48042FCD619400D77E94 /* OSResilientStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCC48032FCD619400D77E94 /* OSResilientStorage.swift */; };
3CCF44BE299B17290021964D /* OneSignalWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CCF44BC299B17290021964D /* OneSignalWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; };
3CCF44BF299B17290021964D /* OneSignalWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CCF44BD299B17290021964D /* OneSignalWrapper.m */; };
3CDE664C2BFC2A56006DA114 /* OneSignalUserObjcTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CDE664B2BFC2A56006DA114 /* OneSignalUserObjcTests.m */; };
Expand Down Expand Up @@ -1332,6 +1336,9 @@
3C14E39E2AFAE39B006ED053 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3C14E3A02AFAE461006ED053 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3C19C6312E919F0C00D6731E /* OSRequestLiveActivityClicked.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSRequestLiveActivityClicked.swift; sourceTree = "<group>"; };
3C23A21A2FCE0A52001D32E3 /* OneSignalIdentifiersFallbackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneSignalIdentifiersFallbackTests.swift; sourceTree = "<group>"; };
3C23A21C2FCE0A83001D32E3 /* OSModelStoreRefreshTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSModelStoreRefreshTests.swift; sourceTree = "<group>"; };
3C23A21E2FCE0AA1001D32E3 /* OSResilientStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSResilientStorageTests.swift; sourceTree = "<group>"; };
3C24B0EA2BD09D790052E771 /* OneSignalCoreTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OneSignalCoreTests-Bridging-Header.h"; sourceTree = "<group>"; };
3C24B0EB2BD09D7A0052E771 /* OneSignalCoreObjCTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalCoreObjCTests.m; sourceTree = "<group>"; };
3C277D7D2BD76E0000857606 /* OSIdentityModelRepo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSIdentityModelRepo.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1416,6 +1423,7 @@
3CC890342C5BF9A7002CB4CC /* UserConcurrencyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserConcurrencyTests.swift; sourceTree = "<group>"; };
3CC9A6332AFA1FDD008F68FD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3CC9A6352AFA26E7008F68FD /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3CCC48032FCD619400D77E94 /* OSResilientStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSResilientStorage.swift; sourceTree = "<group>"; };
3CCF44BC299B17290021964D /* OneSignalWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalWrapper.h; sourceTree = "<group>"; };
3CCF44BD299B17290021964D /* OneSignalWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalWrapper.m; sourceTree = "<group>"; };
3CDE664A2BFC2A55006DA114 /* OneSignalUserTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OneSignalUserTests-Bridging-Header.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2231,6 +2239,7 @@
3C115163289A259500565C41 /* OneSignalOSCore.h */,
3C115188289ADEA300565C41 /* OSModelStore.swift */,
3C5C6FFB2FCB8DED00102E2C /* OneSignalIdentifiers.swift */,
3CCC48032FCD619400D77E94 /* OSResilientStorage.swift */,
3C115186289ADE7700565C41 /* OSModelStoreListener.swift */,
3C115184289ADE4F00565C41 /* OSModel.swift */,
3CF1A5622C669EA40056B3AA /* OSNewRecordsState.swift */,
Expand Down Expand Up @@ -2513,6 +2522,9 @@
isa = PBXGroup;
children = (
5BC1DE672C90C23E00CA8807 /* OSConsistencyManagerTests.swift */,
3C23A21A2FCE0A52001D32E3 /* OneSignalIdentifiersFallbackTests.swift */,
3C23A21E2FCE0AA1001D32E3 /* OSResilientStorageTests.swift */,
3C23A21C2FCE0A83001D32E3 /* OSModelStoreRefreshTests.swift */,
);
path = OneSignalOSCoreTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -4381,6 +4393,7 @@
5BC1DE5C2C90B7E600CA8807 /* OSConsistencyManager.swift in Sources */,
3C5C6FFC2FCB8DED00102E2C /* OneSignalIdentifiers.swift in Sources */,
3C115189289ADEA300565C41 /* OSModelStore.swift in Sources */,
3CCC48042FCD619400D77E94 /* OSResilientStorage.swift in Sources */,
3C115185289ADE4F00565C41 /* OSModel.swift in Sources */,
3CF1A5632C669EA40056B3AA /* OSNewRecordsState.swift in Sources */,
3C448BA22936B474002F96BC /* OSBackgroundTaskManager.swift in Sources */,
Expand Down Expand Up @@ -4527,6 +4540,9 @@
buildActionMask = 2147483647;
files = (
5B053FC32CAE0843002F30C4 /* OSConsistencyManagerTests.swift in Sources */,
3C23A21F2FCE0AA1001D32E3 /* OSResilientStorageTests.swift in Sources */,
3C23A21D2FCE0A83001D32E3 /* OSModelStoreRefreshTests.swift in Sources */,
3C23A21B2FCE0A52001D32E3 /* OneSignalIdentifiersFallbackTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@
@implementation OneSignalReceiveReceiptsController

- (BOOL)isReceiveReceiptsEnabled {
return [OneSignalUserDefaults.initShared getSavedBoolForKey:OSUD_RECEIVE_RECEIPTS_ENABLED defaultValue:NO];
BOOL enabled = [OneSignalUserDefaults.initShared getSavedBoolForKey:OSUD_RECEIVE_RECEIPTS_ENABLED defaultValue:NO];
if (enabled) {
return YES;
}
// UserDefaults can return NO for two reasons: the flag is genuinely off, or the shared
// UserDefaults file isn't readable right now (NSE running while device is locked under
// NSFileProtectionCompleteUntilFirstUserAuthentication). Fall back to the unencrypted cache.
NSString *cached = [OSResilientStorage stringForKey:OSResilientStorage.keyReceiveReceiptsEnabled];
return [cached isEqualToString:@"1"];
}

- (void)sendReceiveReceiptWithNotificationId:(NSString *)notificationId {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class OSRequestLiveActivityClicked: OneSignalRequest, OSLiveActivityRequest {
return false
}

guard let subscriptionId = OneSignalUserManagerImpl.sharedInstance.pushSubscriptionId else {
guard let subscriptionId = OneSignalIdentifiers.subscriptionId else {
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the OSRequestLiveActivityClicked due to null subscription ID.")
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class OSRequestLiveActivityReceiveReceipts: OneSignalRequest, OSLiveActivityRequ
return false
}

guard let subscriptionId = OneSignalUserManagerImpl.sharedInstance.pushSubscriptionId else {
guard let subscriptionId = OneSignalIdentifiers.subscriptionId else {
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the OSRequestLiveActivityReceiveReceipts due to null subscription ID.")
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class OSRequestRemoveStartToken: OneSignalRequest, OSLiveActivityRequest, OSLive
return false
}

guard let subscriptionId = OneSignalUserManagerImpl.sharedInstance.pushSubscriptionId else {
guard let subscriptionId = OneSignalIdentifiers.subscriptionId else {
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the remove start token request due to null subscription ID.")
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class OSRequestRemoveUpdateToken: OneSignalRequest, OSLiveActivityRequest, OSLiv
return false
}

guard let subscriptionId = OneSignalUserManagerImpl.sharedInstance.pushSubscriptionId else {
guard let subscriptionId = OneSignalIdentifiers.subscriptionId else {
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the remove update token request due to null subscription ID.")
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class OSRequestSetStartToken: OneSignalRequest, OSLiveActivityRequest, OSLiveAct
return false
}

guard let subscriptionId = OneSignalUserManagerImpl.sharedInstance.pushSubscriptionId else {
guard let subscriptionId = OneSignalIdentifiers.subscriptionId else {
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the set start token request due to null subscription ID.")
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class OSRequestSetUpdateToken: OneSignalRequest, OSLiveActivityRequest, OSLiveAc
return false
}

guard let subscriptionId = OneSignalUserManagerImpl.sharedInstance.pushSubscriptionId else {
guard let subscriptionId = OneSignalIdentifiers.subscriptionId else {
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Cannot generate the set update token request due to null subscription ID.")
return false
}
Expand Down
40 changes: 31 additions & 9 deletions iOS_SDK/OneSignalSDK/OneSignalOSCore/Source/OSModelStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,20 @@ open class OSModelStore<TModel: OSModel>: NSObject {
public init(changeSubscription: OSEventProducer<OSModelStoreChangedHandler>, storeKey: String) {
self.storeKey = storeKey
self.changeSubscription = changeSubscription

// read models from cache, if any
if let models = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: self.storeKey, defaultValue: [:]) as? [String: TModel] {
self.models = models
} else {
// log error
self.models = [:]
}
self.models = OSModelStore.loadModelsFromUserDefaults(storeKey: storeKey)
super.init()
subscribeToOwnedModels()
}

/// Reads the archived `[String: TModel]` dict for `storeKey` from shared UserDefaults.
/// Returns an empty dict if the entry is missing or the unarchive fails.
private static func loadModelsFromUserDefaults(storeKey: String) -> [String: TModel] {
return (OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: storeKey, defaultValue: [:]) as? [String: TModel]) ?? [:]
}

// listen for changes to the models
/// Subscribes this store as a change observer on every model currently in `models`.
/// Callers must hold `lock` if invoking after init.
private func subscribeToOwnedModels() {
for model in self.models.values {
model.changeNotifier.subscribe(self)
}
Expand Down Expand Up @@ -93,6 +96,25 @@ open class OSModelStore<TModel: OSModel>: NSObject {
}
}

/// Re-read this store's backing UserDefaults entry and hydrate `models` from disk.
/// No-op when `models` is already non-empty — we never clobber in-memory state.
///
/// Motivation: model stores load their `models` dict once in `init()` from shared UserDefaults.
/// If `init()` runs while protected data is unavailable (iOS app prewarm, NSE before first
/// unlock), that read returns nil and the dict stays empty for the lifetime of the singleton —
/// it is never re-read. After protected data becomes available, callers can call `refresh()`
/// so the store reflects what's actually on disk. Does not fire listener events.
public func refresh() {
lock.withLock {
guard models.isEmpty else { return }
let stored = OSModelStore.loadModelsFromUserDefaults(storeKey: self.storeKey)
guard !stored.isEmpty else { return }
OneSignalLog.onesignalLog(.LL_DEBUG, message: "OSModelStore[\(self.storeKey)] refresh hydrated \(stored.count) model(s) from UserDefaults")
self.models = stored
subscribeToOwnedModels()
}
}

public func add(id: String, model: TModel, hydrating: Bool) {
// TODO: Check if we are adding the same model? Do we replace?
// For example, calling addEmail multiple times with the same email
Expand Down
Loading
Loading