Skip to content

Commit

Permalink
Fixed iOS params issue related to the second init for wrappers (#594)
Browse files Browse the repository at this point in the history
* Fixed params issue related to the second init
* On first init call the app id is null form some wrappers
* Now every time init is called we try to download the params if the `didCallDownloadParams` false

* Fix for OneSignal wrappers in native init
* Wrapper SDKs call init twice, once with a null app id and once with a valid app id
  - On first init: null app id prevents iOS params and initDone will be set true
  - On second init: valid app id will allow iOS params to be pulled down and init is done already
* Log level is now being set to default VERBOSE in NSE
  - This is so any logs get recorded for the device even when coming from the NSE
  - The customer will have control app level for showing OneSignal logs, but NSE will always log out logs
* Unit test written for checking that init called twice (once with null app id and once with valid app id) does not effect iOS params request

* Updated the log when entering the NSE of the SDK
  • Loading branch information
mikechoch authored Jan 14, 2020
1 parent 80af6a8 commit ac76834
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 29 deletions.
Binary file not shown.
62 changes: 38 additions & 24 deletions iOS_SDK/OneSignalSDK/Source/OneSignal.m
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,6 @@ @implementation OneSignal
// Under Capabilities is "Background Modes" > "Remote notifications" enabled.
static BOOL backgroundModesEnabled = false;

// indicates if the GetiOSParams request has completed
static BOOL downloadedParameters = false;
static BOOL didCallDownloadParameters = false;

static BOOL promptBeforeOpeningPushURLs = false;


Expand Down Expand Up @@ -332,6 +328,24 @@ + (void)setMSubscriptionStatus:(NSNumber*)status {
mSubscriptionStatus = [status intValue];
}

/*
Indicates if the iOS params request has started
Set to true when the method is called and set false if the request's failure callback is triggered
*/
static BOOL _didCallDownloadParameters = false;
+ (BOOL)didCallDownloadParameters {
return _didCallDownloadParameters;
}

/*
Indicates if the iOS params request is complete
Set to true when the request's success callback is triggered
*/
static BOOL _downloadedParameters = false;
+ (BOOL)downloadedParameters {
return _downloadedParameters;
}

static OneSignalReceiveReceiptsController* _receiveReceiptsController;
+ (OneSignalReceiveReceiptsController*)receiveReceiptsController {
if (!_receiveReceiptsController)
Expand Down Expand Up @@ -428,7 +442,8 @@ + (void)clearStatics {

_permissionStateChangesObserver = nil;

didCallDownloadParameters = false;
_downloadedParameters = false;
_didCallDownloadParameters = false;

maxApnsWait = APNS_TIMEOUT;
reattemptRegistrationInterval = REGISTRATION_DELAY_SECONDS;
Expand Down Expand Up @@ -520,6 +535,11 @@ + (id)initWithLaunchOptions:(NSDictionary*)launchOptions
if (!success)
return self;

// Wrapper SDK's call init twice and pass null as the appId on the first call
// the app ID is required to download parameters, so do not download params until the appID is provided
if (!_didCallDownloadParameters && appId && appId != (id)[NSNull null])
[self downloadIOSParamsWithAppId:appId];

if (initDone)
return self;
initDone = true;
Expand All @@ -529,11 +549,6 @@ + (id)initWithLaunchOptions:(NSDictionary*)launchOptions
// Outcomes init
_sessionManager = [[OneSignalSessionManager alloc] init:self];
_outcomeEventsController = [[OneSignalOutcomeEventsController alloc] init:self.sessionManager];

// Some wrapper SDK's call init multiple times and pass nil/NSNull as the appId on the first call
// the app ID is required to download parameters, so do not download params until the appID is provided
if (!didCallDownloadParameters && appId != nil && appId != (id)[NSNull null])
[self downloadIOSParamsWithAppId:appId];

if (appId && mShareLocation)
[OneSignalLocation getLocation:false];
Expand Down Expand Up @@ -597,7 +612,6 @@ + (id)initWithLaunchOptions:(NSDictionary*)launchOptions
[self registerUser];
else {
[self.osNotificationSettings getNotificationPermissionState:^(OSPermissionState *state) {

if (state.answeredPrompt) {
[self registerUser];
} else {
Expand Down Expand Up @@ -664,6 +678,8 @@ + (bool)initAppId:(NSString*)appId withSettings:(NSDictionary*)settings {
// Will also run the first time OneSignal is initialized
if (app_id && ![app_id isEqualToString:prevAppId]) {
initDone = false;
_downloadedParameters = false;
_didCallDownloadParameters = false;
let sharedUserDefaults = OneSignalUserDefaults.initShared;

[standardUserDefaults saveStringForKey:NSUD_APP_ID withValue:app_id];
Expand Down Expand Up @@ -762,9 +778,9 @@ + (void)checkIfApplicationImplementsDeprecatedMethods {
});
}

+(void)downloadIOSParamsWithAppId:(NSString *)appId {
+ (void)downloadIOSParamsWithAppId:(NSString *)appId {
[self onesignal_Log:ONE_S_LL_DEBUG message:@"Downloading iOS parameters for this application"];
didCallDownloadParameters = true;
_didCallDownloadParameters = true;

[OneSignalClient.sharedClient executeRequest:[OSRequestGetIosParams withUserId:self.currentSubscriptionState.userId appId:appId] onSuccess:^(NSDictionary *result) {
if (result[IOS_REQUIRES_EMAIL_AUTHENTICATION]) {
Expand All @@ -777,24 +793,22 @@ +(void)downloadIOSParamsWithAppId:(NSString *)appId {
}
}

if (!usesAutoPrompt &&
result[IOS_USES_PROVISIONAL_AUTHORIZATION] &&
result[IOS_USES_PROVISIONAL_AUTHORIZATION] != [NSNull null] &&
[result[IOS_USES_PROVISIONAL_AUTHORIZATION] boolValue]) {

[OneSignalUserDefaults.initStandard saveBoolForKey:USES_PROVISIONAL_AUTHORIZATION withValue:true];
if (!usesAutoPrompt && result[IOS_USES_PROVISIONAL_AUTHORIZATION] != (id)[NSNull null]) {
[OneSignalUserDefaults.initStandard saveBoolForKey:USES_PROVISIONAL_AUTHORIZATION withValue:[result[IOS_USES_PROVISIONAL_AUTHORIZATION] boolValue]];

[self checkProvisionalAuthorizationStatus];
}

if (result[IOS_RECEIVE_RECEIPTS_ENABLE])
[OneSignalUserDefaults.initShared saveBoolForKey:ONESIGNAL_ENABLE_RECEIVE_RECEIPTS withValue:true];
if (result[IOS_RECEIVE_RECEIPTS_ENABLE] != (id)[NSNull null])
[OneSignalUserDefaults.initShared saveBoolForKey:ONESIGNAL_ENABLE_RECEIVE_RECEIPTS withValue:[result[IOS_RECEIVE_RECEIPTS_ENABLE] boolValue]];

[OSOutcomesUtils saveOutcomeParamsForApp:result];
[OneSignalTrackFirebaseAnalytics updateFromDownloadParams:result];

downloadedParameters = true;
} onFailure:nil];
_downloadedParameters = true;
} onFailure:^(NSError *error) {
_didCallDownloadParameters = false;
}];
}

+ (void)setLogLevel:(ONE_S_LOG_LEVEL)nsLogLevel visualLevel:(ONE_S_LOG_LEVEL)visualLogLevel {
Expand Down Expand Up @@ -2290,7 +2304,7 @@ + (void)setEmail:(NSString * _Nonnull)email withEmailAuthHashToken:(NSString * _
and we do not need to delay the request
*/

if (!self.currentSubscriptionState.userId || (downloadedParameters == false && emailAuthToken != nil)) {
if (!self.currentSubscriptionState.userId || (_downloadedParameters == false && emailAuthToken != nil)) {
[self onesignal_Log:ONE_S_LL_VERBOSE message:@"iOS Parameters for this application has not yet been downloaded. Delaying call to setEmail: until the parameters have been downloaded."];
delayedEmailParameters = [OneSignalSetEmailParameters withEmail:email withAuthToken:emailAuthToken withSuccess:successBlock withFailure:failureBlock];
return;
Expand Down
11 changes: 7 additions & 4 deletions iOS_SDK/OneSignalSDK/Source/OneSignalInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@

+ (NSDate *)sessionLaunchTime;

// Indicates if the app provides its own custom Notification customization settings UI
// To enable this, set kOSSettingsKeyProvidesAppNotificationSettings to true in init.
+ (BOOL)providesAppNotificationSettings;

@property (class, readonly) BOOL didCallDownloadParameters;
@property (class, readonly) BOOL downloadedParameters;

@property (class) NSObject<OneSignalNotificationSettings>* osNotificationSettings;
@property (class) OSPermissionState* currentPermissionState;

Expand All @@ -75,10 +82,6 @@
@property (class) OneSignalSessionManager* sessionManager;
@property (class) OneSignalOutcomeEventsController* outcomeEventsController;

// Indicates if the app provides its own custom Notification customization settings UI
// To enable this, set kOSSettingsKeyProvidesAppNotificationSettings to true in init.
+ (BOOL)providesAppNotificationSettings;

@end


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ @implementation OneSignalNotificationServiceExtensionHandler

+ (UNMutableNotificationContent*)didReceiveNotificationExtensionRequest:(UNNotificationRequest*)request
withMutableNotificationContent:(UNMutableNotificationContent*)replacementContent {
// Set default log level of NSE to VERBOSE so we get all logs from NSE logic
[OneSignal setLogLevel:ONE_S_LL_VERBOSE visualLevel:ONE_S_LL_NONE];
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"NSE request received, setting OneSignal log level to VERBOSE!"];

if (!replacementContent)
replacementContent = [request.content mutableCopy];

Expand All @@ -50,6 +54,7 @@ + (UNMutableNotificationContent*)didReceiveNotificationExtensionRequest:(UNNotif
// Track receieved
[OneSignalTrackFirebaseAnalytics trackReceivedEvent:payload];

// Get and check the received notification id
let receivedNotificationId = payload.notificationID;
if (receivedNotificationId && ![receivedNotificationId isEqualToString:@""]) {
// Track confirmed delivery
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ - (void)sendReceiveReceiptWithPlayerId:(nonnull NSString *)playerId
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Receieve receipts disabled"];
return;
}

let request = [OSRequestReceiveReceipts withPlayerId:playerId notificationId:notificationId appId:appId];
[OneSignalClient.sharedClient executeRequest:request onSuccess:^(NSDictionary *result) {
if (success)
Expand Down
26 changes: 26 additions & 0 deletions iOS_SDK/OneSignalSDK/UnitTests/UnitTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#import "OneSignal.h"
#import "OneSignalHelper.h"
#import "OneSignalTracker.h"
#import "OneSignalInternal.h"
#import "NSString+OneSignal.h"
#import "UnitTestCommonMethods.h"
#import "OneSignalSelectorHelpers.h"
Expand Down Expand Up @@ -1820,6 +1821,31 @@ - (void) testDidReceiveNotificationExtensionRequestDontOverrideCateogory {
XCTAssertEqualObjects(content.attachments[0].URL.scheme, @"file");
}

/*
Wrapper SDKs call OneSignal init method twice:
1. App id is null
2. App id should be valid
NOTE: The init method uses flags initDone, didCallDownloadParameters, downloadedParameters and these prevent code from executing more than once in specific cases
initDone BOOL is used to return early in the event of init being called more than once
didCallDownloadParameters BOOL is used to determine whether iOS params have started being pulled down
downloadedParameters BOOL is used to determine whether iOS params have successfully been pulled down
*/
- (void)testiOSParams_withNullAppIdInit_andValidAppIdInit {
// 1. Open app and init with null app id
[OneSignal initWithLaunchOptions:nil appId:nil];
[UnitTestCommonMethods foregroundApp];

// 2. Make sure iOS params did not download, since app id was invalid
XCTAssertFalse(OneSignal.didCallDownloadParameters);
XCTAssertFalse(OneSignal.downloadedParameters);

// 3. Init with valid app id
[OneSignal initWithLaunchOptions:nil appId:@"b2f7f966-d8cc-11e4-bed1-df8f05be55ba"];

// 4. Make sure iOS params have been downloaded, since app_id is valid
XCTAssertTrue(OneSignal.didCallDownloadParameters);
XCTAssertTrue(OneSignal.downloadedParameters);
}

- (void)testAddingSharedKeysIfMissing {
// 1. Init SDK as normal
Expand Down

0 comments on commit ac76834

Please sign in to comment.