diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 54d15b49..cecd41b5 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -218,9 +218,12 @@ The Push Subscription namespace is accessible via `OneSignal.User.pushSubscripti | **React Native** | **Description** | | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `OneSignal.User.pushSubscription.getPushSubscriptionId()` | _The readonly push subscription ID._ | -| `OneSignal.User.pushSubscription.getPushSubscriptionToken()` | _The readonly push token._ | -| `OneSignal.User.pushSubscription.getOptedIn()` | _Gets a boolean value indicating whether the current user is opted in to push notifications. This returns `true` when the app has notifications permission and `optedOut` is called. **_Note:_** Does not take into account the existence of the subscription ID and push token. This boolean may return `true` but push notifications may still not be received by the user._ | +| `OneSignal.User.pushSubscription.getPushSubscriptionId()` | _**DEPRECATED**
use `getIdAsync`._ | +| `OneSignal.User.pushSubscription.getPushSubscriptionToken()` | _**DEPRECATED**
use `getTokenAsync`_ | +| `OneSignal.User.pushSubscription.getOptedIn()` | _**DEPRECATED**
use `getOptedInAsync`_ | +| `await OneSignal.User.pushSubscription.getIdAsync()` | _The readonly push subscription ID._ | +| `await OneSignal.User.pushSubscription.getTokenAsync()` | _The readonly push token._ | +| `await OneSignal.User.pushSubscription.getOptedInAsync()` | _Gets a boolean value indicating whether the current user is opted in to push notifications. This returns `true` when the app has notifications permission and `optedOut` is called. **_Note:_** Does not take into account the existence of the subscription ID and push token. This boolean may return `true` but push notifications may still not be received by the user._ | | `OneSignal.User.pushSubscription.optIn()` | _Call this method to receive push notifications on the device or to resume receiving of push notifications after calling `optOut`. If needed, this method will prompt the user for push notifications permission._ | | `OneSignal.User.pushSubscription.optOut()` | _If at any point you want the user to stop receiving push notifications on the current device (regardless of system-level permission status), you can call this method to opt out._ | | `OneSignal.User.pushSubscription.addEventListener('change', listener: (event) => void)`

**_See below for usage_** | _Adds the listener to run when the push subscription changes._ | @@ -254,7 +257,8 @@ The Notifications namespace is accessible via `OneSignal.Notifications` and prov | **React Native** | **Description** | |--------------------------------------- | --------------- | -| `OneSignal.Notifications.hasPermission()` | _Whether this app has push notification permission._ | +| `OneSignal.Notifications.hasPermission()` | _**DEPRECATED**
use `getPermissionAsync()`_ | +| `OneSignal.Notifications.getPermissionAsync()` | _Whether this app has push notification permission._ | | `await OneSignal.Notifications.canRequestPermission()` | _Whether attempting to request notification permission will show a prompt. Returns `true` if the device has not been prompted for push notification permission already._ | | `await OneSignal.Notifications.permissionNative()` | _(ios only) Returns the enum for the native permission of the device. It will be one of: NotDetermined, Denied, Authorized, Provisional (only available in iOS 12), Ephemeral (only available in iOS 14)_ | | `OneSignal.Notifications.clearAll();` | _Removes all OneSignal notifications._ | diff --git a/android/src/main/java/com/onesignal/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/onesignal/rnonesignalandroid/RNOneSignal.java index b856594e..debabf3e 100644 --- a/android/src/main/java/com/onesignal/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/onesignal/rnonesignalandroid/RNOneSignal.java @@ -434,6 +434,12 @@ public void onNotificationPermissionChange(boolean permission) { @ReactMethod public void requestNotificationPermission(final boolean fallbackToSettings, Promise promise) { + // if permission already exists, return early as the method call will not resolve + if (OneSignal.getNotifications().getPermission()) { + promise.resolve(true); + return; + } + OneSignal.getNotifications().requestPermission(fallbackToSettings, Continue.with(result -> { if (result.isSuccess()) { promise.resolve(result.getData()); @@ -448,6 +454,16 @@ public void hasNotificationPermission(Promise promise) { promise.resolve(OneSignal.getNotifications().getPermission()); } + @ReactMethod + public void permissionNative(Promise promise) { + if (OneSignal.getNotifications().getPermission()) { + promise.resolve(2); + } + else { + promise.resolve(1); + } + } + @ReactMethod public void canRequestNotificationPermission(Promise promise) { promise.resolve(OneSignal.getNotifications().getCanRequestPermission()); @@ -473,13 +489,23 @@ public void removeGroupedNotifications(String id) { @ReactMethod public void getPushSubscriptionId(Promise promise) { IPushSubscription pushSubscription = OneSignal.getUser().getPushSubscription(); - promise.resolve(pushSubscription.getId()); + String pushId = pushSubscription.getId(); + if (pushId != null && !pushId.isEmpty()){ + promise.resolve(pushId); + } else { + promise.resolve(null); + } } @ReactMethod public void getPushSubscriptionToken(Promise promise) { IPushSubscription pushSubscription = OneSignal.getUser().getPushSubscription(); - promise.resolve(pushSubscription.getToken()); + String pushToken = pushSubscription.getToken(); + if (pushToken != null && !pushToken.isEmpty()) { + promise.resolve(pushToken); + } else { + promise.resolve(null); + } } @ReactMethod diff --git a/android/src/main/java/com/onesignal/rnonesignalandroid/RNUtils.java b/android/src/main/java/com/onesignal/rnonesignalandroid/RNUtils.java index ee7c60f6..a9b034a9 100644 --- a/android/src/main/java/com/onesignal/rnonesignalandroid/RNUtils.java +++ b/android/src/main/java/com/onesignal/rnonesignalandroid/RNUtils.java @@ -182,9 +182,16 @@ public static HashMap convertInAppMessageClickEventToMap(IInAppM public static HashMap convertPushSubscriptionStateToMap(PushSubscriptionState state) { HashMap hash = new HashMap<>(); - - hash.put("token", state.getToken()); - hash.put("id", state.getId()); + if (state.getToken() != null && !state.getToken().isEmpty()) { + hash.put("token", state.getToken()); + } else { + hash.put("token", JSONObject.NULL); + } + if (state.getId() != null && !state.getId().isEmpty()) { + hash.put("id", state.getId()); + } else { + hash.put("id", JSONObject.NULL); + } hash.put("optedIn", state.getOptedIn()); return hash; diff --git a/examples/RNOneSignalTS/src/OSButtons.tsx b/examples/RNOneSignalTS/src/OSButtons.tsx index d9a4914f..ce3ebfc4 100644 --- a/examples/RNOneSignalTS/src/OSButtons.tsx +++ b/examples/RNOneSignalTS/src/OSButtons.tsx @@ -133,8 +133,8 @@ class OSButtons extends React.Component { const hasPermissionButton = renderButtonView( 'Has Notification Permission', - () => { - const granted = OneSignal.Notifications.hasPermission(); + async () => { + const granted = await OneSignal.Notifications.getPermissionAsync(); loggingFunction(`Has Notification Permission: ${granted}`); }, ); @@ -368,8 +368,7 @@ class OSButtons extends React.Component { const getPushSubscriptionIdButton = renderButtonView( 'Get Push Subscription Id', async () => { - const id = - await OneSignal.User.pushSubscription.getPushSubscriptionId(); + const id = await OneSignal.User.pushSubscription.getIdAsync(); loggingFunction('Push Subscription Id: ', id); }, ); @@ -377,14 +376,13 @@ class OSButtons extends React.Component { const getPushSubscriptionTokenButton = renderButtonView( 'Get Push Subscription Token', async () => { - const token = - await OneSignal.User.pushSubscription.getPushSubscriptionToken(); + const token = await OneSignal.User.pushSubscription.getTokenAsync(); loggingFunction('Push Subscription Token: ', token); }, ); const getOptedInButton = renderButtonView('Is Opted In', async () => { - const optedIn = await OneSignal.User.pushSubscription.getOptedIn(); + const optedIn = await OneSignal.User.pushSubscription.getOptedInAsync(); loggingFunction('Subscribed for the push notifications: ', optedIn); }); diff --git a/ios/RCTOneSignal/RCTOneSignal.m b/ios/RCTOneSignal/RCTOneSignal.m index 1e4486cf..85118514 100644 --- a/ios/RCTOneSignal/RCTOneSignal.m +++ b/ios/RCTOneSignal/RCTOneSignal.m @@ -78,7 +78,23 @@ - (void)sendEvent:(NSString *)eventName withBody:(NSDictionary *)body { } - (void)onPushSubscriptionDidChangeWithState:(OSPushSubscriptionChangedState * _Nonnull)state { - [self sendEvent:OSEventString(SubscriptionChanged) withBody:[state jsonRepresentation]]; + NSMutableDictionary *result = [NSMutableDictionary new]; + + //Previous state + NSMutableDictionary *previousObject = [NSMutableDictionary new]; + previousObject[@"token"] = (state.previous.token && ![state.previous.token isEqualToString:@""]) ? state.previous.token : [NSNull null]; + previousObject[@"id"] = (state.previous.id && ![state.previous.id isEqualToString:@""]) ? state.previous.id : [NSNull null]; + previousObject[@"optedIn"] = @(state.previous.optedIn); + result[@"previous"] = previousObject; + + //Current state + NSMutableDictionary *currentObject = [NSMutableDictionary new]; + currentObject[@"token"] = (state.current.token && ![state.current.token isEqualToString:@""]) ? state.current.token : [NSNull null]; + currentObject[@"id"] = (state.current.id && ![state.current.id isEqualToString:@""]) ? state.current.id : [NSNull null]; + currentObject[@"optedIn"] = @(state.current.optedIn); + result[@"current"] = currentObject; + + [self sendEvent:OSEventString(SubscriptionChanged) withBody:result]; } - (void)onNotificationPermissionDidChange:(BOOL)permission { diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 5861b208..0d72549c 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -392,13 +392,23 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_REMAP_METHOD(getPushSubscriptionId, getPushSubscriptionIdResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - resolve(OneSignal.User.pushSubscription.id); + NSString *pushId = OneSignal.User.pushSubscription.id; + if (pushId && ![pushId isEqualToString:@""]) { + resolve(pushId); + } else { + resolve([NSNull null]); + } } RCT_REMAP_METHOD(getPushSubscriptionToken, getPushSubscriptionTokenResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - resolve(OneSignal.User.pushSubscription.token); + NSString *token = OneSignal.User.pushSubscription.token; + if (token && ![token isEqualToString:@""]) { + resolve(token); + } else { + resolve([NSNull null]); + } } RCT_EXPORT_METHOD(optIn) { diff --git a/src/index.ts b/src/index.ts index ed6d2e67..1958466f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -217,22 +217,67 @@ export namespace OneSignal { eventManager.removeEventListener(SUBSCRIPTION_CHANGED, listener); } - /** The readonly push subscription ID */ + /** + * @deprecated This method is deprecated. It has been replaced by {@link getIdAsync}. + */ export function getPushSubscriptionId(): string { if (!isNativeModuleLoaded(RNOneSignal)) { return ''; } + console.warn( + 'OneSignal: This method has been deprecated. Use getIdAsync instead for getting push subscription id.', + ); - return pushSub.id; + return pushSub.id ? pushSub.id : ''; } - /** The readonly push subscription token */ + export async function getIdAsync(): Promise { + if (!isNativeModuleLoaded(RNOneSignal)) { + return Promise.reject( + new Error('OneSignal native module not loaded'), + ); + } + + return await RNOneSignal.getPushSubscriptionId(); + } + + /** + * @deprecated This method is deprecated. It has been replaced by {@link getTokenAsync}. + */ export function getPushSubscriptionToken(): string { if (!isNativeModuleLoaded(RNOneSignal)) { return ''; } + console.warn( + 'OneSignal: This method has been deprecated. Use getTokenAsync instead for getting push subscription token.', + ); - return pushSub.token; + return pushSub.token ? pushSub.token : ''; + } + + /** The readonly push subscription token */ + export async function getTokenAsync(): Promise { + if (!isNativeModuleLoaded(RNOneSignal)) { + return Promise.reject( + new Error('OneSignal native module not loaded'), + ); + } + + return await RNOneSignal.getPushSubscriptionToken(); + } + + /** + * @deprecated This method is deprecated. It has been replaced by {@link getOptedInAsync}. + */ + export function getOptedIn(): boolean { + if (!isNativeModuleLoaded(RNOneSignal)) { + return false; + } + console.warn( + 'OneSignal: This method has been deprecated. Use getOptedInAsync instead for getting push subscription opted in status.', + ); + + return pushSub.optedIn; } /** @@ -241,12 +286,14 @@ export namespace OneSignal { * Note: Does not take into account the existence of the subscription ID and push token. * This boolean may return true but push notifications may still not be received by the user. */ - export function getOptedIn(): boolean { + export async function getOptedInAsync(): Promise { if (!isNativeModuleLoaded(RNOneSignal)) { - return false; + return Promise.reject( + new Error('OneSignal native module not loaded'), + ); } - return pushSub.optedIn; + return await RNOneSignal.getOptedIn(); } /** Disable the push notification subscription to OneSignal. */ @@ -263,7 +310,6 @@ export namespace OneSignal { RNOneSignal.optIn(); } } - /** Explicitly set a 2-character language code for the user. */ export function setLanguage(language: string) { if (!isNativeModuleLoaded(RNOneSignal)) return; @@ -404,13 +450,24 @@ export namespace OneSignal { export namespace Notifications { /** - * Whether this app has push notification permission. Returns true if the user has accepted permissions, - * or if the app has ephemeral or provisional permission. + * @deprecated This method is deprecated. It has been replaced by {@link getPermissionAsync}. */ export function hasPermission(): boolean { + console.warn( + 'OneSignal: This method has been deprecated. Use getPermissionAsync instead for getting notification permission status.', + ); + return notificationPermission; } + /** + * Whether this app has push notification permission. Returns true if the user has accepted permissions, + * or if the app has ephemeral or provisional permission. + */ + export async function getPermissionAsync(): Promise { + return RNOneSignal.hasNotificationPermission(); + } + /** * Prompt the user for permission to receive push notifications. This will display the native system prompt to request push * notification permission. Use the fallbackToSettings parameter to prompt to open the settings app if a user has already @@ -422,10 +479,6 @@ export namespace OneSignal { if (!isNativeModuleLoaded(RNOneSignal)) { return Promise.reject(new Error('OneSignal native module not loaded')); } - // if permission already exists, return early as the native call will not resolve - if (hasPermission()) { - return Promise.resolve(true); - } return RNOneSignal.requestNotificationPermission(fallbackToSettings); } @@ -475,13 +528,7 @@ export namespace OneSignal { return Promise.reject(new Error('OneSignal native module not loaded')); } - if (Platform.OS === 'ios') { - return RNOneSignal.permissionNative(); - } else { - return notificationPermission - ? Promise.resolve(OSNotificationPermission.Authorized) - : Promise.resolve(OSNotificationPermission.Denied); - } + return RNOneSignal.permissionNative(); } /** diff --git a/src/models/Subscription.ts b/src/models/Subscription.ts index ac21cf24..d4771f55 100644 --- a/src/models/Subscription.ts +++ b/src/models/Subscription.ts @@ -7,8 +7,8 @@ export enum OSNotificationPermission { } export interface PushSubscriptionState { - id: string; - token: string; + id?: string; + token?: string; optedIn: boolean; }