diff --git a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
index 45b0570fc..101ad0792 100644
--- a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
+++ b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
@@ -41,9 +41,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
[FIRApp configure];
NSLog(@"Bundle URL: %@", [[NSBundle mainBundle] bundleURL]);
- NSLog(@"[[NSUUID alloc] initWithUUIDString:nil]: %@", [[NSUUID alloc] initWithUUIDString:nil]);
- [OneSignal setLogLevel:ONE_S_LL_VERBOSE visualLevel:ONE_S_LL_WARN];
+ [OneSignal setLogLevel:ONE_S_LL_VERBOSE visualLevel:ONE_S_LL_ERROR];
OneSignal.inFocusDisplayType = OSNotificationDisplayTypeInAppAlert;
diff --git a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Base.lproj/Main.storyboard b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Base.lproj/Main.storyboard
index a7c9f0421..f8652c39b 100644
--- a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Base.lproj/Main.storyboard
+++ b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Base.lproj/Main.storyboard
@@ -6,6 +6,7 @@
+
@@ -71,24 +72,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Info.plist b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Info.plist
index 7e2d08241..aa7551392 100644
--- a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Info.plist
+++ b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/Info.plist
@@ -2,6 +2,8 @@
+ OneSignal_require_privacy_consent
+ CFBundleDevelopmentRegionenCFBundleExecutable
diff --git a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/ViewController.m b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/ViewController.m
index 684ebd334..7744fc6ef 100644
--- a/iOS_SDK/OneSignalDevApp/OneSignalDevApp/ViewController.m
+++ b/iOS_SDK/OneSignalDevApp/OneSignalDevApp/ViewController.m
@@ -35,6 +35,7 @@
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+@property (weak, nonatomic) IBOutlet UISegmentedControl *consentSegmentedControl;
@end
@@ -45,6 +46,8 @@ - (void)viewDidLoad {
// Do any additional setup after loading the view, typically from a nib.
self.activityIndicatorView.hidden = true;
+
+ self.consentSegmentedControl.selectedSegmentIndex = (NSInteger)![OneSignal requiresUserPrivacyConsent];
}
- (void)changeAnimationState:(BOOL)animating {
@@ -121,5 +124,10 @@ - (void)didReceiveMemoryWarning {
// Dispose of any resources that can be recreated.
}
+- (IBAction)consentSegmentedControlValueChanged:(UISegmentedControl *)sender {
+ NSLog(@"View controller consent granted: %i", (int)sender.selectedSegmentIndex);
+ [OneSignal consentGranted:(bool)sender.selectedSegmentIndex];
+}
+
@end
diff --git a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
index e12241530..f99d5bf74 100644
--- a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
+++ b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
@@ -153,6 +153,9 @@
CAABF34B205B15780042F8E5 /* OneSignalExtensionBadgeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CAABF34A205B15780042F8E5 /* OneSignalExtensionBadgeHandler.m */; };
CAABF34C205B157B0042F8E5 /* OneSignalExtensionBadgeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CAABF34A205B15780042F8E5 /* OneSignalExtensionBadgeHandler.m */; };
CAABF34D205B157B0042F8E5 /* OneSignalExtensionBadgeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CAABF34A205B15780042F8E5 /* OneSignalExtensionBadgeHandler.m */; };
+ CAB4112920852E48005A70D1 /* DelayedInitializationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB4112820852E48005A70D1 /* DelayedInitializationParameters.m */; };
+ CAB4112A20852E4C005A70D1 /* DelayedInitializationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB4112820852E48005A70D1 /* DelayedInitializationParameters.m */; };
+ CAB4112B20852E4C005A70D1 /* DelayedInitializationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB4112820852E48005A70D1 /* DelayedInitializationParameters.m */; };
CAB411AE208931EE005A70D1 /* DummyNotificationCenterDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CAB411AD208931EE005A70D1 /* DummyNotificationCenterDelegate.m */; };
CAEA1C66202BB3C600FBFE9E /* OSEmailSubscription.h in Headers */ = {isa = PBXBuildFile; fileRef = CA810FCF202BA97300A60FED /* OSEmailSubscription.h */; };
/* End PBXBuildFile section */
@@ -293,6 +296,8 @@
CAA4ED0020646762005BD59B /* BadgeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BadgeTests.m; sourceTree = ""; };
CAABF349205B15780042F8E5 /* OneSignalExtensionBadgeHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalExtensionBadgeHandler.h; sourceTree = ""; };
CAABF34A205B15780042F8E5 /* OneSignalExtensionBadgeHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalExtensionBadgeHandler.m; sourceTree = ""; };
+ CAB4112720852E48005A70D1 /* DelayedInitializationParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DelayedInitializationParameters.h; sourceTree = ""; };
+ CAB4112820852E48005A70D1 /* DelayedInitializationParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DelayedInitializationParameters.m; sourceTree = ""; };
CAB411AC208931EE005A70D1 /* DummyNotificationCenterDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DummyNotificationCenterDelegate.h; sourceTree = ""; };
CAB411AD208931EE005A70D1 /* DummyNotificationCenterDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DummyNotificationCenterDelegate.m; sourceTree = ""; };
/* End PBXFileReference section */
@@ -448,6 +453,8 @@
91C7725D1E7CCE1000D612D0 /* OneSignalInternal.h */,
912411F01E73342200E41FD7 /* OneSignal.h */,
912411F11E73342200E41FD7 /* OneSignal.m */,
+ CAB4112720852E48005A70D1 /* DelayedInitializationParameters.h */,
+ CAB4112820852E48005A70D1 /* DelayedInitializationParameters.m */,
CA70E3332023D51000019273 /* OneSignalSetEmailParameters.h */,
CA70E3342023D51000019273 /* OneSignalSetEmailParameters.m */,
912411F41E73342200E41FD7 /* OneSignalHelper.h */,
@@ -736,6 +743,7 @@
9124123A1E73342200E41FD7 /* OneSignalWebView.m in Sources */,
9124123E1E73342200E41FD7 /* UIApplicationDelegate+OneSignal.m in Sources */,
912412261E73342200E41FD7 /* OneSignalMobileProvision.m in Sources */,
+ CAB4112920852E48005A70D1 /* DelayedInitializationParameters.m in Sources */,
454F94F21FAD218000D74CCF /* OneSignalNotificationServiceExtensionHandler.m in Sources */,
912412321E73342200E41FD7 /* OneSignalTracker.m in Sources */,
CA70E3352023D51000019273 /* OneSignalSetEmailParameters.m in Sources */,
@@ -774,6 +782,7 @@
0338566B1FBBD2270002F7C1 /* OSNotificationPayload.m in Sources */,
912412431E73342200E41FD7 /* UNUserNotificationCenter+OneSignal.m in Sources */,
9124123B1E73342200E41FD7 /* OneSignalWebView.m in Sources */,
+ CAB4112A20852E4C005A70D1 /* DelayedInitializationParameters.m in Sources */,
9124123F1E73342200E41FD7 /* UIApplicationDelegate+OneSignal.m in Sources */,
0338566C1FBBDB150002F7C1 /* OneSignalNotificationServiceExtensionHandler.m in Sources */,
CA70E3362023D51300019273 /* OneSignalSetEmailParameters.m in Sources */,
@@ -814,6 +823,7 @@
912412491E73369800E41FD7 /* OneSignalHelper.m in Sources */,
4529DEE41FA82C6200CEAB1D /* NSURLSessionOverrider.m in Sources */,
4529DED21FA81EA800CEAB1D /* NSObjectOverrider.m in Sources */,
+ CAB4112B20852E4C005A70D1 /* DelayedInitializationParameters.m in Sources */,
912412341E73342200E41FD7 /* OneSignalTracker.m in Sources */,
912412101E73342200E41FD7 /* OneSignal.m in Sources */,
9124122C1E73342200E41FD7 /* OneSignalReachability.m in Sources */,
diff --git a/iOS_SDK/OneSignalSDK/Source/DelayedInitializationParameters.h b/iOS_SDK/OneSignalSDK/Source/DelayedInitializationParameters.h
new file mode 100644
index 000000000..f1a28fb28
--- /dev/null
+++ b/iOS_SDK/OneSignalSDK/Source/DelayedInitializationParameters.h
@@ -0,0 +1,41 @@
+/**
+ * Modified MIT License
+ *
+ * Copyright 2017 OneSignal
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 2. All copies of substantial portions of the Software may only be used in connection
+ * with services provided by OneSignal.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#import
+#import "OneSignal.h"
+
+@interface DelayedInitializationParameters : NSObject
+
+-(instancetype _Nonnull)initWithLaunchOptions:(NSDictionary * _Nullable)launchOptions withAppId:(NSString * _Nullable)appId withHandleNotificationReceivedBlock:(OSHandleNotificationReceivedBlock _Nullable)received withHandleNotificationActionBlock:(OSHandleNotificationActionBlock _Nullable)action withSettings:(NSDictionary * _Nullable)settings;
+
+@property (strong, nonatomic, nullable) NSDictionary *launchOptions;
+@property (strong, nonatomic, nullable) NSString *appId;
+@property (strong, nonatomic, nullable) NSDictionary *settings;
+@property (nonatomic, nullable) OSHandleNotificationReceivedBlock receivedBlock;
+@property (nonatomic, nullable) OSHandleNotificationActionBlock actionBlock;
+
+@end
diff --git a/iOS_SDK/OneSignalSDK/Source/DelayedInitializationParameters.m b/iOS_SDK/OneSignalSDK/Source/DelayedInitializationParameters.m
new file mode 100644
index 000000000..7b117e8ef
--- /dev/null
+++ b/iOS_SDK/OneSignalSDK/Source/DelayedInitializationParameters.m
@@ -0,0 +1,41 @@
+/**
+ * Modified MIT License
+ *
+ * Copyright 2017 OneSignal
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 2. All copies of substantial portions of the Software may only be used in connection
+ * with services provided by OneSignal.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#import "DelayedInitializationParameters.h"
+
+@implementation DelayedInitializationParameters
+
+-(instancetype)initWithLaunchOptions:(NSDictionary *)launchOptions withAppId:(NSString *)appId withHandleNotificationReceivedBlock:(OSHandleNotificationReceivedBlock)received withHandleNotificationActionBlock:(OSHandleNotificationActionBlock)action withSettings:(NSDictionary *)settings {
+ self.launchOptions = launchOptions;
+ self.appId = appId;
+ self.receivedBlock = received;
+ self.actionBlock = action;
+ self.settings = settings;
+ return self;
+}
+
+@end
diff --git a/iOS_SDK/OneSignalSDK/Source/OneSignal.h b/iOS_SDK/OneSignalSDK/Source/OneSignal.h
index 4ce7aac90..c750025a0 100755
--- a/iOS_SDK/OneSignalSDK/Source/OneSignal.h
+++ b/iOS_SDK/OneSignalSDK/Source/OneSignal.h
@@ -340,6 +340,11 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) {
+ (id)initWithLaunchOptions:(NSDictionary*)launchOptions appId:(NSString*)appId handleNotificationAction:(OSHandleNotificationActionBlock)actionCallback settings:(NSDictionary*)settings;
+ (id)initWithLaunchOptions:(NSDictionary*)launchOptions appId:(NSString*)appId handleNotificationReceived:(OSHandleNotificationReceivedBlock)receivedCallback handleNotificationAction:(OSHandleNotificationActionBlock)actionCallback settings:(NSDictionary*)settings;
+// - Privacy
++ (void)consentGranted:(BOOL)granted;
++ (BOOL)requiresUserPrivacyConsent; // tells your application if privacy consent is still needed from the current user
++ (void)setRequiresUserPrivacyConsent:(BOOL)required; //used by wrapper SDK's to require user privacy consent
+
@property (class) OSNotificationDisplayType inFocusDisplayType;
+ (NSString*)app_id;
diff --git a/iOS_SDK/OneSignalSDK/Source/OneSignal.m b/iOS_SDK/OneSignalSDK/Source/OneSignal.m
index ceb676a92..a887fb04f 100755
--- a/iOS_SDK/OneSignalSDK/Source/OneSignal.m
+++ b/iOS_SDK/OneSignalSDK/Source/OneSignal.m
@@ -67,6 +67,7 @@
#import "OneSignalSetEmailParameters.h"
#import "OneSignalCommonDefines.h"
+#import "DelayedInitializationParameters.h"
#define NOTIFICATION_TYPE_NONE 0
#define NOTIFICATION_TYPE_BADGE 1
@@ -144,7 +145,7 @@ @implementation OneSignal
this property stores the parameters so that once registration is complete
we can finish setEmail:
*/
-static OneSignalSetEmailParameters *delayedParameters;
+static OneSignalSetEmailParameters *delayedEmailParameters;
static NSMutableArray* pendingSendTagCallbacks;
static OSResultSuccessBlock pendingGetTagsSuccessBlock;
@@ -165,6 +166,14 @@ @implementation OneSignal
static BOOL promptBeforeOpeningPushURLs = false;
+static BOOL delayedInitializationForPrivacyConsent = false;
+DelayedInitializationParameters *delayedInitParameters;
+
+//the iOS Native SDK will use the plist flag to enable privacy consent
+//however wrapper SDK's will use a method call before initialization
+//this boolean flag is switched on to enable this behavior
+static BOOL shouldRequireUserConsent = false;
+
static OneSignalTrackIAP* trackIAPPurchase;
static NSString* app_id;
NSString* emailToSet;
@@ -387,6 +396,19 @@ + (id)initWithLaunchOptions:(NSDictionary*)launchOptions appId:(NSString*)appId
// NOTE: Wrapper SDKs such as Unity3D will call this method with appId set to nil so open events are not lost.
// Ensure a 2nd call can be made later with the appId from the developer's code.
+ (id)initWithLaunchOptions:(NSDictionary*)launchOptions appId:(NSString*)appId handleNotificationReceived:(OSHandleNotificationReceivedBlock)receivedCallback handleNotificationAction:(OSHandleNotificationActionBlock)actionCallback settings:(NSDictionary*)settings {
+ NSLog(@"Called init with app ID: %@", appId);
+
+ //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 ([self requiresUserPrivacyConsent]) {
+ delayedInitializationForPrivacyConsent = true;
+ delayedInitParameters = [[DelayedInitializationParameters alloc] initWithLaunchOptions:launchOptions withAppId:appId withHandleNotificationReceivedBlock:receivedCallback withHandleNotificationActionBlock:actionCallback withSettings:settings];
+ [self onesignal_Log:ONE_S_LL_VERBOSE message:@"Delayed initialization of the OneSignal SDK until the user provides privacy consent using the consentGranted() method"];
+ return self;
+ }
let userDefaults = [NSUserDefaults standardUserDefaults];
@@ -492,11 +514,6 @@ + (id)initWithLaunchOptions:(NSDictionary*)launchOptions appId:(NSString*)appId
(B) if this app requires email authentication
*/
- //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 downloadIOSParams];
-
if ([OneSignalTrackFirebaseAnalytics needsRemoteParams]) {
[OneSignalTrackFirebaseAnalytics init];
}
@@ -540,26 +557,81 @@ +(bool)initAppId:(NSString*)appId withUserDefaults:(NSUserDefaults*)userDefaults
return true;
}
++ (BOOL)shouldLogMissingPrivacyConsentErrorWithMethodName:(NSString *)methodName {
+ if ([self requiresUserPrivacyConsent]) {
+ if (methodName) {
+ [self onesignal_Log:ONE_S_LL_WARN message:[NSString stringWithFormat:@"Your application has called %@ before the user granted privacy permission. Please call `consentGranted(bool)` in order to provide user privacy consent", methodName]];
+ }
+ return true;
+ }
+
+ return false;
+}
+
++ (void)setRequiresUserPrivacyConsent:(BOOL)required {
+ shouldRequireUserConsent = required;
+}
+
++ (BOOL)requiresUserPrivacyConsent {
+
+ // if the plist key does not exist default to true
+ // the plist value specifies whether GDPR privacy consent is required for this app
+ // if required and consent has not been previously granted, return false
+
+ let requiresConsent = [[[NSBundle mainBundle] objectForInfoDictionaryKey:ONESIGNAL_REQUIRE_PRIVACY_CONSENT] boolValue] ?: false;
+
+ if (requiresConsent || shouldRequireUserConsent) {
+ let userDefaults = [NSUserDefaults standardUserDefaults];
+
+ let consentGranted = (NSNumber *)[userDefaults objectForKey:GDPR_CONSENT_GRANTED];
+
+ if (consentGranted == nil) {
+ [userDefaults setObject:@false forKey:GDPR_CONSENT_GRANTED];
+ [userDefaults synchronize];
+ }
+
+ return ![[userDefaults objectForKey:GDPR_CONSENT_GRANTED] boolValue];
+ }
+
+ return false;
+}
+
++ (void)consentGranted:(BOOL)granted {
+ let userDefaults = [NSUserDefaults standardUserDefaults];
+
+ [userDefaults setObject:@(granted) forKey:GDPR_CONSENT_GRANTED];
+ [userDefaults synchronize];
+
+ if (!granted || !delayedInitializationForPrivacyConsent || delayedInitParameters == nil)
+ return;
+
+ [self initWithLaunchOptions:delayedInitParameters.launchOptions appId:delayedInitParameters.appId handleNotificationReceived:delayedInitParameters.receivedBlock handleNotificationAction:delayedInitParameters.actionBlock settings:delayedInitParameters.settings];
+ delayedInitializationForPrivacyConsent = false;
+ delayedInitParameters = nil;
+}
+
// the iOS SDK used to call these selectors as a convenience but has stopped due to concerns about private API usage
// the SDK will now print warnings when a developer's app implements these selectors
+ (void)checkIfApplicationImplementsDeprecatedMethods {
- for (NSString *selectorName in DEPRECATED_SELECTORS)
- if ([[[UIApplication sharedApplication] delegate] respondsToSelector:NSSelectorFromString(selectorName)])
- [OneSignal onesignal_Log:ONE_S_LL_WARN message:[NSString stringWithFormat:@"OneSignal has detected that your application delegate implements a deprecated method (%@). Please note that this method has been officially deprecated and the OneSignal SDK will no longer call it. You should use UNUserNotificationCenter instead", selectorName]];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ for (NSString *selectorName in DEPRECATED_SELECTORS)
+ if ([[[UIApplication sharedApplication] delegate] respondsToSelector:NSSelectorFromString(selectorName)])
+ [OneSignal onesignal_Log:ONE_S_LL_WARN message:[NSString stringWithFormat:@"OneSignal has detected that your application delegate implements a deprecated method (%@). Please note that this method has been officially deprecated and the OneSignal SDK will no longer call it. You should use UNUserNotificationCenter instead", selectorName]];
+ });
}
-+(void)downloadIOSParams {
++(void)downloadIOSParamsWithAppId:(NSString *)appId {
[self onesignal_Log:ONE_S_LL_DEBUG message:@"Downloading iOS parameters for this application"];
didCallDownloadParameters = true;
- [OneSignalClient.sharedClient executeRequest:[OSRequestGetIosParams withUserId:self.currentSubscriptionState.userId appId:self.app_id] onSuccess:^(NSDictionary *result) {
+ [OneSignalClient.sharedClient executeRequest:[OSRequestGetIosParams withUserId:self.currentSubscriptionState.userId appId:appId] onSuccess:^(NSDictionary *result) {
if (result[@"require_email_auth"]) {
self.currentEmailSubscriptionState.requiresEmailAuth = [result[@"require_email_auth"] boolValue];
// checks if a cell to setEmail: was delayed due to missing 'requiresEmailAuth' parameter
- if (delayedParameters && self.currentSubscriptionState.userId) {
- [self setEmail:delayedParameters.email withEmailAuthHashToken:delayedParameters.authToken withSuccess:delayedParameters.successBlock withFailure:delayedParameters.failureBlock];
- delayedParameters = nil;
+ if (delayedEmailParameters && self.currentSubscriptionState.userId) {
+ [self setEmail:delayedEmailParameters.email withEmailAuthHashToken:delayedEmailParameters.authToken withSuccess:delayedEmailParameters.successBlock withFailure:delayedEmailParameters.failureBlock];
+ delayedEmailParameters = nil;
}
}
@@ -649,6 +721,11 @@ + (BOOL)registerForAPNsToken {
}
+ (void)promptForPushNotificationsWithUserResponse:(void(^)(BOOL accepted))completionHandler {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"promptForPushNotificationsWithUserResponse:"])
+ return;
+
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"registerForPushNotifications Called:waitingForApnsResponse: %d", waitingForApnsResponse]];
self.currentPermissionState.hasPrompted = true;
@@ -659,6 +736,11 @@ + (void)promptForPushNotificationsWithUserResponse:(void(^)(BOOL accepted))compl
// This registers for a push token and prompts the user for notifiations permisions
// Will trigger didRegisterForRemoteNotificationsWithDeviceToken on the AppDelegate when APNs responses.
+ (void)registerForPushNotifications {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"registerForPushNotifications:"])
+ return;
+
[self promptForPushNotificationsWithUserResponse:nil];
}
@@ -711,11 +793,21 @@ + (void)removeEmailSubscriptionObserver:(NSObject*)
// Block not assigned if userID nil and there is a device token
+ (void)IdsAvailable:(OSIdsAvailableBlock)idsAvailableBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"IdsAvailable:"])
+ return;
+
idsAvailableBlockWhenReady = idsAvailableBlock;
[self fireIdsAvailableCallback];
}
+ (void) fireIdsAvailableCallback {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
if (!idsAvailableBlockWhenReady)
return;
if (!self.currentSubscriptionState.userId)
@@ -733,6 +825,11 @@ + (void) fireIdsAvailableCallback {
}
+ (void)sendTagsWithJsonString:(NSString*)jsonString {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"sendTagsWithJsonString:"])
+ return;
+
NSError* jsonError;
NSData* data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
@@ -746,10 +843,19 @@ + (void)sendTagsWithJsonString:(NSString*)jsonString {
}
+ (void)sendTags:(NSDictionary*)keyValuePair {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"sendTags:"])
+ return;
+
[self sendTags:keyValuePair onSuccess:nil onFailure:nil];
}
+ (void)sendTags:(NSDictionary*)keyValuePair onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"sendTags:onSuccess:onFailure:"])
+ return;
if (![NSJSONSerialization isValidJSONObject:keyValuePair]) {
onesignal_Log(ONE_S_LL_WARN, [NSString stringWithFormat:@"sendTags JSON Invalid: The following key/value pairs you attempted to send as tags are not valid JSON: %@", keyValuePair]);
@@ -787,6 +893,11 @@ + (void)sendTags:(NSDictionary*)keyValuePair onSuccess:(OSResultSuccessBlock)suc
// Called only with a delay to batch network calls.
+ (void) sendTagsToServer {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
if (!tagsToSend)
return;
@@ -828,14 +939,29 @@ + (void) sendTagsToServer {
}
+ (void)sendTag:(NSString*)key value:(NSString*)value {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"sendTag:value:"])
+ return;
+
[self sendTag:key value:value onSuccess:nil onFailure:nil];
}
+ (void)sendTag:(NSString*)key value:(NSString*)value onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"sendTag:value:onSuccess:onFailure:"])
+ return;
+
[self sendTags:[NSDictionary dictionaryWithObjectsAndKeys: value, key, nil] onSuccess:successBlock onFailure:failureBlock];
}
+ (void)getTags:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"getTags:onFailure:"])
+ return;
+
if (!self.currentSubscriptionState.userId) {
pendingGetTagsSuccessBlock = successBlock;
pendingGetTagsFailureBlock = failureBlock;
@@ -849,23 +975,48 @@ + (void)getTags:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)fai
}
+ (void)getTags:(OSResultSuccessBlock)successBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"getTags:"])
+ return;
+
[self getTags:successBlock onFailure:nil];
}
+ (void)deleteTag:(NSString*)key onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"deleteTag:onSuccess:onFailure:"])
+ return;
+
[self deleteTags:@[key] onSuccess:successBlock onFailure:failureBlock];
}
+ (void)deleteTag:(NSString*)key {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"deleteTag:"])
+ return;
+
[self deleteTags:@[key] onSuccess:nil onFailure:nil];
}
+ (void)deleteTags:(NSArray*)keys {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"deleteTags:"])
+ return;
+
[self deleteTags:keys onSuccess:nil onFailure:nil];
}
+ (void)deleteTagsWithJsonString:(NSString*)jsonString {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"deleteTagsWithJsonString:"])
+ return;
+
NSError* jsonError;
NSData* data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
@@ -895,10 +1046,20 @@ + (void)deleteTags:(NSArray*)keys onSuccess:(OSResultSuccessBlock)successBlock o
+ (void)postNotification:(NSDictionary*)jsonData {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"postNotification:"])
+ return;
+
[self postNotification:jsonData onSuccess:nil onFailure:nil];
}
+ (void)postNotification:(NSDictionary*)jsonData onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"postNotification:onSuccess:onFailure:"])
+ return;
+
NSMutableDictionary *json = [jsonData mutableCopy];
[OneSignal convertDatesToISO8061Strings:json]; //convert any dates to NSString's
@@ -923,6 +1084,11 @@ + (void)postNotification:(NSDictionary*)jsonData onSuccess:(OSResultSuccessBlock
}
+ (void)postNotificationWithJsonString:(NSString*)jsonString onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"postNotificationWithJsonString:onSuccess:onFailure:"])
+ return;
+
NSError* jsonError;
NSData* data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
@@ -974,6 +1140,11 @@ + (void)enableInAppLaunchURL:(NSNumber*)enable {
}
+ (void)setSubscription:(BOOL)enable {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setSubscription:"])
+ return;
+
NSString* value = nil;
if (!enable)
value = @"no";
@@ -995,6 +1166,11 @@ + (void)setLocationShared:(BOOL)enable {
}
+ (void) promptLocation {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"promptLocation"])
+ return;
+
[OneSignalLocation getLocation:true];
}
@@ -1027,6 +1203,11 @@ + (void) handleDidFailRegisterForRemoteNotification:(NSError*)err {
}
+ (void)updateDeviceToken:(NSString*)deviceToken onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"updateDeviceToken:onSuccess:onFailure:"])
+ return;
+
onesignal_Log(ONE_S_LL_VERBOSE, @"updateDeviceToken:onSuccess:onFailure:");
// iOS 7
@@ -1088,6 +1269,11 @@ + (void)updateLastSessionDateTime {
}
+(BOOL)shouldRegisterNow {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return false;
+
if (waitingForOneSReg)
return false;
@@ -1121,6 +1307,11 @@ + (dispatch_queue_t) getRegisterQueue {
}
+ (void)registerUser {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
if (waitingForApnsResponse) {
[self registerUserAfterDelay];
return;
@@ -1135,6 +1326,11 @@ + (void)registerUser {
}
+ (void)registerUserInternal {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
// Make sure we only call create or on_session once per open of the app.
if (![self shouldRegisterNow])
return;
@@ -1273,10 +1469,10 @@ + (void)registerUserInternal {
if (results.count > 0 && results[@"push"][@"id"]) {
self.currentSubscriptionState.userId = results[@"push"][@"id"];
- if (delayedParameters) {
+ if (delayedEmailParameters) {
//a call to setEmail: was delayed because the push player_id did not exist yet
- [self setEmail:delayedParameters.email withEmailAuthHashToken:delayedParameters.authToken withSuccess:delayedParameters.successBlock withFailure:delayedParameters.failureBlock];
- delayedParameters = nil;
+ [self setEmail:delayedEmailParameters.email withEmailAuthHashToken:delayedEmailParameters.authToken withSuccess:delayedEmailParameters.successBlock withFailure:delayedEmailParameters.failureBlock];
+ delayedEmailParameters = nil;
}
[[NSUserDefaults standardUserDefaults] setObject:self.currentSubscriptionState.userId forKey:USERID];
@@ -1348,6 +1544,11 @@ +(NSString*)getUsableDeviceToken {
// Updates the server with the new user's notification setting or subscription status changes
+ (BOOL) sendNotificationTypesUpdate {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return false;
+
// User changed notification settings for the app.
if ([self getNotificationTypes] != -1 && self.currentSubscriptionState.userId && mLastNotificationTypes != [self getNotificationTypes]) {
if (!self.currentSubscriptionState.pushToken) {
@@ -1379,6 +1580,11 @@ + (BOOL) sendNotificationTypesUpdate {
}
+ (void)sendPurchases:(NSArray*)purchases {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
if (!self.currentSubscriptionState.userId)
return;
@@ -1405,6 +1611,8 @@ + (void)setLastnonActiveMessageId:(NSString*)value { _lastnonActiveMessageId = v
// - 2A. iOS 9 - Notification received while app is in focus.
// - 2B. iOS 10 - Notification received/displayed while app is in focus.
+ (void)notificationReceived:(NSDictionary*)messageDict isActive:(BOOL)isActive wasOpened:(BOOL)opened {
+ if ([OneSignal shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
if (!app_id)
return;
@@ -1481,6 +1689,10 @@ + (void)handleNotificationOpened:(NSDictionary*)messageDict
actionType:(OSNotificationActionType)actionType
displayType:(OSNotificationDisplayType)displayType {
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"handleNotificationOpened:isActive:actionType:displayType:"])
+ return;
+
NSDictionary* customDict = [messageDict objectForKey:@"custom"] ?: [messageDict objectForKey:@"os_data"];
// Notify backend that user opened the notification
@@ -1526,6 +1738,11 @@ + (void)launchWebURL:(NSString*)openUrl {
}
+ (void)submitNotificationOpened:(NSString*)messageId {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
//(DUPLICATE Fix): Make sure we do not upload a notification opened twice for the same messageId
//Keep track of the Id for the last message sent
NSString* lastMessageId = [[NSUserDefaults standardUserDefaults] objectForKey:@"GT_LAST_MESSAGE_OPENED_"];
@@ -1627,9 +1844,13 @@ + (void)updateNotificationTypes:(int)notificationTypes {
}
+ (void)didRegisterForRemoteNotifications:(UIApplication*)app deviceToken:(NSData*)inDeviceToken {
+ if ([OneSignal shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
let trimmedDeviceToken = [[inDeviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
let parsedDeviceToken = [[trimmedDeviceToken componentsSeparatedByString:@" "] componentsJoinedByString:@""];
+
[OneSignal onesignal_Log:ONE_S_LL_INFO message: [NSString stringWithFormat:@"Device Registered with Apple: %@", parsedDeviceToken]];
waitingForApnsResponse = false;
@@ -1693,6 +1914,9 @@ + (BOOL)remoteSilentNotification:(UIApplication*)application UserInfo:(NSDiction
// iOS 8-9 - Entry point when OneSignal action button notification is displayed or opened.
+ (void)processLocalActionBasedNotification:(UILocalNotification*) notification identifier:(NSString*)identifier {
+ if ([OneSignal shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
+ return;
+
if (!notification.userInfo)
return;
@@ -1713,6 +1937,11 @@ + (void)processLocalActionBasedNotification:(UILocalNotification*) notification
}
+ (void)syncHashedEmail:(NSString *)email {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"syncHashedEmail:"])
+ return;
+
if (!email) {
[self onesignal_Log:ONE_S_LL_WARN message:@"OneSignal syncHashedEmail: The provided email is nil"];
return;
@@ -1769,6 +1998,10 @@ + (void)callSuccessBlockOnMainThread:(OSEmailSuccessBlock)successBlock {
+ (void)setEmail:(NSString * _Nonnull)email withEmailAuthHashToken:(NSString * _Nullable)hashToken withSuccess:(OSEmailSuccessBlock _Nullable)successBlock withFailure:(OSEmailFailureBlock _Nullable)failureBlock {
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setEmail:withEmailAuthHashToken:withSuccess:withFailure:"])
+ return;
+
//some clients/wrappers may send NSNull instead of nil as the auth token
NSString *emailAuthToken = hashToken;
if (hashToken == (id)[NSNull null])
@@ -1804,7 +2037,7 @@ + (void)setEmail:(NSString * _Nonnull)email withEmailAuthHashToken:(NSString * _
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."];
- delayedParameters = [OneSignalSetEmailParameters withEmail:email withAuthToken:emailAuthToken withSuccess:successBlock withFailure:failureBlock];
+ delayedEmailParameters = [OneSignalSetEmailParameters withEmail:email withAuthToken:emailAuthToken withSuccess:successBlock withFailure:failureBlock];
return;
}
@@ -1846,10 +2079,20 @@ + (void)setEmail:(NSString * _Nonnull)email withEmailAuthHashToken:(NSString * _
}
+ (void)setEmail:(NSString * _Nonnull)email withSuccess:(OSEmailSuccessBlock _Nullable)successBlock withFailure:(OSEmailFailureBlock _Nullable)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setEmail:withSuccess:withFailure:"])
+ return;
+
[self setEmail:email withEmailAuthHashToken:nil withSuccess:successBlock withFailure:failureBlock];
}
+ (void)logoutEmailWithSuccess:(OSEmailSuccessBlock _Nullable)successBlock withFailure:(OSEmailFailureBlock _Nullable)failureBlock {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"logoutEmailWithSuccess:withFailure:"])
+ return;
+
if (!self.currentEmailSubscriptionState.emailUserId) {
[OneSignal onesignal_Log:ONE_S_LL_ERROR message:@"Email Player ID does not exist, cannot logout"];
@@ -1877,14 +2120,29 @@ + (void)logoutEmailWithSuccess:(OSEmailSuccessBlock _Nullable)successBlock withF
}
+ (void)setEmail:(NSString * _Nonnull)email {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setEmail:"])
+ return;
+
[self setEmail:email withSuccess:nil withFailure:nil];
}
+ (void)logoutEmail {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"logoutEmail"])
+ return;
+
[self logoutEmailWithSuccess:nil withFailure:nil];
}
+ (void)setEmail:(NSString * _Nonnull)email withEmailAuthHashToken:(NSString * _Nullable)hashToken {
+
+ // return if the user has not granted privacy permissions
+ if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setEmail:withEmailAuthHashToken:"])
+ return;
+
[self setEmail:email withEmailAuthHashToken:hashToken withSuccess:nil withFailure:nil];
}
diff --git a/iOS_SDK/OneSignalSDK/Source/OneSignalClient.m b/iOS_SDK/OneSignalSDK/Source/OneSignalClient.m
index e6cbed2da..2910eadec 100644
--- a/iOS_SDK/OneSignalSDK/Source/OneSignalClient.m
+++ b/iOS_SDK/OneSignalSDK/Source/OneSignalClient.m
@@ -28,12 +28,17 @@
#import "OneSignalClient.h"
#import "UIApplicationDelegate+OneSignal.h"
#import "ReattemptRequest.h"
+#import "OneSignal.h"
#define REATTEMPT_DELAY 30.0
#define REQUEST_TIMEOUT_REQUEST 60.0 //for most HTTP requests
#define REQUEST_TIMEOUT_RESOURCE 100.0 //for loading a resource like an image
#define MAX_ATTEMPT_COUNT 3
+@interface OneSignal (OneSignalClientExtra)
++ (BOOL)shouldLogMissingPrivacyConsentErrorWithMethodName:(NSString *)methodName;
+@end
+
@interface OneSignalClient ()
@property (strong, nonatomic) NSURLSession *sharedSession;
@end
@@ -100,6 +105,12 @@ - (void)executeSimultaneousRequests:(NSDictionarylast.from.userId);
+ XCTAssertNil(observer->last.to.userId);
+ XCTAssertFalse(observer->last.to.subscribed);
+
+ [OneSignal setSubscription:true];
+ [UnitTestCommonMethods runBackgroundThreads];
+
+ XCTAssertFalse(observer->last.from.userSubscriptionSetting);
+ XCTAssertFalse(observer->last.to.userSubscriptionSetting);
+ // Device registered with OneSignal so now make pushToken available.
+ XCTAssertNil(observer->last.to.pushToken);
+
+ [NSBundleOverrider setPrivacyState:false];
+
//tests to make sure that UNNotificationCenter setDelegate: duplicate calls don't double-swizzle for the same object
- (void)testSwizzling {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
@@ -1874,6 +1952,7 @@ - (void)testSwizzling {
XCTAssertNotEqual(original, newSwizzled);
XCTAssertEqual(swizzled, newSwizzled);
+
}
@end