Skip to content

Commit 92dc53f

Browse files
authored
Merge pull request #896 from OneSignal/fix/2.x.x-NSUserDefaults-crash-fix
2.X.X NSUserDefaults crash fix
2 parents 983ab2d + 5658b47 commit 92dc53f

File tree

4 files changed

+93
-6
lines changed

4 files changed

+93
-6
lines changed

iOS_SDK/OneSignalSDK/Source/OSMessagingController.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ - (void)deleteOldRedisplayedInAppMessages {
200200
[newRedisplayDictionary removeObjectForKey:messageId];
201201
}
202202

203-
[OneSignalUserDefaults.initStandard saveDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:newRedisplayDictionary];
203+
[OneSignalUserDefaults.initStandard saveCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:newRedisplayDictionary];
204204
}
205205
}
206206

iOS_SDK/OneSignalSDK/Source/OSMigrationController.m

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ of this software and associated documentation files (the "Software"), to deal
3434
#import "OneSignal.h"
3535
#import "OneSignalUserDefaults.h"
3636
#import "OneSignalCommonDefines.h"
37+
#import "OSInAppMessagingDefines.h"
3738
#import "OneSignalHelper.h"
3839

3940
@interface OneSignal ()
@@ -45,6 +46,7 @@ @implementation OSMigrationController
4546

4647
- (void)migrate {
4748
[self migrateToVersion_02_14_00_AndGreater];
49+
[self migrateIAMRedisplayCache];
4850
[self saveCurrentSDKVersion];
4951
}
5052

@@ -78,6 +80,36 @@ - (void)migrateToVersion_02_14_00_AndGreater {
7880
}
7981
}
8082

83+
// Devices could potentially have bad data in the OS_IAM_REDISPLAY_DICTIONARY
84+
// that was saved as a dictionary and not CodeableData. Try to detect if that is the case
85+
// and save it is as CodeableData instead.
86+
- (void)migrateIAMRedisplayCache {
87+
let iamRedisplayCacheFixVersion = 21604;
88+
long sdkVersion = [OneSignalUserDefaults.initShared getSavedIntegerForKey:OSUD_CACHED_SDK_VERSION defaultValue:0];
89+
if (sdkVersion >= iamRedisplayCacheFixVersion)
90+
return;
91+
92+
@try {
93+
__unused NSMutableDictionary *redisplayDict =[[NSMutableDictionary alloc] initWithDictionary:[OneSignalUserDefaults.initStandard
94+
getSavedCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY
95+
defaultValue:[NSMutableDictionary new]]];
96+
} @catch (NSException *exception) {
97+
@try {
98+
// The redisplay IAMs might have been saved as a dictionary.
99+
// Try to read them as a dictionary and then save them as a codeable.
100+
NSMutableDictionary *redisplayDict = [[NSMutableDictionary alloc] initWithDictionary:[OneSignalUserDefaults.initStandard
101+
getSavedDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY
102+
defaultValue:[NSMutableDictionary new]]];
103+
[OneSignalUserDefaults.initStandard saveCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY
104+
withValue:redisplayDict];
105+
} @catch (NSException *exception) {
106+
//Clear the cached redisplay dictionary of bad data
107+
[OneSignalUserDefaults.initStandard saveCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY
108+
withValue:nil];
109+
}
110+
}
111+
}
112+
81113
- (void)saveCurrentSDKVersion {
82114
let currentVersion = [[OneSignal sdk_version_raw] intValue];
83115
[OneSignalUserDefaults.initShared saveIntegerForKey:OSUD_CACHED_SDK_VERSION withValue:currentVersion];

iOS_SDK/OneSignalSDK/UnitTests/InAppMessagingIntegrationTests.m

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ - (void)testIAMWithNoTriggersDisplayOnePerSession_Redisplay {
522522

523523
message.displayStats.lastDisplayTime = firstInterval - delay;
524524
// Save IAM for redisplay
525-
[OneSignalUserDefaults.initStandard saveDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:redisplayedInAppMessages];
525+
[OneSignalUserDefaults.initStandard saveCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:redisplayedInAppMessages];
526526
// Set data for redisplay
527527
[OSMessagingControllerOverrider setMessagesForRedisplay:redisplayedInAppMessages];
528528
// Save IAM for dismiss
@@ -658,11 +658,11 @@ - (void)testIAMRemoveFromCache_Redisplay {
658658
[redisplayedInAppMessages setObject:message2 forKey:message2.messageId];
659659

660660
[OSMessagingControllerOverrider setMessagesForRedisplay:redisplayedInAppMessages];
661-
[standardUserDefaults saveDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:redisplayedInAppMessages];
662-
661+
[standardUserDefaults saveCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:redisplayedInAppMessages];
662+
663663
[self initOneSignalWithInAppMessage:message];
664-
665-
let redisplayMessagesCache = [standardUserDefaults getSavedDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY defaultValue:nil];
664+
665+
NSMutableDictionary *redisplayMessagesCache = [standardUserDefaults getSavedCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY defaultValue:nil];
666666
XCTAssertTrue([redisplayMessagesCache objectForKey:message1.messageId]);
667667
XCTAssertFalse([redisplayMessagesCache objectForKey:message2.messageId]);
668668
}

iOS_SDK/OneSignalSDK/UnitTests/MigrationTests.m

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
#import "UnitTestCommonMethods.h"
3838
#import "OneSignalUserDefaults.h"
3939
#import "OneSignalCommonDefines.h"
40+
#import "OSInAppMessagingDefines.h"
41+
#import "OneSignalUserDefaults.h"
42+
#import "OSInAppMessage.h"
43+
#import "OSInAppMessagingHelpers.h"
4044
#import "CommonAsserts.h"
4145

4246
@interface MigrationTests : XCTestCase
@@ -237,4 +241,55 @@ - (void)testCachedUniqueOutcomeToCachedUniqueOutcomeMigration {
237241
XCTAssertEqual([[OneSignal sdk_version_raw] intValue], sdkVersionAfterMigration);
238242
}
239243

244+
- (void)testIAMCachedEmptyDictionaryToCachedCodeableMigration {
245+
NSDictionary<NSString *, OSInAppMessage *>*emptyDict = [NSMutableDictionary new];
246+
[OneSignalUserDefaults.initStandard saveDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:emptyDict];
247+
248+
[migrationController migrate];
249+
}
250+
251+
- (void)testIAMCachedDictionaryToCachedCodeableMigration {
252+
NSMutableDictionary <NSString *, OSInAppMessage *> *emptyDict = [NSMutableDictionary new];
253+
254+
[OneSignalUserDefaults.initStandard saveDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:emptyDict];
255+
256+
[migrationController migrate];
257+
258+
NSDictionary<NSString *, OSInAppMessage *>*retrievedDict = [OneSignalUserDefaults.initStandard
259+
getSavedCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY defaultValue:nil];
260+
XCTAssertEqualObjects(emptyDict, retrievedDict);
261+
}
262+
263+
- (void)testIAMCachedCodeableMigration {
264+
let limit = 5;
265+
let delay = 60;
266+
let message = [OSInAppMessageTestHelper testMessageWithRedisplayLimit:limit delay:@(delay)];
267+
message.isDisplayedInSession = true;
268+
NSMutableDictionary <NSString *, OSInAppMessage *> *redisplayedInAppMessages = [NSMutableDictionary new];
269+
[redisplayedInAppMessages setObject:message forKey:message.messageId];
270+
271+
[OneSignalUserDefaults.initStandard saveCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:redisplayedInAppMessages];
272+
273+
[migrationController migrate];
274+
275+
NSDictionary<NSString *, OSInAppMessage *>*retrievedDict = [OneSignalUserDefaults.initStandard
276+
getSavedCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY defaultValue:nil];
277+
XCTAssertEqualObjects(redisplayedInAppMessages, retrievedDict);
278+
}
279+
280+
- (void)testIAMNilCacheToNilMigration {
281+
282+
[OneSignalUserDefaults.initStandard saveDictionaryForKey:OS_IAM_REDISPLAY_DICTIONARY withValue:nil];
283+
284+
[migrationController migrate];
285+
286+
NSDictionary<NSString *, OSInAppMessage *>*retrievedDict = [OneSignalUserDefaults.initStandard
287+
getSavedCodeableDataForKey:OS_IAM_REDISPLAY_DICTIONARY defaultValue:nil];
288+
XCTAssertNil(retrievedDict);
289+
}
290+
291+
292+
293+
294+
240295
@end

0 commit comments

Comments
 (0)