Skip to content

Commit 3e7707e

Browse files
committed
iOS 13 Token Fix
- This commit fixes an issue where the SDK was relying on NSData's `description` field to convert the APNS token to a string - This worked fine up until iOS 13 where Apple has changed NSData's `description` to be more like Swift, where it includes the byte length in addition to the data being encoded - Our existing test suite would actually have caught this issue if ran in an iOS 13 environment. However I did add a test to make sure our SDK can handle variable length APNS tokens
1 parent 9271672 commit 3e7707e

File tree

6 files changed

+62
-13
lines changed

6 files changed

+62
-13
lines changed

iOS_SDK/OneSignalSDK/Source/NSString+OneSignal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@
1717
- (NSString *)fileExtensionForMimeType;
1818
- (NSString *)supportedFileExtension;
1919

20+
// returns a lower case hex representation of the data
21+
+ (NSString *)hexStringFromData:(NSData *)data;
22+
2023
@end
2124
#endif

iOS_SDK/OneSignalSDK/Source/NSString+OneSignal.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,15 @@ - (NSString *)fileExtensionForMimeType {
5959
return MIME_MAP[self];
6060
}
6161

62+
+ (NSString *)hexStringFromData:(NSData *)data
63+
{
64+
NSMutableString *parsedDeviceToken = [NSMutableString new];
65+
const char *byteArray = (char *)data.bytes;
66+
67+
for (int i = 0; i < data.length; i++)
68+
[parsedDeviceToken appendFormat:@"%02.2hhx", byteArray[i]];
69+
70+
return [parsedDeviceToken copy];
71+
}
72+
6273
@end

iOS_SDK/OneSignalSDK/Source/OneSignal.m

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,21 +2084,25 @@ + (void)updateNotificationTypes:(int)notificationTypes {
20842084
[self fireIdsAvailableCallback];
20852085
}
20862086

2087-
+ (void)didRegisterForRemoteNotifications:(UIApplication*)app deviceToken:(NSData*)inDeviceToken {
2087+
+ (void)didRegisterForRemoteNotifications:(UIApplication *)app
2088+
deviceToken:(NSData *)inDeviceToken {
20882089
if ([OneSignal shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
20892090
return;
2090-
2091-
let trimmedDeviceToken = [[inDeviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
2092-
let parsedDeviceToken = [[trimmedDeviceToken componentsSeparatedByString:@" "] componentsJoinedByString:@""];
2093-
2094-
2091+
2092+
if (!app_id)
2093+
return;
2094+
2095+
NSString *parsedDeviceToken = [NSString hexStringFromData:inDeviceToken];
2096+
20952097
[OneSignal onesignal_Log:ONE_S_LL_INFO message: [NSString stringWithFormat:@"Device Registered with Apple: %@", parsedDeviceToken]];
2098+
2099+
if (!parsedDeviceToken) {
2100+
[OneSignal onesignal_Log:ONE_S_LL_ERROR message:@"Unable to convert APNS device token to a string"];
2101+
return;
2102+
}
20962103

20972104
waitingForApnsResponse = false;
20982105

2099-
if (!app_id)
2100-
return;
2101-
21022106
[OneSignal updateDeviceToken:parsedDeviceToken onSuccess:^(NSDictionary* results) {
21032107
[OneSignal onesignal_Log:ONE_S_LL_INFO message:[NSString stringWithFormat: @"Device Registered with OneSignal: %@", self.currentSubscriptionState.userId]];
21042108
} onFailure:^(NSError* error) {

iOS_SDK/OneSignalSDK/UnitTests/Shadows/UIApplicationOverrider.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535

3636
+(void)setCurrentUIApplicationState:(UIApplicationState)value;
3737

38+
+ (void)setAPNSTokenLength:(int)tokenLength;
39+
40+
+ (NSString *)mockAPNSToken;
41+
3842
+(UILocalNotification*)lastUILocalNotification;
3943

4044
+(void)runBackgroundThreads;

iOS_SDK/OneSignalSDK/UnitTests/Shadows/UIApplicationOverrider.m

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ @implementation UIApplicationOverrider
5252

5353
static NSURL* lastOpenedUrl;
5454

55+
static int apnsTokenLength = 32;
56+
5557
+ (void)load {
5658
injectToProperClass(@selector(overrideRegisterForRemoteNotifications), @selector(registerForRemoteNotifications), @[], [UIApplicationOverrider class], [UIApplication class]);
5759
injectToProperClass(@selector(override_run), @selector(_run), @[], [UIApplicationOverrider class], [UIApplication class]);
@@ -73,6 +75,7 @@ +(void)reset {
7375
didFailRegistarationErrorCode = 0;
7476
currentUIApplicationState = UIApplicationStateActive;
7577
lastUIUserNotificationSettings = nil;
78+
apnsTokenLength = 32;
7679
}
7780

7881
+(void)setCurrentUIApplicationState:(UIApplicationState)value {
@@ -98,6 +101,19 @@ +(void)setBlockApnsResponse:(BOOL)block {
98101
blockApnsResponse = true;
99102
}
100103

104+
+ (void)setAPNSTokenLength:(int)tokenLength {
105+
apnsTokenLength = tokenLength;
106+
}
107+
108+
+ (NSString *)mockAPNSToken {
109+
NSMutableString *token = [NSMutableString new];
110+
111+
for (int i = 0; i < apnsTokenLength * 2; i++)
112+
[token appendString:@"0"];
113+
114+
return token;
115+
}
116+
101117
// Keeps UIApplicationMain(...) from looping to continue to the next line.
102118
- (void) override_run {
103119
NSLog(@"override_run!!!!!!");
@@ -130,9 +146,9 @@ + (void)runBackgroundThreads {
130146
id app = [UIApplication sharedApplication];
131147
id appDelegate = [[UIApplication sharedApplication] delegate];
132148

133-
char bytes[32];
134-
memset(bytes, 0, 32);
135-
id deviceToken = [NSData dataWithBytes:bytes length:32];
149+
char bytes[apnsTokenLength];
150+
memset(bytes, 0, apnsTokenLength);
151+
id deviceToken = [NSData dataWithBytes:bytes length:apnsTokenLength];
136152
[appDelegate application:app didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
137153
}
138154

iOS_SDK/OneSignalSDK/UnitTests/UnitTests.m

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ - (void)testBasicInitTest {
158158
NSLog(@"CHECKING LAST HTTP REQUEST");
159159

160160
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequest[@"app_id"], @"b2f7f966-d8cc-11e4-bed1-df8f05be55ba");
161-
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequest[@"identifier"], @"0000000000000000000000000000000000000000000000000000000000000000");
161+
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequest[@"identifier"], UIApplicationOverrider.mockAPNSToken);
162162
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequest[@"notification_types"], @15);
163163
NSLog(@"RAN A FEW CONDITIONALS: %@", OneSignalClientOverrider.lastHTTPRequest);
164164
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequest[@"device_model"], @"x86_64");
@@ -2375,4 +2375,15 @@ - (void)testTimeoutOverrideNotificationDisplayType {
23752375
}];
23762376
}
23772377

2378+
- (void)testAllowsIncreasedAPNSTokenSize
2379+
{
2380+
[UIApplicationOverrider setAPNSTokenLength:64];
2381+
2382+
[UnitTestCommonMethods clearStateForAppRestart:self];
2383+
[UnitTestCommonMethods initOneSignal];
2384+
[UnitTestCommonMethods runBackgroundThreads];
2385+
2386+
XCTAssertEqualObjects(OneSignalClientOverrider.lastHTTPRequest[@"identifier"], UIApplicationOverrider.mockAPNSToken);
2387+
}
2388+
23782389
@end

0 commit comments

Comments
 (0)