From b9acd05360eeda9fc1fcb88819b8194659edb0f3 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 4 Sep 2020 17:59:32 -0500 Subject: [PATCH 01/69] Index Implementation * Clean up Events * Removed `addEventListener` * Added Observers * Notification handlers --- index.js | 538 --------------------------------------------------- src/index.js | 424 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 424 insertions(+), 538 deletions(-) delete mode 100644 index.js create mode 100644 src/index.js diff --git a/index.js b/index.js deleted file mode 100644 index 3032de3e..00000000 --- a/index.js +++ /dev/null @@ -1,538 +0,0 @@ - -'use strict'; - -import { NativeModules, NativeEventEmitter, Platform } from 'react-native'; -import invariant from 'invariant'; - -const RNOneSignal = NativeModules.OneSignal; - - -/** - 1. - These events are used to broadcast events to native code - */ -const OS_REMOTE_NOTIFICATION_RECEIVED = 'OneSignal-remoteNotificationReceived'; -const OS_REMOTE_NOTIFICATION_OPENED = 'OneSignal-remoteNotificationOpened'; -const OS_IDS_AVAILABLE = 'OneSignal-idsAvailable'; -//const OS_SUBSCRIPTION = 'OneSignal-subscription'; -//const OS_PERMISSION = 'OneSignal-permission'; -const OS_EMAIL_SUBSCRIPTION = 'OneSignal-emailSubscription'; -const OS_IN_APP_MESSAGE_CLICKED = 'OneSignal-inAppMessageClicked'; -// Add more native broadcast strings here... - -const _eventBroadcastNames = [ - OS_REMOTE_NOTIFICATION_RECEIVED, - OS_REMOTE_NOTIFICATION_OPENED, - OS_IDS_AVAILABLE, -// OS_SUBSCRIPTION, -// OS_PERMISSION, - OS_EMAIL_SUBSCRIPTION, - OS_IN_APP_MESSAGE_CLICKED, - // Append new native broadcast strings here -]; - -/** - 2. - These events are used to interpret events from native code - */ -const NOTIFICATION_RECEIVED_EVENT = "received"; -const NOTIFICATION_OPENED_EVENT = "opened"; -const IDS_AVAILABLE_EVENT = "ids"; -//const SUBSCRIPTION_EVENT = "subscription"; -//const PERMISSION_EVENT = "permission"; -const EMAIL_SUBSCRIPTION_EVENT = "emailSubscription"; -const IN_APP_MESSAGE_CLICKED_EVENT = "inAppMessageClicked"; -// Add more JS string events here... - -const _eventNames = [ - NOTIFICATION_RECEIVED_EVENT, - NOTIFICATION_OPENED_EVENT, - IDS_AVAILABLE_EVENT, -// SUBSCRIPTION_EVENT, -// PERMISSION_EVENT, - EMAIL_SUBSCRIPTION_EVENT, - IN_APP_MESSAGE_CLICKED_EVENT, - // Append new JS string events here -]; - -var oneSignalEventEmitter; - -var _eventTypeHandler = new Map(); -var _notificationCache = new Map(); -var _listeners = []; - -if (RNOneSignal != null) { - oneSignalEventEmitter = new NativeEventEmitter(RNOneSignal); - - for(var i = 0; i < _eventBroadcastNames.length; i++) { - var eventBroadcastName = _eventBroadcastNames[i]; - var eventName = _eventNames[i]; - - _listeners[eventName] = handleEventBroadcast(eventName, eventBroadcastName) - } -} - -function handleEventBroadcast(type, broadcast) { - return oneSignalEventEmitter.addListener( - broadcast, (notification) => { - // Check if we have added listener for this type yet - // Cache the result first if we have not. - var handler = _eventTypeHandler.get(type); - - if (handler) { - handler(notification); - } else { - _notificationCache.set(type, notification); - } - } - ); -} - -function checkIfInitialized() { - return RNOneSignal != null; -} - -export default class OneSignal { - - /** - Listen to events of received, opened, ids, subscription, permission, emailSubscription, inAppMessageClicked - TODO: We currently have implemented the steps up until connecting the "SUBSCRIPTION_EVENT" and "PERMISSION_EVENT" - Currently the getPermissionSubscriptionState is used to get all device information and - needs to be broken up into using the native observers to fire these React-Native handlers - */ - static addEventListener(type, handler) { - if (!checkIfInitialized()) return; - - invariant( - type === NOTIFICATION_RECEIVED_EVENT || - type === NOTIFICATION_OPENED_EVENT || - type === IDS_AVAILABLE_EVENT || -// type === SUBSCRIPTION_EVENT || -// type === PERMISSION_EVENT || - type === EMAIL_SUBSCRIPTION_EVENT || - type === IN_APP_MESSAGE_CLICKED_EVENT, - 'OneSignal only supports received, opened, ids, emailSubscription, and inAppMessageClicked events' - ); - - _eventTypeHandler.set(type, handler); - - // Make native request to init notification opened handler - if (type === NOTIFICATION_OPENED_EVENT) { - RNOneSignal.initNotificationOpenedHandlerParams(); - } - - // Make native request to init idsAvailable handler - if (type === IDS_AVAILABLE_EVENT) { - RNOneSignal.idsAvailable(); - } - - // Make native request to init IAM handler - if (type === IN_APP_MESSAGE_CLICKED_EVENT) { - if (Platform.OS === 'android') { - RNOneSignal.initInAppMessageClickHandlerParams(); - } else if (Platform.OS === 'ios') { - RNOneSignal.setInAppMessageClickHandler(); - } - } - - // Check if there is a cache for this type of event - var cache = _notificationCache.get(type); - if (handler && cache) { - handler(cache); - _notificationCache.delete(type); - } - } - - static removeEventListener(type) { - if (!checkIfInitialized()) return; - - invariant( - type === NOTIFICATION_RECEIVED_EVENT || - type === NOTIFICATION_OPENED_EVENT || - type === IDS_AVAILABLE_EVENT || -// type === SUBSCRIPTION_EVENT || -// type === PERMISSION_EVENT || - type === EMAIL_SUBSCRIPTION_EVENT || - type === IN_APP_MESSAGE_CLICKED_EVENT, - 'OneSignal only supports received, opened, ids, emailSubscription, and inAppMessageClicked events' - ); - - _eventTypeHandler.delete(type); - } - - static clearListeners() { - if (!checkIfInitialized()) return; - - for(var i = 0; i < _eventNames.length; i++) { - _listeners[_eventNames].remove(); - } - } - - static registerForPushNotifications() { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'ios') { - RNOneSignal.registerForPushNotifications(); - } else { - console.log("This function is not supported on Android"); - } - } - - static promptForPushNotificationsWithUserResponse(callback) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'ios') { - invariant( - typeof callback === 'function', - 'Must provide a valid callback' - ); - RNOneSignal.promptForPushNotificationsWithUserResponse(callback); - } else { - console.log("This function is not supported on Android"); - } - } - - static requestPermissions(permissions) { - if (!checkIfInitialized()) return; - - var requestedPermissions = {}; - if (Platform.OS === 'ios') { - if (permissions) { - requestedPermissions = { - alert: !!permissions.alert, - badge: !!permissions.badge, - sound: !!permissions.sound - }; - } else { - requestedPermissions = { - alert: true, - badge: true, - sound: true - }; - } - RNOneSignal.requestPermissions(requestedPermissions); - } else { - console.log("This function is not supported on Android"); - } - } - - /* deprecated */ - static configure() { - console.warn("OneSignal: the `configure` method has been deprecated. The `ids` event is now triggered automatically."); - } - - static init(appId, iOSSettings) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'ios') { - RNOneSignal.initWithAppId(appId, iOSSettings); - } else { - RNOneSignal.init(appId); - } - } - - static checkPermissions(callback) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'ios') { - invariant( - typeof callback === 'function', - 'Must provide a valid callback' - ); - RNOneSignal.checkPermissions(callback); - } else { - console.log("This function is not supported on Android"); - } - } - - static promptForPushNotificationPermissions(callback) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'ios') { - RNOneSignal.promptForPushNotificationPermissions(callback); - } else { - console.log('This function is not supported on Android'); - } - } - - static getPermissionSubscriptionState(callback) { - if (!checkIfInitialized()) return; - - invariant( - typeof callback === 'function', - 'Must provide a valid callback' - ); - RNOneSignal.getPermissionSubscriptionState(callback); - } - - static sendTag(key, value) { - if (!checkIfInitialized()) return; - - if (typeof value === "boolean") { - value = value.toString(); - } - - RNOneSignal.sendTag(key, value); - } - - static sendTags(tags) { - if (!checkIfInitialized()) return; - - Object.keys(tags).forEach((key)=>{ - if (typeof tags[key] === "boolean"){ - tags[key] = tags[key].toString(); - } - }) - - RNOneSignal.sendTags(tags || {}); - } - - static getTags(next) { - if (!checkIfInitialized()) return; - - RNOneSignal.getTags(next); - } - - static deleteTag(key) { - if (!checkIfInitialized()) return; - - RNOneSignal.deleteTag(key); - } - - static enableVibrate(enable) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'android') { - RNOneSignal.enableVibrate(enable); - } else { - console.log("This function is not supported on iOS"); - } - } - - static enableSound(enable) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'android') { - RNOneSignal.enableSound(enable); - } else { - console.log("This function is not supported on iOS"); - } - } - - static setEmail(email, emailAuthCode, callback) { - if (!checkIfInitialized()) return; - - if (emailAuthCode === undefined) - emailAuthCode = null; - - if (callback === undefined) - callback = function(){}; - - RNOneSignal.setEmail(email, emailAuthCode, callback); - } - - static logoutEmail(callback) { - if (!checkIfInitialized()) return; - - invariant( - typeof callback === 'function', - 'Must provide a valid callback' - ); - - RNOneSignal.logoutEmail(callback); - } - - static setLocationShared(shared) { - if (!checkIfInitialized()) return; - - RNOneSignal.setLocationShared(shared); - } - - static setSubscription(enable) { - if (!checkIfInitialized()) return; - - RNOneSignal.setSubscription(enable); - } - - static promptLocation() { - if (!checkIfInitialized()) return; - - //Supported in both iOS & Android - RNOneSignal.promptLocation(); - } - - static inFocusDisplaying(displayOption) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'android') { - //Android: Set Display option of the notifications. displayOption is of type OSInFocusDisplayOption - // 0 -> None, 1 -> InAppAlert, 2 -> Notification - RNOneSignal.inFocusDisplaying(displayOption); - } else { - //iOS: displayOption is a number, 0 -> None, 1 -> InAppAlert, 2 -> Notification - RNOneSignal.setInFocusDisplayType(displayOption); - } - } - - static postNotification(contents, data, player_id, otherParameters) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'android') - RNOneSignal.postNotification(JSON.stringify(contents), JSON.stringify(data), JSON.stringify(player_id), JSON.stringify(otherParameters)); - else - RNOneSignal.postNotification(contents, data, player_id, otherParameters); - } - - static clearOneSignalNotifications() { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'android') { - RNOneSignal.clearOneSignalNotifications(); - } else { - console.log("This function is not supported on iOS"); - } - } - - static cancelNotification(id) { - if (!checkIfInitialized()) return; - - if (Platform.OS === 'android') { - RNOneSignal.cancelNotification(id); - } else { - console.log("This function is not supported on iOS"); - } - } - - //Sends MD5 and SHA1 hashes of the user's email address (https://documentation.onesignal.com/docs/ios-sdk-api#section-synchashedemail) - static syncHashedEmail(email) { - if (!checkIfInitialized()) return; - - RNOneSignal.syncHashedEmail(email); - } - - static setLogLevel(nsLogLevel, visualLogLevel) { - if (!checkIfInitialized()) return; - - RNOneSignal.setLogLevel(nsLogLevel, visualLogLevel); - } - - static setRequiresUserPrivacyConsent(required) { - if (!checkIfInitialized()) return; - - RNOneSignal.setRequiresUserPrivacyConsent(required); - } - - static provideUserConsent(granted) { - if (!checkIfInitialized()) return; - - RNOneSignal.provideUserConsent(granted); - } - - static userProvidedPrivacyConsent() { - if (!checkIfInitialized()) return; - - //returns a promise - return RNOneSignal.userProvidedPrivacyConsent(); - } - - static setExternalUserId(externalId, callback) { - if (!checkIfInitialized()) return; - - if (callback === undefined) - callback = function(){}; - - RNOneSignal.setExternalUserId(externalId, callback); - } - - static removeExternalUserId(callback) { - if (!checkIfInitialized()) return; - - if (callback === undefined) - callback = function(){}; - - RNOneSignal.removeExternalUserId(callback); - } - - /** - * In-App Messaging - */ - - // Pass a String key and any value and creates a trigger map to pass to addTriggers() - static addTrigger(key, value) { - if (!checkIfInitialized()) return; - - var trigger = {}; - trigger[key] = value; - RNOneSignal.addTriggers(trigger); - } - - - // Expected format is Map, make sure all values are Objects and keys are Strings - static addTriggers(triggers) { - if (!checkIfInitialized()) return; - - RNOneSignal.addTriggers(triggers); - } - - static removeTriggersForKeys(keys) { - if (!checkIfInitialized()) return; - - RNOneSignal.removeTriggersForKeys(keys); - } - - static removeTriggerForKey(key) { - if (!checkIfInitialized()) return; - - RNOneSignal.removeTriggerForKey(key); - } - - static getTriggerValueForKey(key) { - // must return a promise - if (!checkIfInitialized()) return Promise.resolve(); - - return RNOneSignal.getTriggerValueForKey(key); - } - - static pauseInAppMessages(pause) { - if (!checkIfInitialized()) return; - - RNOneSignal.pauseInAppMessages(pause); - } - - /** - * Outcomes - */ - - static sendOutcome(name, callback=function(){}) { - if (!checkIfInitialized()) return; - - invariant( - typeof callback === 'function', - 'Must provide a valid callback' - ); - - RNOneSignal.sendOutcome(name, callback); - } - - static sendUniqueOutcome(name, callback=function(){}) { - if (!checkIfInitialized()) return; - - invariant( - typeof callback === 'function', - 'Must provide a valid callback' - ); - - RNOneSignal.sendUniqueOutcome(name, callback); - } - - static sendOutcomeWithValue(name, value, callback=function(){}) { - if (!checkIfInitialized()) return; - - invariant( - typeof callback === 'function', - 'Must provide a valid callback' - ); - - RNOneSignal.sendOutcomeWithValue(name, Number(value), callback); - } -} diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..1f703f95 --- /dev/null +++ b/src/index.js @@ -0,0 +1,424 @@ +'use strict'; + +import { NativeModules, Platform } from 'react-native'; +import EventManager from './EventManager'; +import { + PERMISSION_CHANGED, + SUBSCRIPTION_CHANGED, + IN_APP_MESSAGE_CLICKED, + NOTIFICATION_WILL_SHOW, + NOTIFICATION_OPENED, + EMAIL_SUBSCRIPTION_CHANGED +} from './events'; +import { isValidCallback, checkIfInitialized } from './helpers'; + +const RNOneSignal = NativeModules.OneSignal; +const eventManager = new EventManager(RNOneSignal); + +export default class OneSignal { + /* I N I T I A L I Z A T I O N */ + + /** + * Sets the OneSignal application Id. 1/2 of the initialization process. + * @param {string} appId + */ + static setAppId(appId) { + RNOneSignal.setAppId(appId); + } + + /* O B S E R V E R S */ + + static addPermissionObserver(observer) { + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(observer); + if (Platform.OS === 'android') { + RNOneSignal.addPermissionObserver(); + } + eventManager.addEventHandler(PERMISSION_CHANGED, observer); + } + + static addSubscriptionObserver(observer) { + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(observer); + if (Platform.OS === 'android') { + RNOneSignal.addSubscriptionObserver(); + } + eventManager.addEventHandler(SUBSCRIPTION_CHANGED, observer); + } + + static addEmailSubscriptionObserver(observer) { + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(observer); + if (Platform.OS === 'android') { + RNOneSignal.addEmailSubscriptionObserver(); + } + eventManager.addEventHandler(EMAIL_SUBSCRIPTION_CHANGED, observer); + } + + /* H A N D L E R S */ + + /** + * Sets the handler that fires before the notification is displayed + * Callback parameter is a `NotificationReceivedEvent` with: + * - notification data + * - `complete` function that accepts the `NotificationReceivedEvent` + * @param {function} handler + */ + static setNotificationWillShowInForegroundHandler(handler){ + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(handler); + RNOneSignal.setNotificationWillShowInForegroundHandler(); + eventManager.setEventHandler(NOTIFICATION_WILL_SHOW, handler); + } + + static setNotificationOpenedHandler(handler){ + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(handler); + + RNOneSignal.setNotificationOpenedHandler(); + eventManager.setEventHandler(NOTIFICATION_OPENED, handler); + } + + /* R E G I S T R A T I O N E T C */ + + static registerForPushNotifications() { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'ios') { + RNOneSignal.registerForPushNotifications(); + } else { + console.log("registerForPushNotifications: this function is not supported on Android"); + } + } + + static promptForPushNotificationsWithUserResponse(handler) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'ios') { + isValidCallback(handler); + RNOneSignal.promptForPushNotificationsWithUserResponse(handler); + } else { + console.log("promptForPushNotificationsWithUserResponse: this function is not supported on Android"); + } + } + + static requestPermissions(permissions) { + if (!checkIfInitialized(RNOneSignal)) return; + + let requestedPermissions = {}; + if (Platform.OS === 'ios') { + if (permissions) { + requestedPermissions = { + alert: !!permissions.alert, + badge: !!permissions.badge, + sound: !!permissions.sound + }; + } else { + requestedPermissions = { + alert: true, + badge: true, + sound: true + }; + } + RNOneSignal.requestPermissions(requestedPermissions); + } else { + console.log("requestPermissions: this function is not supported on Android"); + } + } + + static promptForPushNotificationPermissions(handler) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'ios') { + RNOneSignal.promptForPushNotificationPermissions(handler); + } else { + console.log('promptForPushNotificationPermissions: this function is not supported on Android'); + } + } + + static disablePush(disable) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.disablePush(disable); + } + + static setLocationShared(shared) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.setLocationShared(shared); + } + + static promptLocation() { + if (!checkIfInitialized(RNOneSignal)) return; + + //Supported in both iOS & Android + RNOneSignal.promptLocation(); + } + + /* D E V I C E I N F O */ + + /** + * Gets the device state. + * // TO DO: add more details here + */ + static getDeviceState() { + // TODO: check if we need to return promise? + if (!checkIfInitialized(RNOneSignal)) return Promise.resolve(); + const deviceState = await RNOneSignal.getDeviceState(); + + if (Platform.OS === 'android') { + deviceState['hasNotificationPermission'] = deviceState['areNotificationsEnabled']; + delete deviceState['areNotificationsEnabled']; + } + + return deviceState; + } + + static getPermissionSubscriptionState(handler) { + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(handler); + RNOneSignal.getPermissionSubscriptionState(handler); + } + + static userProvidedPrivacyConsent() { + if (!checkIfInitialized(RNOneSignal)) return; + + //returns a promise + return RNOneSignal.userProvidedPrivacyConsent(); + } + + /* T A G S */ + + static sendTag(key, value) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (typeof value === "boolean") { + value = value.toString(); + } + + RNOneSignal.sendTag(key, value); + } + + static sendTags(tags) { + if (!checkIfInitialized(RNOneSignal)) return; + + Object.keys(tags).forEach((key)=>{ + if (typeof tags[key] === "boolean"){ + tags[key] = tags[key].toString(); + } + }) + + RNOneSignal.sendTags(tags || {}); + } + + static getTags(next) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.getTags(next); + } + + static deleteTag(key) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.deleteTag(key); + } + + static deleteTags(tags) { + if (!checkIfInitialized(RNOneSignal)) return; + + Object.keys(tags).forEach((key)=>{ + if (typeof tags[key] === "boolean"){ + tags[key] = tags[key].toString(); + } + }) + + RNOneSignal.deleteTags(tags || {}); + } + + /* V I B R A T I O N */ + + static enableVibrate(enable) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'android') { + RNOneSignal.enableVibrate(enable); + } else { + console.log("This function is not supported on iOS"); + } + } + + static enableSound(enable) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'android') { + RNOneSignal.enableSound(enable); + } else { + console.log("This function is not supported on iOS"); + } + } + + /* E M A I L */ + + static setEmail(email, emailAuthCode, handler) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (emailAuthCode === undefined) + emailAuthCode = null; + + if (handler === undefined) + handler = function(){}; + + RNOneSignal.setEmail(email, emailAuthCode, handler); + } + + static logoutEmail(handler) { + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(handler); + RNOneSignal.logoutEmail(handler); + } + + /* N O T I F I C A T I O N S */ + + static postNotification(contents, data, player_id, otherParameters) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'android') + RNOneSignal.postNotification(JSON.stringify(contents), JSON.stringify(data), JSON.stringify(player_id), JSON.stringify(otherParameters)); + else + RNOneSignal.postNotification(contents, data, player_id, otherParameters); + } + + static clearOneSignalNotifications() { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'android') { + RNOneSignal.clearOneSignalNotifications(); + } else { + console.log("clearOneSignalNotifications: this function is not supported on iOS"); + } + } + + static cancelNotification(id) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (Platform.OS === 'android') { + RNOneSignal.cancelNotification(id); + } else { + console.log("cancelNotification: this function is not supported on iOS"); + } + } + + /* E X T E R N A L U S E R I D */ + + static setExternalUserId(externalId, handler) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (handler === undefined) + handler = function(){}; + + RNOneSignal.setExternalUserId(externalId, handler); + } + + static removeExternalUserId(handler) { + if (!checkIfInitialized(RNOneSignal)) return; + + if (handler === undefined) + handler = function(){}; + + RNOneSignal.removeExternalUserId(handler); + } + + /* I N A P P M E S S A G I N G */ + + static setInAppMessageClickHandler(handler) { + if (!checkIfInitialized(RNOneSignal)) return; + isValidCallback(handler); + + if (Platform.OS === 'android') { + RNOneSignal.initInAppMessageClickHandlerParams(); + } + + RNOneSignal.setInAppMessageClickHandler(); + eventManager.setEventHandler(IN_APP_MESSAGE_CLICKED, handler); + } + + // Pass a String key and any value and creates a trigger map to pass to addTriggers() + static addTrigger(key, value) { + if (!checkIfInitialized(RNOneSignal)) return; + + let trigger = {}; + trigger[key] = value; + RNOneSignal.addTriggers(trigger); + } + + + // Expected format is Map, make sure all values are Objects and keys are Strings + static addTriggers(triggers) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.addTriggers(triggers); + } + + static removeTriggersForKeys(keys) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.removeTriggersForKeys(keys); + } + + static removeTriggerForKey(key) { + if (!checkIfInitialized(RNOneSignal)) return; + RNOneSignal.removeTriggerForKey(key); + } + + static getTriggerValueForKey(key) { + // must return a promise + if (!checkIfInitialized(RNOneSignal)) return Promise.resolve(); + return RNOneSignal.getTriggerValueForKey(key); + } + + static pauseInAppMessages(pause) { + if (!checkIfInitialized(RNOneSignal)) return; + RNOneSignal.pauseInAppMessages(pause); + } + + /* O U T C O M E S */ + + static sendOutcome(name, handler=function(){}) { + if (!checkIfInitialized(RNOneSignal)) return; + RNOneSignal.sendOutcome(name, handler); + } + + static sendUniqueOutcome(name, handler=function(){}) { + if (!checkIfInitialized(RNOneSignal)) return; + RNOneSignal.sendUniqueOutcome(name, handler); + } + + static sendOutcomeWithValue(name, value, handler=function(){}) { + if (!checkIfInitialized(RNOneSignal)) return; + RNOneSignal.sendOutcomeWithValue(name, Number(value), handler); + } + + /* O T H E R F U N C T I O N S */ + + static setLogLevel(nsLogLevel, visualLogLevel) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.setLogLevel(nsLogLevel, visualLogLevel); + } + + static clearHandlers() { + eventManager.clearHandlers(); + } + + static setRequiresUserPrivacyConsent(required) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.setRequiresUserPrivacyConsent(required); + } + + static provideUserConsent(granted) { + if (!checkIfInitialized(RNOneSignal)) return; + + RNOneSignal.provideUserConsent(granted); + } +} From cb6dd6d05b4f420fd79cf18cc6b7f609399ff8b5 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 4 Sep 2020 17:59:52 -0500 Subject: [PATCH 02/69] RNOneSignal java bridge implementation --- .../rnonesignalandroid/RNOneSignal.java | 312 ++++++++++++------ 1 file changed, 210 insertions(+), 102 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 299462ec..98d40523 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -1,77 +1,132 @@ +/* +Modified MIT License + +Copyright 2020 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. + +Authors: + - Avishay Bar (creator) - 1/31/16 + - Brad Hesse + - Josh Kasten + - Rodrigo Gomez-Palacio + - Michael DiCioccio +*/ + package com.geektime.rnonesignalandroid; import java.util.Iterator; +import java.util.HashMap; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.content.pm.ApplicationInfo; -import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.modules.core.DeviceEventManagerModule; -import com.facebook.react.bridge.Promise; -import com.onesignal.OSInAppMessageAction; + +import com.onesignal.OSEmailSubscriptionStateChanges; +import com.onesignal.OneSignal; +import com.onesignal.OutcomeEvent; +import com.onesignal.OSDeviceState; import com.onesignal.OSPermissionState; -import com.onesignal.OSPermissionSubscriptionState; +import com.onesignal.OSInAppMessageAction; +import com.onesignal.OSNotification; +import com.onesignal.OSNotificationReceivedEvent; +import com.onesignal.OSNotificationOpenedResult; +import com.onesignal.OneSignal.OutcomeCallback; +import com.onesignal.OneSignal.EmailUpdateError; +import com.onesignal.OSNotificationGenerationJob; + import com.onesignal.OSSubscriptionState; import com.onesignal.OSEmailSubscriptionState; -import com.onesignal.OneSignal; +import com.onesignal.OSPermissionSubscriptionState; + import com.onesignal.OneSignal.EmailUpdateHandler; -import com.onesignal.OneSignal.EmailUpdateError; +import com.onesignal.OneSignal.OSInAppMessageClickHandler; +import com.onesignal.OneSignal.OSNotificationOpenedHandler; import com.onesignal.OneSignal.OSExternalUserIdUpdateCompletionHandler; import com.onesignal.OneSignal.OutcomeCallback; - -import com.onesignal.OneSignal.InAppMessageClickHandler; -import com.onesignal.OneSignal.NotificationOpenedHandler; -import com.onesignal.OneSignal.NotificationReceivedHandler; -import com.onesignal.OSNotificationOpenResult; -import com.onesignal.OSNotification; +import com.onesignal.OneSignal.OSInAppMessageClickHandler; import com.onesignal.OutcomeEvent; +import com.onesignal.OSDeviceState; + +import com.onesignal.OSPermissionObserver; +import com.onesignal.OSSubscriptionObserver; +import com.onesignal.OSEmailSubscriptionObserver; + +import com.onesignal.OSPermissionStateChanges; +import com.onesignal.OSSubscriptionStateChanges; +import com.onesignal.OSEmailSubscriptionObserver; import org.json.JSONObject; import org.json.JSONArray; import org.json.JSONException; +public class RNOneSignal extends ReactContextBaseJavaModule + implements + OSPermissionObserver, + OSSubscriptionObserver, + OSNotificationOpenedHandler, + OSEmailSubscriptionObserver, + LifecycleEventListener, + OSInAppMessageClickHandler +{ -/** - * Created by Avishay on 1/31/16. - */ -public class RNOneSignal extends ReactContextBaseJavaModule implements LifecycleEventListener, NotificationReceivedHandler, NotificationOpenedHandler, InAppMessageClickHandler { public static final String HIDDEN_MESSAGE_KEY = "hidden"; private ReactApplicationContext mReactApplicationContext; private ReactContext mReactContext; + private boolean oneSignalInitDone; private boolean registeredEvents = false; - private OSNotificationOpenResult coldStartNotificationResult; private OSInAppMessageAction inAppMessageActionResult; + private HashMap notificationReceivedEventCache; + private boolean hasSetNotificationOpenedHandler = false; private boolean hasSetInAppClickedHandler = false; private boolean hasSetRequiresPrivacyConsent = false; private boolean waitingForUserPrivacyConsent = false; - //ensure only one callback exists at a given time due to react-native restriction + // A native module is supposed to invoke its callback only once. It can, however, store the callback and invoke it later. + // It is very important to highlight that the callback is not invoked immediately after the native function completes + // - remember that bridge communication is asynchronous, and this too is tied to the run loop. + // Once you have done invoke() on the callback, you cannot use it again. Store it here. private Callback pendingGetTagsCallback; - - public RNOneSignal(ReactApplicationContext reactContext) { - super(reactContext); - mReactApplicationContext = reactContext; - mReactContext = reactContext; - mReactContext.addLifecycleEventListener(this); - initOneSignal(); - } + private Callback inAppMessageClickedCallback; private String appIdFromManifest(ReactApplicationContext context) { try { @@ -84,23 +139,6 @@ private String appIdFromManifest(ReactApplicationContext context) { } } - // Initialize OneSignal only once when an Activity is available. - // React creates an instance of this class to late for OneSignal to get the current Activity - // based on registerActivityLifecycleCallbacks it uses to listen for the first Activity. - // However it seems it is also to soon to call getCurrentActivity() from the reactContext as well. - // This will normally succeed when onHostResume fires instead. - private void initOneSignal() { - // Uncomment to debug init issues. - // OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.ERROR); - - OneSignal.sdkType = "react"; - - String appId = appIdFromManifest(mReactApplicationContext); - - if (appId != null && appId.length() > 0) - init(appId); - } - private void sendEvent(String eventName, Object params) { mReactContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) @@ -111,8 +149,21 @@ private JSONObject jsonFromErrorMessageString(String errorMessage) throws JSONEx return new JSONObject().put("error", errorMessage); } - @ReactMethod - public void init(String appId) { + public RNOneSignal(ReactApplicationContext reactContext) { + super(reactContext); + mReactApplicationContext = reactContext; + mReactContext = reactContext; + mReactContext.addLifecycleEventListener(this); + notificationReceivedEventCache = new HashMap(); + } + + // Initialize OneSignal only once when an Activity is available. + // React creates an instance of this class to late for OneSignal to get the current Activity + // based on registerActivityLifecycleCallbacks it uses to listen for the first Activity. + // However it seems it is also to soon to call getCurrentActivity() from the reactContext as well. + // This will normally succeed when onHostResume fires instead. + private void initOneSignal() { + OneSignal.sdkType = "react"; Context context = mReactApplicationContext.getCurrentActivity(); if (oneSignalInitDone) { @@ -122,7 +173,6 @@ public void init(String appId) { oneSignalInitDone = true; - OneSignal.sdkType = "react"; if (context == null) { // in some cases, especially when react-native-navigation is installed, @@ -130,13 +180,65 @@ public void init(String appId) { context = mReactApplicationContext.getApplicationContext(); } - OneSignal.getCurrentOrNewInitBuilder().setInAppMessageClickHandler(this); - OneSignal.init(context, null, appId, this, this); + OneSignal.setInAppMessageClickHandler(this); + OneSignal.initWithContext(context); if (this.hasSetRequiresPrivacyConsent) this.waitingForUserPrivacyConsent = true; } + @ReactMethod + public void setAppId(String appId) { + OneSignal.setAppId(appId); + } + + /* Observers */ + @Override + public void onOSPermissionChanged(OSPermissionStateChanges stateChanges) { + Log.e("Onesignal", "sending permission change event"); + sendEvent("OneSignal-permissionChanged", RNUtils.jsonToWritableMap(stateChanges.toJSONObject())); + } + + @Override + public void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges) { + Log.e("Onesignal", "sending subscription change event"); + sendEvent("OneSignal-subscriptionChanged", RNUtils.jsonToWritableMap(stateChanges.toJSONObject())); + } + + @Override + public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateChanges) { + Log.e("Onesignal", "sending email subscription change event"); + sendEvent("OneSignal-emailSubscriptionChanged", RNUtils.jsonToWritableMap(stateChanges.toJSONObject())); + } + + @ReactMethod + public void addPermissionObserver() { + OneSignal.addPermissionObserver(this); + } + + @ReactMethod + public void addSubscriptionObserver() { + OneSignal.addSubscriptionObserver(this); + } + + @ReactMethod + public void addEmailSubscriptionObserver() { + OneSignal.addEmailSubscriptionObserver(this); + } + + /* Other methods */ + + @ReactMethod + public void getDeviceState(Promise promise) { + OSDeviceState state = OneSignal.getDeviceState(); + promise.resolve(RNUtils.jsonToWritableMap(state.toJSONObject())); + } + + @ReactMethod + public void disablePush(boolean disable) { + OneSignal.disablePush(disable); + } + @ReactMethod public void sendTag(String key, String value) { OneSignal.sendTag(key, value); @@ -152,7 +254,7 @@ public void getTags(final Callback callback) { if (pendingGetTagsCallback == null) pendingGetTagsCallback = callback; - OneSignal.getTags(new OneSignal.GetTagsHandler() { + OneSignal.getTags(new OneSignal.OSGetTagsHandler() { @Override public void tagsAvailable(JSONObject tags) { if (pendingGetTagsCallback != null) @@ -201,20 +303,6 @@ public void onFailure(EmailUpdateError error) { }); } - @ReactMethod - public void idsAvailable() { - OneSignal.idsAvailable(new OneSignal.IdsAvailableHandler() { - public void idsAvailable(String userId, String registrationId) { - final WritableMap params = Arguments.createMap(); - - params.putString("userId", userId); - params.putString("pushToken", registrationId); - - sendEvent("OneSignal-idsAvailable", params); - } - }); - } - // TODO: This needs to be split out into several different callbacks to the JS and connect // to the correct native methods @ReactMethod @@ -257,13 +345,13 @@ public void getPermissionSubscriptionState(final Callback callback) { } @ReactMethod - public void inFocusDisplaying(int displayOption) { - OneSignal.setInFocusDisplaying(displayOption); + public void deleteTag(String key) { + OneSignal.deleteTag(key); } @ReactMethod - public void deleteTag(String key) { - OneSignal.deleteTag(key); + public void deleteTags(ReadableArray tags) { + OneSignal.deleteTags(RNUtils.convertReableArrayIntoStringCollection(tags)); } @ReactMethod @@ -276,21 +364,11 @@ public void enableSound(Boolean enable) { OneSignal.enableSound(enable); } - @ReactMethod - public void setSubscription(Boolean enable) { - OneSignal.setSubscription(enable); - } - @ReactMethod public void promptLocation() { OneSignal.promptLocation(); } - @ReactMethod - public void syncHashedEmail(String email) { - OneSignal.syncHashedEmail(email); - } - @ReactMethod public void setLogLevel(int logLevel, int visualLogLevel) { OneSignal.setLogLevel(logLevel, visualLogLevel); @@ -399,33 +477,46 @@ public void onComplete(JSONObject results) { }); } + /* notification opened / received */ + @ReactMethod - public void initNotificationOpenedHandlerParams() { - this.hasSetNotificationOpenedHandler = true; - if (this.coldStartNotificationResult != null) { - this.notificationOpened(this.coldStartNotificationResult); - this.coldStartNotificationResult = null; - } + public void setNotificationOpenedHandler() { + OneSignal.setNotificationOpenedHandler(this); } @Override - public void notificationReceived(OSNotification notification) { - this.sendEvent("OneSignal-remoteNotificationReceived", RNUtils.jsonToWritableMap(notification.toJSONObject())); + public void notificationOpened(OSNotificationOpenedResult result) { + sendEvent("OneSignal-remoteNotificationOpened", RNUtils.jsonToWritableMap(result.toJSONObject())); } - @Override - public void notificationOpened(OSNotificationOpenResult result) { - if (!this.hasSetNotificationOpenedHandler) { - this.coldStartNotificationResult = result; - return; - } - this.sendEvent("OneSignal-remoteNotificationOpened", RNUtils.jsonToWritableMap(result.toJSONObject())); + @ReactMethod + public void setNotificationWillShowInForegroundHandler() { + OneSignal.setNotificationWillShowInForegroundHandler(new OneSignal.OSNotificationWillShowInForegroundHandler() { + @Override + public void notificationWillShowInForeground(OSNotificationReceivedEvent notificationReceivedEvent) { + OSNotification notification = notificationReceivedEvent.getNotification(); + String notificationJobId = notification.getNotificationId(); + notificationReceivedEventCache.put(notificationJobId, notificationReceivedEvent); + + sendEvent("OneSignal-notificationWillShowInForeground", RNUtils.jsonToWritableMap(notificationReceivedEvent.toJSONObject())); + } + }); + } + + @ReactMethod + public void completeNotificationJob(String uuid) { + OSNotificationReceivedEvent receivedEvent = notificationReceivedEventCache.get(uuid); + OSNotification notification = receivedEvent.getNotification(); + receivedEvent.complete(notification); + notificationReceivedEventCache.remove(uuid); } /** * In-App Messaging */ + /* triggers */ + @ReactMethod public void addTrigger(String key, Object object) { OneSignal.addTrigger(key, object); @@ -451,15 +542,26 @@ public void getTriggerValueForKey(String key, Promise promise) { promise.resolve(OneSignal.getTriggerValueForKey(key)); } + /* in app message click */ + @ReactMethod - public void pauseInAppMessages(Boolean pause) { - OneSignal.pauseInAppMessages(pause); + public void setInAppMessageClickHandler() { + OneSignal.setInAppMessageClickHandler(new OneSignal.OSInAppMessageClickHandler() { + @Override + public void inAppMessageClicked(OSInAppMessageAction result) { + if (!hasSetInAppClickedHandler) { + inAppMessageActionResult = result; + return; + } + sendEvent("OneSignal-inAppMessageClicked", RNUtils.jsonToWritableMap(result.toJSONObject())); + } + }); } @ReactMethod public void initInAppMessageClickHandlerParams() { this.hasSetInAppClickedHandler = true; - if (inAppMessageActionResult != null) { + if (this.inAppMessageActionResult != null) { this.inAppMessageClicked(this.inAppMessageActionResult); this.inAppMessageActionResult = null; } @@ -474,6 +576,13 @@ public void inAppMessageClicked(OSInAppMessageAction result) { this.sendEvent("OneSignal-inAppMessageClicked", RNUtils.jsonToWritableMap(result.toJSONObject())); } + /* other IAM functions */ + + @ReactMethod + public void pauseInAppMessages(Boolean pause) { + OneSignal.pauseInAppMessages(pause); + } + /** * Outcomes */ @@ -533,7 +642,7 @@ public void onSuccess(OutcomeEvent outcomeEvent) { } /** - * Overrides + * Native Module Overrides */ @Override @@ -555,5 +664,4 @@ public void onHostPause() { public void onHostResume() { initOneSignal(); } - } From 6b5118d870365e943716feb888d5803b0dd83f68 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 8 Sep 2020 17:53:06 -0500 Subject: [PATCH 03/69] RNNotificationJob implementation --- .../rnonesignalandroid/RNNotificationJob.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java new file mode 100644 index 00000000..3bffd8e4 --- /dev/null +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java @@ -0,0 +1,21 @@ +package com.geektime.rnonesignalandroid; +import com.facebook.react.bridge.ReactContextBaseJavaModule; + +public class RNNotificationJob extends ReactContextBaseJavaModule { + public additionalData; + private notificationJob; + + RNNotificationJob(AppNotificationGenerationJob notificationJob) { + JSONObject additionalData = notificationJob.getAdditionalData(); + this.notificationJob = notificationJob; + } + + @ReactMethod + public JSONObject + + @ReactMethod + public void complete(WhateverObject object){ + // mapping + this.notificationJob.complete(object); + } +} \ No newline at end of file From 2ca196fdfc9617f285866c0f4cd194dd857f36cd Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 11 Sep 2020 17:28:44 -0500 Subject: [PATCH 04/69] Removed `RNNotificationJob` After discussion, we decided we didn't need this class anymore to pursue the following strategy: For the setNotificationWillShowInForegroundHandler, * We want to store the callback on the JS side * We want to store the notification job on the native side * We can then have a separate function on the JS side that will call a native bridge method to complete the notification job * We want to store the notification jobs on the native side with UUIDs since multiple notifications can come in --- .../rnonesignalandroid/RNNotificationJob.java | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java deleted file mode 100644 index 3bffd8e4..00000000 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNNotificationJob.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.geektime.rnonesignalandroid; -import com.facebook.react.bridge.ReactContextBaseJavaModule; - -public class RNNotificationJob extends ReactContextBaseJavaModule { - public additionalData; - private notificationJob; - - RNNotificationJob(AppNotificationGenerationJob notificationJob) { - JSONObject additionalData = notificationJob.getAdditionalData(); - this.notificationJob = notificationJob; - } - - @ReactMethod - public JSONObject - - @ReactMethod - public void complete(WhateverObject object){ - // mapping - this.notificationJob.complete(object); - } -} \ No newline at end of file From 23281a95b8bb0db74f40757978831fd6bcd9520a Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 11 Sep 2020 23:56:01 -0500 Subject: [PATCH 05/69] Update iOS EventEmitter --- ios/RCTOneSignal/RCTOneSignalEventEmitter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.h b/ios/RCTOneSignal/RCTOneSignalEventEmitter.h index 0d86542a..63f98dd4 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.h +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.h @@ -22,7 +22,7 @@ typedef NS_ENUM(NSInteger, OSNotificationEventTypes) { InAppMessageClicked }; -#define OSNotificationEventTypesArray @[@"OneSignal-remoteNotificationReceived",@"OneSignal-remoteNotificationOpened",@"OneSignal-idsAvailable",@"OneSignal-emailSubscription",@"OneSignal-inAppMessageClicked"] +#define OSNotificationEventTypesArray @[@"OneSignal-notificationOpened",@"OneSignal-emailSubscription",@"OneSignal-inAppMessageClicked"] #define OSEventString(enum) [OSNotificationEventTypesArray objectAtIndex:enum] @interface RCTOneSignalEventEmitter : RCTEventEmitter From a6d3c541575fa18fb6f9b413ca11a124cb1b0ab6 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 15 Sep 2020 22:04:32 -0500 Subject: [PATCH 06/69] NotificationReceivedEvent Implementation Encapsulates the notification data as well as the `complete` function which triggers the completion of the notification display. Used in the `notificationWillShowInForegroundHandler` --- src/NotificationReceivedEvent.js | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/NotificationReceivedEvent.js diff --git a/src/NotificationReceivedEvent.js b/src/NotificationReceivedEvent.js new file mode 100644 index 00000000..b4b3e824 --- /dev/null +++ b/src/NotificationReceivedEvent.js @@ -0,0 +1,58 @@ +import { NativeModules, Platform } from 'react-native'; +const RNOneSignal = NativeModules.OneSignal; + +export default class NotificationReceivedEvent { + constructor(receivedEvent){ + this.body = receivedEvent.body; + this.sound = receivedEvent.sound; + this.title = receivedEvent.title; + this.launchURL = receivedEvent.launchURL; + this.rawPayload = receivedEvent.rawPayload; + this.actionButtons = receivedEvent.actionButtons; + this.additionalData = receivedEvent.additionalData; + this.notificationId = receivedEvent.notificationId; + + if (Platform.OS === 'android') { + this.groupKey = receivedEvent.groupKey; + this.ledColor = receivedEvent.ledColor; + this.priority = receivedEvent.priority; + this.smallIcon = receivedEvent.smallIcon; + this.largeIcon = receivedEvent.largeIcon; + this.bigPicture = receivedEvent.bigPicture; + this.collapseId = receivedEvent.collapseId; + this.groupMessage = receivedEvent.groupMessage; + this.fromProjectNumber = receivedEvent.fromProjectNumber; + this.smallIconAccentColor = receivedEvent.smallIconAccentColor; + this.lockScreenVisibility = receivedEvent.lockScreenVisibililty; + this.androidNotificationId = receivedEvent.androidNotificationId; + } + + if (Platform.OS = 'ios') { + this.badge = receivedEvent.badge; + this.category = receivedEvent.category; + this.threadId = receivedEvent.threadId; + this.subtitle = receivedEvent.subtitle; + this.templateId = receivedEvent.templateId; + this.attachments = receivedEvent.attachments; + this.templateName = receivedEvent.templateName; + this.actionButtons = receivedEvent.actionButtons; + this.mutableContent = receivedEvent.mutableContent; + this.badgeIncrement = receivedEvent.badgeIncrement; + this.contentAvailable = receivedEvent.contentAvailable; + } + } + + complete(notificationReceivedEvent) { + if (!notificationReceivedEvent) { + // if the notificationReceivedEvent is null, we want to call the native-side + // complete/completion with null to silence the notification + RNOneSignal.completeNotificationEvent(this.notificationId, false); + return; + } + + // if the notificationReceivedEvent is not null, we want to pass the specific event + // future: Android side: make the notification modifiable + // iOS & Android: the notification id is associated with the native-side complete handler / completion block + RNOneSignal.completeNotificationEvent(notificationReceivedEvent.notificationId, true); + } +} \ No newline at end of file From be13f7d0549467187b91f8ee07c0c32d4b423c89 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 15 Sep 2020 22:19:20 -0500 Subject: [PATCH 07/69] EventManager Implementation Manages everything related to events including the event emitter. - `setupListeners` - `clearListeners` - `setEventHandler` - `generateEventListener` - `getFinalPayload` --- src/EventManager.js | 105 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/EventManager.js diff --git a/src/EventManager.js b/src/EventManager.js new file mode 100644 index 00000000..092e7b2e --- /dev/null +++ b/src/EventManager.js @@ -0,0 +1,105 @@ +import { NativeEventEmitter } from 'react-native'; +import NotificationReceivedEvent from './NotificationReceivedEvent'; +import { isMultipleInstancesPossible } from './helpers'; +import { + PERMISSION_CHANGED, + SUBSCRIPTION_CHANGED, + NOTIFICATION_WILL_SHOW, + NOTIFICATION_OPENED, + IN_APP_MESSAGE_CLICKED, + EMAIL_SUBSCRIPTION_CHANGED +} from './events'; + +const eventList = [ + PERMISSION_CHANGED, + SUBSCRIPTION_CHANGED, + NOTIFICATION_WILL_SHOW, + NOTIFICATION_OPENED, + IN_APP_MESSAGE_CLICKED, + EMAIL_SUBSCRIPTION_CHANGED +] + +export default class EventManager { + constructor(RNOneSignal) { + this.RNOneSignal = RNOneSignal; + this.notificationCache = new Map(); + this.oneSignalEventEmitter = new NativeEventEmitter(RNOneSignal); + this.eventHandlerMap = new Map(); // used for setters (single replacable callback) + this.eventHandlerArrayMap = new Map(); // used for adders (multiple callbacks possible) + this.listeners = []; + this.setupListeners(); + } + + setupListeners() { + // set up the event emitter and listeners + if (this.RNOneSignal != null) { + + for(let i = 0; i < eventList.length; i++) { + let eventName = eventList[i]; + this.listeners[eventName] = this.generateEventListener(eventName); + } + } + } + + // clear handlers + clearHandlers() { + this.eventHandlerMap = new Map(); + this.eventHandlerArrayMap = new Map(); + } + + /** + * Sets the event handler on the JS side of the bridge + * Supports only one handler at a time + * @param {string} eventName + * @param {function} handler + */ + setEventHandler(eventName, handler) { + this.eventHandlerMap.set(eventName, handler); + } + + /** + * Adds the event handler to the corresponding handler array on the JS side of the bridge + * @param {string} eventName + * @param {function} handler + */ + addEventHandler(eventName, handler) { + let handlerArray = this.eventHandlerArrayMap.get(eventName); + handlerArray && handlerArray.length > 0 ? handlerArray.push(handler) : this.eventHandlerArrayMap.set(eventName, [handler]); + } + + // returns an event listener with the js to native mapping + generateEventListener(eventName) { + const addListenerCallback = (payload) => { + if (isMultipleInstancesPossible(eventName)) { + // used for adders + let handlerArray = this.eventHandlerArrayMap.get(eventName); + if (handlerArray) { + handlerArray.forEach(handler => { + handler(payload); + }); + } + } else { + // used for setters + let handler = this.eventHandlerMap.get(eventName); + payload = this.getFinalPayload(eventName, payload); + + // Check if we have added listener for this type yet + if (handler) { + handler(payload); + } + } + }; + + return this.oneSignalEventEmitter.addListener(eventName, addListenerCallback); + } + + getFinalPayload(eventName, payload) { + switch(eventName) { + case NOTIFICATION_WILL_SHOW: + return new NotificationReceivedEvent(payload); + default: + return payload; + } + } +} + From 49ad07e45735d60c54cc66b95a0af2e38a20e36f Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 15 Sep 2020 22:19:58 -0500 Subject: [PATCH 08/69] File with event string constants --- src/events.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/events.js diff --git a/src/events.js b/src/events.js new file mode 100644 index 00000000..e2a3c398 --- /dev/null +++ b/src/events.js @@ -0,0 +1,7 @@ +// events +export const NOTIFICATION_WILL_SHOW = 'OneSignal-notificationWillShowInForeground'; +export const NOTIFICATION_OPENED = 'OneSignal-remoteNotificationOpened' +export const IN_APP_MESSAGE_CLICKED = 'OneSignal-inAppMessageClicked'; +export const PERMISSION_CHANGED = 'OneSignal-permissionChanged'; +export const SUBSCRIPTION_CHANGED = 'OneSignal-subscriptionChanged'; +export const EMAIL_SUBSCRIPTION_CHANGED = 'OneSignal-emailSubscriptionChanged'; \ No newline at end of file From b873c756e2f513a0c4afede47ec6ddc743697394 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 15 Sep 2020 22:28:07 -0500 Subject: [PATCH 09/69] Package Update * Updated main (index.js) location in package.json * Added jsconfig file for VS Code detection --- jsconfig.json | 12 ++++++++++++ package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 jsconfig.json diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 00000000..f6a389bf --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6" + }, + "exclude": [ + "node_modules", + "android", + "examples", + "ios" + ] +} diff --git a/package.json b/package.json index d5ec6979..4d56695d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "react-native-onesignal", "version": "3.9.1", "description": "React Native OneSignal SDK", - "main": "index", + "main": "src/index", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, From 86ceb9aa56477a133a584a1440ce5225f4032185 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 16 Sep 2020 15:51:13 -0500 Subject: [PATCH 10/69] Helpers Functions Implementation --- src/helpers.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/helpers.js diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 00000000..d5cbccbc --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,33 @@ +import invariant from 'invariant'; +import { + PERMISSION_CHANGED, + SUBSCRIPTION_CHANGED, + EMAIL_SUBSCRIPTION_CHANGED +} from './events'; + +export function isValidCallback(handler) { + invariant( + typeof handler === 'function', + 'Must provide a valid callback' + ); +} + +export function checkIfInitialized(object) { + const initialized = object != null; + return initialized; +} + +/** + * Returns whether the handler associated with the event name can have multiple instances set + * @param {String} eventName + */ +export function isMultipleInstancesPossible(eventName) { + switch(eventName){ + case PERMISSION_CHANGED: + case SUBSCRIPTION_CHANGED: + case EMAIL_SUBSCRIPTION_CHANGED: + return true; + default: + return false; + } +} From 39b92885b5514b0817f34bf0aff9b5672bfe736b Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 17 Sep 2020 18:52:20 -0500 Subject: [PATCH 11/69] RCTOneSignalEventEmitter implmentation --- ios/RCTOneSignal/RCTOneSignalEventEmitter.h | 14 +-- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 94 +++++++++++---------- 2 files changed, 58 insertions(+), 50 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.h b/ios/RCTOneSignal/RCTOneSignalEventEmitter.h index 63f98dd4..ceafdd6c 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.h +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.h @@ -13,16 +13,16 @@ #endif typedef NS_ENUM(NSInteger, OSNotificationEventTypes) { - NotificationReceived, + PermissionChanged, + SubscriptionChanged, + NotificationWillShowInForeground, NotificationOpened, - IdsAvailable, -// Subscription, -// Permission, - EmailSubscriptionChanged, - InAppMessageClicked + InAppMessageClicked, + EmailSubscriptionChanged }; -#define OSNotificationEventTypesArray @[@"OneSignal-notificationOpened",@"OneSignal-emailSubscription",@"OneSignal-inAppMessageClicked"] +#define OSNotificationEventTypesArray @[@"OneSignal-permissionChanged",@"OneSignal-subscriptionChanged",@"OneSignal-notificationWillShowInForeground",@"OneSignal-remoteNotificationOpened",@"OneSignal-inAppMessageClicked",@"OneSignal-emailSubscriptionChanged"] + #define OSEventString(enum) [OSNotificationEventTypesArray objectAtIndex:enum] @interface RCTOneSignalEventEmitter : RCTEventEmitter diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 7dd937e9..5a37870e 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -13,6 +13,8 @@ @implementation RCTOneSignalEventEmitter { BOOL hasListeners; + NSMutableDictionary* notificationCompletionCache; + NSMutableDictionary* receivedNotificationCache; } static BOOL _didStartObserving = false; @@ -38,6 +40,8 @@ +(BOOL)requiresMainQueueSetup { -(instancetype)init { if (self = [super init]) { [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Initialized RCTOneSignalEventEmitter"]; + notificationCompletionCache = [NSMutableDictionary new]; + receivedNotificationCache = [NSMutableDictionary new]; for (NSString *eventName in [self supportedEvents]) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitEvent:) name:eventName object:nil]; @@ -103,12 +107,16 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { resolve(@(!OneSignal.requiresUserPrivacyConsent)); } -RCT_EXPORT_METHOD(initWithAppId:(NSString *)appId settings:(NSDictionary *)settings) { +RCT_EXPORT_METHOD(initialize) { dispatch_async(dispatch_get_main_queue(), ^{ - [[RCTOneSignal sharedInstance] configureWithAppId:appId settings:settings]; + [[RCTOneSignal sharedInstance] initOneSignal]; }); } +RCT_EXPORT_METHOD(setAppId:(NSString* _Nonnull)newAppId) { + [OneSignal setAppId:newAppId]; +} + RCT_EXPORT_METHOD(promptForPushNotificationPermissions:(RCTResponseSenderBlock)callback) { [OneSignal promptForPushNotificationsWithUserResponse:^(BOOL accepted) { callback(@[@(accepted)]); @@ -173,6 +181,42 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { } } +RCT_REMAP_METHOD(getDeviceState, + getDeviceStateResolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + OSDeviceState *deviceState = [OneSignal getDeviceState]; + + if (deviceState) { + resolve([deviceState jsonRepresentation]); + } else { + NSError * error = nil; + NSString * message = @"Could not get OneSignal device state"; + reject(@"no_value", message, error); + } +} + +RCT_EXPORT_METHOD(setNotificationOpenedHandler) { + [OneSignal setNotificationOpenedHandler:^(OSNotificationOpenedResult *result) { + [RCTOneSignalEventEmitter sendEventWithName:@"OneSignal-remoteNotificationOpened" withBody:[result jsonRepresentation]]; + }]; +} + +RCT_EXPORT_METHOD(setNotificationWillShowInForegroundHandler) { + [OneSignal setNotificationWillShowInForegroundHandler:^(OSNotification *notif, OSNotificationDisplayResponse completion) { + self->receivedNotificationCache[notif.notificationId] = notif; + self->notificationCompletionCache[notif.notificationId] = completion; + [RCTOneSignalEventEmitter sendEventWithName:@"OneSignal-notificationWillShowInForeground" withBody:[notif jsonRepresentation]]; + }]; +} + +RCT_EXPORT_METHOD(completeNotificationJob:(NSString*)notificationId) { + OSNotification *notif = self->receivedNotificationCache[notificationId]; + OSNotificationDisplayResponse completion = self->notificationCompletionCache[notificationId]; + dispatch_async(dispatch_get_main_queue(), ^{ + completion(notif); + }); +} + RCT_EXPORT_METHOD(setEmail:(NSString *)email withAuthHash:(NSString *)authHash withResponse:(RCTResponseSenderBlock)callback) { // Auth hash token created on server and sent to client. [OneSignal setEmail:email withEmailAuthHashToken:authHash withSuccess:^{ @@ -236,14 +280,6 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { }]); } -RCT_EXPORT_METHOD(setInFocusDisplayType:(int)displayType) { - [OneSignal setInFocusDisplayType:displayType]; -} - -RCT_EXPORT_METHOD(registerForPushNotifications) { - [OneSignal registerForPushNotifications]; -} - RCT_EXPORT_METHOD(promptForPushNotificationsWithUserResponse:(RCTResponseSenderBlock)callback) { [OneSignal promptForPushNotificationsWithUserResponse:^(BOOL accepted) { [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Prompt For Push Notifications Success"]; @@ -255,18 +291,6 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal sendTag:key value:value]; } -RCT_EXPORT_METHOD(idsAvailable) { - [OneSignal IdsAvailable:^(NSString* userId, NSString* pushToken) { - - NSDictionary *params = @{ - @"pushToken": pushToken ?: [NSNull null], - @"userId" : userId ?: [NSNull null] - }; - - [RCTOneSignalEventEmitter sendEventWithName:@"OneSignal-idsAvailable" withBody:params]; - }]; -} - RCT_EXPORT_METHOD(sendTags:(NSDictionary *)properties) { [OneSignal sendTags:properties onSuccess:^(NSDictionary *sucess) { [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Send Tags Success"]; @@ -292,8 +316,8 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal deleteTag:key]; } -RCT_EXPORT_METHOD(setSubscription:(BOOL)enable) { - [OneSignal setSubscription:enable]; +RCT_EXPORT_METHOD(disablePush:(BOOL)disabled) { + [OneSignal disablePush:disabled]; } RCT_EXPORT_METHOD(promptLocation) { @@ -326,10 +350,6 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal postNotification:notification]; } -RCT_EXPORT_METHOD(syncHashedEmail:(NSString*)email) { - [OneSignal syncHashedEmail:email]; -} - RCT_EXPORT_METHOD(setLogLevel:(int)logLevel visualLogLevel:(int)visualLogLevel) { [OneSignal setLogLevel:logLevel visualLevel:visualLogLevel]; } @@ -360,16 +380,9 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { }]; } -RCT_EXPORT_METHOD(initNotificationOpenedHandlerParams) { - // Not implemented in iOS -} - /* * In-App Messaging */ -RCT_EXPORT_METHOD(initInAppMessageClickHandlerParams) { - // Not implemented in iOS -} RCT_EXPORT_METHOD(addTriggers:(NSDictionary *)triggers) { [OneSignal addTriggers:triggers]; @@ -383,13 +396,14 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal removeTriggerForKey:key]; } +// to do, check this still works RCT_REMAP_METHOD(getTriggerValueForKey, key:(NSString *)key getTriggerValueForKeyResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { NSString *val = [OneSignal getTriggerValueForKey:key]; - + if (val) { resolve(val); } else { @@ -405,13 +419,7 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_EXPORT_METHOD(setInAppMessageClickHandler) { [OneSignal setInAppMessageClickHandler:^(OSInAppMessageAction *action) { - NSDictionary *result = @{ - @"clickName": action.clickName ?: [NSNull null], - @"clickUrl" : action.clickUrl.absoluteString ?: [NSNull null], - @"firstClick" : @(action.firstClick), - @"closesMessage" : @(action.closesMessage) - }; - [RCTOneSignalEventEmitter sendEventWithName:@"OneSignal-inAppMessageClicked" withBody:result]; + [RCTOneSignalEventEmitter sendEventWithName:@"OneSignal-inAppMessageClicked" withBody:[action jsonRepresentation]]; }]; } From 937d4ddfeff54106f920863bcf2ff49aec632073 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 29 Sep 2020 13:53:47 -0500 Subject: [PATCH 12/69] iOS - RCTOneSignal implementation --- ios/RCTOneSignal/RCTOneSignal.h | 6 +- ios/RCTOneSignal/RCTOneSignal.m | 122 +++++++++----------------------- 2 files changed, 36 insertions(+), 92 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignal.h b/ios/RCTOneSignal/RCTOneSignal.h index 536da8d7..bf9039ba 100644 --- a/ios/RCTOneSignal/RCTOneSignal.h +++ b/ios/RCTOneSignal/RCTOneSignal.h @@ -13,10 +13,6 @@ @property (nonatomic) BOOL didStartObserving; -- (void)configureWithAppId:(NSString *)appId; -- (void)configureWithAppId:(NSString *)appId settings:(NSDictionary*)settings; - -- (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appId settings:(NSDictionary*)settings __deprecated_msg(INIT_DEPRECATION_NOTICE); -- (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appId __deprecated_msg(INIT_DEPRECATION_NOTICE); +- (void)initOneSignal; @end diff --git a/ios/RCTOneSignal/RCTOneSignal.m b/ios/RCTOneSignal/RCTOneSignal.m index 93e0a3ab..c6c8ac55 100644 --- a/ios/RCTOneSignal/RCTOneSignal.m +++ b/ios/RCTOneSignal/RCTOneSignal.m @@ -42,101 +42,19 @@ + (RCTOneSignal *) sharedInstance { } - (void)initOneSignal { - [OneSignal setValue:@"react" forKey:@"mSDKType"]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBeginObserving) name:@"didSetBridge" object:nil]; - - [OneSignal initWithLaunchOptions:nil appId:nil handleNotificationReceived:^(OSNotification* notification) { - [self handleRemoteNotificationReceived:[notification stringify]]; - } handleNotificationAction:^(OSNotificationOpenedResult *result) { - if (!RCTOneSignal.sharedInstance.didStartObserving) - coldStartOSNotificationOpenedResult = result; - else - [self handleRemoteNotificationOpened:[result stringify]]; - - } settings:@{@"kOSSettingsKeyInOmitNoAppIdLogging" : @true, kOSSettingsKeyAutoPrompt : @false}]; //default autoPrompt to false since init will be called again - didInitialize = false; -} - -// deprecated init methods -// provides backwards compatibility -- (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appId { - return [self initWithLaunchOptions:launchOptions appId:appId settings:nil]; -} - -- (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appId settings:(NSDictionary*)settings { - [self configureWithAppId:appId settings:settings]; - - return self; -} - -- (void)didBeginObserving { - // To continue supporting deprecated initialization methods (which create a new RCTOneSignal instance), - // we will only access the didStartObserving property of the shared instance to avoid issues - RCTOneSignal.sharedInstance.didStartObserving = true; - - dispatch_async(dispatch_get_main_queue(), ^{ - if (coldStartOSNotificationOpenedResult) { - [self handleRemoteNotificationOpened:[coldStartOSNotificationOpenedResult stringify]]; - coldStartOSNotificationOpenedResult = nil; - } - }); -} -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)configureWithAppId:(NSString *)appId { - [self configureWithAppId:appId settings:nil]; -} - -- (void)configureWithAppId:(NSString *)appId settings:(NSDictionary*)settings { - if (didInitialize) return; - + didInitialize = true; [OneSignal addSubscriptionObserver:self]; [OneSignal addEmailSubscriptionObserver:self]; - [OneSignal initWithLaunchOptions:nil - appId:appId - handleNotificationReceived:^(OSNotification* notification) { - [self handleRemoteNotificationReceived:[notification stringify]]; - } - handleNotificationAction:^(OSNotificationOpenedResult *result) { - if (!RCTOneSignal.sharedInstance.didStartObserving) - coldStartOSNotificationOpenedResult = result; - else - [self handleRemoteNotificationOpened:[result stringify]]; - - } - settings:settings]; -} - --(void)onOSEmailSubscriptionChanged:(OSEmailSubscriptionStateChanges *)stateChanges { - [self sendEvent:OSEventString(EmailSubscriptionChanged) withBody:stateChanges.to.toDictionary]; -} - -- (void)onOSSubscriptionChanged:(OSSubscriptionStateChanges*)stateChanges { - - // Example of detecting subscribing to OneSignal - if (!stateChanges.from.subscribed && stateChanges.to.subscribed) { - //Subscribed for OneSignal push notifications! - } - - [self sendEvent:OSEventString(IdsAvailable) withBody:stateChanges.to.toDictionary]; -} - -- (void)handleRemoteNotificationReceived:(NSString *)notification { - NSDictionary *json = [self jsonObjectWithString:notification]; - - if (json) - [self sendEvent:OSEventString(NotificationReceived) withBody:json]; + [OneSignal initWithLaunchOptions:nil]; } - (void)handleRemoteNotificationOpened:(NSString *)result { NSDictionary *json = [self jsonObjectWithString:result]; - + if (json) [self sendEvent:OSEventString(NotificationOpened) withBody:json]; } @@ -145,12 +63,12 @@ - (NSDictionary *)jsonObjectWithString:(NSString *)jsonString { NSError *jsonError; NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError]; - + if (jsonError) { [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Unable to serialize JSON string into an object: %@", jsonError]]; return nil; } - + return json; } @@ -158,4 +76,34 @@ - (void)sendEvent:(NSString *)eventName withBody:(NSDictionary *)body { [RCTOneSignalEventEmitter sendEventWithName:eventName withBody:body]; } +- (void)onOSSubscriptionChanged:(OSSubscriptionStateChanges * _Nonnull)stateChanges { + [self sendEvent:OSEventString(SubscriptionChanged) withBody:stateChanges.to.toDictionary]; +} + +- (void)onOSEmailSubscriptionChanged:(OSEmailSubscriptionStateChanges * _Nonnull)stateChanges { + // Example of detecting subscribing to OneSignal + if (!stateChanges.from.subscribed && stateChanges.to.subscribed) { + //Subscribed for OneSignal push notifications! + } + + [self sendEvent:OSEventString(EmailSubscriptionChanged) withBody:stateChanges.to.toDictionary]; +} + +- (void)didBeginObserving { + // To continue supporting deprecated initialization methods (which create a new RCTOneSignal instance), + // we will only access the didStartObserving property of the shared instance to avoid issues + RCTOneSignal.sharedInstance.didStartObserving = true; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (coldStartOSNotificationOpenedResult) { + [self handleRemoteNotificationOpened:[coldStartOSNotificationOpenedResult stringify]]; + coldStartOSNotificationOpenedResult = nil; + } + }); +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + @end From 51381c25db789826550c4f30be8b5bc6cfa62f9f Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 29 Sep 2020 13:54:36 -0500 Subject: [PATCH 13/69] iOS: update OneSignal header --- ios/OneSignal.h | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/ios/OneSignal.h b/ios/OneSignal.h index 8bed5da8..1903afe6 100755 --- a/ios/OneSignal.h +++ b/ios/OneSignal.h @@ -1,21 +1,21 @@ /** Modified MIT License - - Copyright 2017 OneSignal - + + Copyright 2020 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 @@ -28,15 +28,15 @@ /** ### Setting up the SDK ### Follow the documentation from https://documentation.onesignal.com/docs/ios-sdk-setupto setup OneSignal in your app. - + ### API Reference ### Follow the documentation from https://documentation.onesignal.com/docs/ios-sdk-api for a detailed explanation of the API. - + ### Troubleshoot ### Follow the documentation from https://documentation.onesignal.com/docs/troubleshooting-ios to fix common problems. - + For help on how to upgrade your code from 1.* SDK to 2.*: https://documentation.onesignal.com/docs/upgrading-to-ios-sdk-20 - + ### More ### iOS Push Cert: https://documentation.onesignal.com/docs/generating-an-ios-push-certificate */ @@ -345,10 +345,6 @@ typedef NS_ENUM(NSInteger, OSNotificationPermission) { - (NSDictionary*)toDictionary; @end -@protocol OSSubscriptionObserver -- (void)onOSSubscriptionChanged:(OSSubscriptionStateChanges*)stateChanges; -@end - @protocol OSEmailSubscriptionObserver - (void)onOSEmailSubscriptionChanged:(OSEmailSubscriptionStateChanges*)stateChanges; @end @@ -482,8 +478,6 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) { + (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; + (NSString*)sdk_version_raw; + (NSString*)sdk_semantic_version; @@ -520,8 +514,6 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) { + (void)syncHashedEmail:(NSString*)email __deprecated_msg("Please refer to our new Email methods/functionality such as setEmail(). This method will be removed in a future version of the OneSignal SDK"); // - Subscription and Permissions -+ (void)IdsAvailable:(OSIdsAvailableBlock)idsAvailableBlock __deprecated_msg("Please use getPermissionSubscriptionState or addSubscriptionObserver and addPermissionObserver instead."); - + (OSPermissionSubscriptionState*)getPermissionSubscriptionState; + (OSDevice*)getUserDevice; From b2f291cd3665be5e2bdb97022c8ce168552b89f0 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 30 Sep 2020 17:55:41 -0500 Subject: [PATCH 14/69] Update Example App --- examples/RNOneSignal/App.js | 254 +++++++++++++++--------------------- 1 file changed, 104 insertions(+), 150 deletions(-) diff --git a/examples/RNOneSignal/App.js b/examples/RNOneSignal/App.js index f777917d..8ef086b7 100644 --- a/examples/RNOneSignal/App.js +++ b/examples/RNOneSignal/App.js @@ -6,14 +6,13 @@ * @flow */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import { Platform, StyleSheet, Text, View, ScrollView, - ActivityIndicator, KeyboardAvoidingView, TextInput, Image, @@ -29,14 +28,15 @@ const disabledColor = '#BEBEBE'; /** Change to desired app id (dashboard app) + React Native Demo App: ce8572ae-ff57-4e77-a265-5c91f00ecc4c */ -var appId = '77e32082-ea27-42e3-a898-c72e141824ef'; +var appId = 'ce8572ae-ff57-4e77-a265-5c91f00ecc4c'; /** Controls whether the app needs privacy consent or not Will hide the button when false and show it when true */ -var requiresPrivacyConsent = true; +var requiresPrivacyConsent = false; export default class App extends Component { @@ -44,7 +44,7 @@ export default class App extends Component { super(properties); this.state = { - // OneSignal states + /* OneSignal states*/ // Privacy Consent states hasPrivacyConsent: false, // App starts without privacy consent isPrivacyConsentLoading: requiresPrivacyConsent, @@ -66,80 +66,84 @@ export default class App extends Component { isEmailLoading: false, // In-App Messaging states - iam_paused: false, - - // Add more states here... + iamPaused: false, // Demo App states debugText: '' + + // Add more states here... }; - // Log level logcat is 6 (VERBOSE) and log level alert is 0 (NONE) - OneSignal.setLogLevel(6, 0); + } - // Share location of device - OneSignal.setLocationShared(true); + /* R E A C T L I F E C Y C L E */ + async componentDidMount() { + console.log("Mounted!"); + /* O N E S I G N A L S E T U P */ + // Log level logcat is 6 (VERBOSE) and log level alert is 0 (NONE) + OneSignal.setLogLevel(6, 0); + OneSignal.setAppId(appId); OneSignal.setRequiresUserPrivacyConsent(requiresPrivacyConsent); - OneSignal.init(appId, { - kOSSettingsKeyAutoPrompt: true, + OneSignal.setLocationShared(true); + OneSignal.promptForPushNotificationsWithUserResponse(response => { + console.log("Prompt response:", response); + }); + /* O N E S I G N A L H A N D L E R S */ + OneSignal.setNotificationWillShowInForegroundHandler(notifReceived => { + console.log("OneSignal: notification will show in foreground:", notifReceived); + setTimeout(()=>notifReceived.complete(notifReceived), 0); + }); + OneSignal.setNotificationOpenedHandler(notification => { + console.log("OneSignal: notification opened:", notification); + }); + OneSignal.setInAppMessageClickHandler(event => { + console.log("OneSignal IAM clicked:", event); + }); + OneSignal.addEmailSubscriptionObserver((event) => { + console.log("OneSignal: email subscription changed: ", event); + }); + OneSignal.addSubscriptionObserver(event => { + console.log("OneSignal: subscription changed:", event); + if (Platform.OS === "android") { + this.setState({ isSubscribed: event.to.isSubscribed }); + } else { + this.setState({ isSubscribed: event.subscribed }); + } + }); + OneSignal.addPermissionObserver(event => { + console.log("OneSignal: permission changed:", event); }); - // Notifications will display as NOTIFICATION type - OneSignal.inFocusDisplaying(2); - - // If the app requires privacy consent check if it has been set yet + //If the app requires privacy consent check if it has been set yet if (requiresPrivacyConsent) { // async 'then' is only so I can sleep using the Promise helper method OneSignal.userProvidedPrivacyConsent().then(async (granted) => { // For UI testing purposes wait X seconds to see the loading state await sleep(0); - console.log('Privacy Consent status: ' + granted); + console.log('OneSignal: Privacy Consent status: ' + granted); this.setState({hasPrivacyConsent:granted, isPrivacyConsentLoading:false}); }); } - OneSignal.getPermissionSubscriptionState((response) => { - console.log('Device state:'); - console.log(response); - - let notificationsEnabled = response['notificationsEnabled']; - let isSubscribed = response['subscriptionEnabled']; - - this.setState({isSubscribed:notificationsEnabled && isSubscribed, isSubscriptionLoading:false}, () => { - OneSignal.setSubscription(isSubscribed); - }); - }); + let deviceState = await OneSignal.getDeviceState(); + this.setState({ isSubscribed: deviceState.isSubscribed }); // Examples for using native IAM public methods -// this.oneSignalInAppMessagingExamples(); + // this.oneSignalInAppMessagingExamples(); // Examples for using native Outcome Event public methods -// this.oneSignalOutcomeEventsExamples(); + // this.oneSignalOutcomeEventsExamples(); } - async componentDidMount() { - OneSignal.addEventListener('received', this.onNotificationReceived); - OneSignal.addEventListener('opened', this.onNotificationOpened); - OneSignal.addEventListener('ids', this.onIdsAvailable); -// OneSignal.addEventListener('subscription', this.onSubscriptionChange); -// OneSignal.addEventListener('permission', this.onPermissionChange); - OneSignal.addEventListener('emailSubscription', this.onEmailSubscriptionChange); - OneSignal.addEventListener('inAppMessageClicked', this.onInAppMessageClicked); - } - componentWillUnmount() { - OneSignal.removeEventListener('received', this.onNotificationReceived); - OneSignal.removeEventListener('opened', this.onNotificationOpened); - OneSignal.removeEventListener('ids', this.onIdsAvailable); -// OneSignal.removeEventListener('subscription', this.onSubscriptionChange); -// OneSignal.removeEventListener('permission', this.onPermissionChange); - OneSignal.removeEventListener('emailSubscription', this.onEmailSubscriptionChange); - OneSignal.removeEventListener('inAppMessageClicked', this.onInAppMessageClicked); + OneSignal.clearHandlers(); } + /* H E L P E R S */ + /** Validate email method */ @@ -211,87 +215,6 @@ export default class App extends Component { }); } - /** - When a notification is received this will fire - */ - onNotificationReceived = (notification) => { - console.log('Notification received: ', notification); - - let debugMsg = 'RECEIVED: \n' + JSON.stringify(notification, null, 2); - this.setState({debugText:debugMsg}, () => { - console.log("Debug text successfully changed!"); - }); - } - - /** - When a notification is opened this will fire - The openResult will contain information about the notification opened - */ - onNotificationOpened = (openResult) => { - console.log('Message: ', openResult.notification.payload.body); - console.log('Data: ', openResult.notification.payload.additionalData); - console.log('isActive: ', openResult.notification.isAppInFocus); - console.log('openResult: ', openResult); - - let debugMsg = 'OPENED: \n' + JSON.stringify(openResult.notification, null, 2); - this.setState({debugText:debugMsg}, () => { - console.log("Debug text successfully changed!"); - }); - } - - /** - Once the user is registered/updated the onIds will send back the userId and pushToken - of the device - */ - onIdsAvailable = (device) => { - console.log('Device info: ', device); - // Save the userId and pushToken for the device, important for updating the device - // record using the SDK, and sending notifications - this.setState({ - userId: device.userId, - pushToken: device.pushToken - }); - } - - /** - TODO: Needs to be implemented still in index.js and RNOneSignal.java - */ - onSubscriptionChange = (change) => { - console.log('onSubscriptionChange: ', change); - } - - /** - TODO: Needs to be implemented still in index.js and RNOneSignal.java - */ - onPermissionChange = (change) => { - console.log('onPermissionChange: ', change); - } - - /** - Success for the change of state for the email record? or setting subscription state of email record (so logging out)? - TODO: Validate functionality and make sure name is correct - Should match the onSubscriptionChange and - - TODO: Validate this is working, might be broken after changing name - */ - onEmailSubscriptionChange = (change) => { - console.log('onEmailSubscriptionChange: ', change); - this.setState({isEmailLoading:false}); - } - - /** - When an element on an IAM is clicked this will fire - The actionResult will contain information about the element clicked - */ - onInAppMessageClicked = (actionResult) => { - console.log('actionResult: ', actionResult); - - let debugMsg = 'CLICKED: \n' + JSON.stringify(actionResult, null, 2); - this.setState({debugText:debugMsg}, () => { - console.log("Debug text successfully changed!"); - }); - } - render() { return ( @@ -302,7 +225,7 @@ export default class App extends Component { { this.createPrivacyConsentFields() } { this.createEmailFields() } { this.createExternalUserIdFields() } - + { this.createSubscriptionElements() } @@ -376,10 +299,6 @@ export default class App extends Component { ); } - /** - ADD MORE GENERIC UI METHODS HERE... - */ - /** Create the fields for displaying information about the demo app and some instruction for modifying the demo app or react-native SDK @@ -432,7 +351,6 @@ export default class App extends Component { // States used through-out the subscription fields const { isSubscribed, - isSubscriptionLoading, isPrivacyConsentLoading } = this.state; @@ -441,15 +359,11 @@ export default class App extends Component { // Subscribe Button let subscribedButton = this.renderButtonView( isSubscribed ? "Unsubscribe" : "Subscribe", - isSubscriptionLoading || isPrivacyConsentLoading, + isPrivacyConsentLoading, () => { - let newSubscription = !isSubscribed; - this.setState({isSubscribed:newSubscription, isSubscriptionLoading: true}, () => { - OneSignal.setSubscription(newSubscription); - - // TODO: Move this into onSubscriptionChange method once implemented - this.setState({isSubscriptionLoading: false}); - }); + console.log(`Setting subscription to ${!isSubscribed}`); + OneSignal.disablePush(isSubscribed); + this.setState({isSubscribed: !isSubscribed}); } ); @@ -460,6 +374,28 @@ export default class App extends Component { return elements; } + createSubscriptionElements() { + let elements = []; + const { + isPrivacyConsentLoading + } = this.state; + + let getDeviceState = this.renderButtonView( + "Get Device State", + isPrivacyConsentLoading, + async () => { + let state = await OneSignal.getDeviceState(); + console.log("Device state:", state); + } + ); + + elements.push( + getDeviceState + ); + + return elements; + } + /** Create the fields necessary to test privacy consent with OneSignal SDK */ @@ -546,6 +482,7 @@ export default class App extends Component { OneSignal.logoutEmail((error) => { if (error) { console.log('Error while logging out email'); + //OneSignal.deleteTags(['a']); } else { console.log('Success logging out email'); } @@ -556,10 +493,31 @@ export default class App extends Component { } ); + let sendTagsButtons = this.renderButtonView( + "Send Tags", + isPrivacyConsentLoading, + () => { + const tags = {'a': 1, 'b':2, 'c':3}; + console.log(`Attempting to send tags ${JSON.stringify(tags)}`); + OneSignal.sendTags(tags); + } + ); + + let deleteTags = this.renderButtonView( + "Delete Tags", + isPrivacyConsentLoading, + () => { + console.log('Deleting tags'); + OneSignal.deleteTags(['b']); + } + ); + elements.push( emailTextInput, setEmailButton, - logoutEmailButton + logoutEmailButton, + sendTagsButtons, + deleteTags, ); return elements; @@ -632,13 +590,9 @@ export default class App extends Component { return elements; } - - /** - ADD MORE UI METHODS HERE... - */ - } +/* S T Y L E S */ const styles = StyleSheet.create({ scrollView: { backgroundColor: '#F5FCFF', From 9c951d2430323c3c85e8021e23a120e53888a51f Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 7 Oct 2020 14:42:07 -0500 Subject: [PATCH 15/69] Nits, remove extra whitespace --- ios/RCTOneSignal/UIApplication+RCTOnesignal.m | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ios/RCTOneSignal/UIApplication+RCTOnesignal.m b/ios/RCTOneSignal/UIApplication+RCTOnesignal.m index 12d4748e..a7a3102d 100644 --- a/ios/RCTOneSignal/UIApplication+RCTOnesignal.m +++ b/ios/RCTOneSignal/UIApplication+RCTOnesignal.m @@ -10,10 +10,10 @@ @implementation UIApplication(OneSignalReactNative) /* This UIApplication category ensures that OneSignal init() gets called at least one time - + If this did not occur, cold-start notifications would not trigger the React-Native 'opened' event and other miscellaneous problems would occur. - + First, we swizzle UIApplication's setDelegate method, to get notified when the app delegate is assigned. Then we swizzle UIApplication's didFinishLaunchingWithOptions() method. When this method gets called, it initializes the OneSignal SDK with a nil app ID. @@ -24,14 +24,14 @@ static void injectSelector(Class newClass, SEL newSel, Class addToClass, SEL mak Method newMeth = class_getInstanceMethod(newClass, newSel); IMP imp = method_getImplementation(newMeth); const char* methodTypeEncoding = method_getTypeEncoding(newMeth); - + BOOL successful = class_addMethod(addToClass, makeLikeSel, imp, methodTypeEncoding); if (!successful) { class_addMethod(addToClass, newSel, imp, methodTypeEncoding); newMeth = class_getInstanceMethod(addToClass, newSel); - + Method orgMeth = class_getInstanceMethod(addToClass, makeLikeSel); - + method_exchangeImplementations(orgMeth, newMeth); } } @@ -49,7 +49,6 @@ - (void) setOneSignalReactNativeDelegate:(id)delegate { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class delegateClass = [delegate class]; - injectSelector(self.class, @selector(oneSignalApplication:didFinishLaunchingWithOptions:), delegateClass, @selector(application:didFinishLaunchingWithOptions:)); [self setOneSignalReactNativeDelegate:delegate]; @@ -58,7 +57,6 @@ - (void) setOneSignalReactNativeDelegate:(id)delegate { - (BOOL)oneSignalApplication:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { [RCTOneSignal.sharedInstance initOneSignal]; - if ([self respondsToSelector:@selector(oneSignalApplication:didFinishLaunchingWithOptions:)]) return [self oneSignalApplication:application didFinishLaunchingWithOptions:launchOptions]; return YES; From 3dbefe99229caadd858af438094945ec63a40767 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 7 Oct 2020 18:52:30 -0500 Subject: [PATCH 16/69] Delete Tags Implementation For some reason, we never added the `deleteTags` method to the iOS bridge. For consistency, I removed the native call in the Android bridge and implemented `deleteTags` via the use of setting empty string with the `sendTags` function. --- .../geektime/rnonesignalandroid/RNOneSignal.java | 15 +++++---------- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 4 ++-- src/index.js | 15 +++------------ 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 98d40523..578f65ce 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -249,6 +249,11 @@ public void sendTags(ReadableMap tags) { OneSignal.sendTags(RNUtils.readableMapToJson(tags)); } + @ReactMethod + public void deleteTags(ReadableArray tagKeys) { + OneSignal.deleteTags(RNUtils.convertReableArrayIntoStringCollection(tagKeys)); + } + @ReactMethod public void getTags(final Callback callback) { if (pendingGetTagsCallback == null) @@ -344,16 +349,6 @@ public void getPermissionSubscriptionState(final Callback callback) { } } - @ReactMethod - public void deleteTag(String key) { - OneSignal.deleteTag(key); - } - - @ReactMethod - public void deleteTags(ReadableArray tags) { - OneSignal.deleteTags(RNUtils.convertReableArrayIntoStringCollection(tags)); - } - @ReactMethod public void enableVibrate(Boolean enable) { OneSignal.enableVibrate(enable); diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 5a37870e..7f0246a0 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -312,8 +312,8 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal setLocationShared:shared]; } -RCT_EXPORT_METHOD(deleteTag:(NSString *)key) { - [OneSignal deleteTag:key]; +RCT_EXPORT_METHOD(deleteTags:(NSArray *)keys) { + [OneSignal deleteTags:keys]; } RCT_EXPORT_METHOD(disablePush:(BOOL)disabled) { diff --git a/src/index.js b/src/index.js index 1f703f95..2bf7a683 100644 --- a/src/index.js +++ b/src/index.js @@ -213,26 +213,17 @@ export default class OneSignal { static getTags(next) { if (!checkIfInitialized(RNOneSignal)) return; - RNOneSignal.getTags(next); } static deleteTag(key) { if (!checkIfInitialized(RNOneSignal)) return; - - RNOneSignal.deleteTag(key); + RNOneSignal.deleteTags([key]); } - static deleteTags(tags) { + static deleteTags(tagKeys) { if (!checkIfInitialized(RNOneSignal)) return; - - Object.keys(tags).forEach((key)=>{ - if (typeof tags[key] === "boolean"){ - tags[key] = tags[key].toString(); - } - }) - - RNOneSignal.deleteTags(tags || {}); + RNOneSignal.deleteTags(tagKeys) } /* V I B R A T I O N */ From d29ee05f90ccb19325a31fb4665df45289ac3f22 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 8 Oct 2020 17:26:59 -0500 Subject: [PATCH 17/69] Remove `checkPermissions` & `getPermissionSubscriptionState` Motivation: These functions are now covered by `getDeviceState` functionality --- .../rnonesignalandroid/RNOneSignal.java | 41 ----------- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 73 ------------------- src/index.js | 9 --- 3 files changed, 123 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 578f65ce..b5ab1ebd 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -308,47 +308,6 @@ public void onFailure(EmailUpdateError error) { }); } - // TODO: This needs to be split out into several different callbacks to the JS and connect - // to the correct native methods - @ReactMethod - public void getPermissionSubscriptionState(final Callback callback) { - OSPermissionSubscriptionState state = OneSignal.getPermissionSubscriptionState(); - - if (state == null) - return; - - OSPermissionState permissionState = state.getPermissionStatus(); - OSSubscriptionState subscriptionState = state.getSubscriptionStatus(); - OSEmailSubscriptionState emailSubscriptionState = state.getEmailSubscriptionStatus(); - - // Notifications enabled for app? (Android Settings) - boolean notificationsEnabled = permissionState.getEnabled(); - - // User subscribed to OneSignal? (automatically toggles with notificationsEnabled) - boolean subscriptionEnabled = subscriptionState.getSubscribed(); - - // User's original subscription preference (regardless of notificationsEnabled) - boolean userSubscriptionEnabled = subscriptionState.getUserSubscriptionSetting(); - - try { - JSONObject result = new JSONObject(); - - result.put("notificationsEnabled", notificationsEnabled) - .put("subscriptionEnabled", subscriptionEnabled) - .put("userSubscriptionEnabled", userSubscriptionEnabled) - .put("pushToken", subscriptionState.getPushToken()) - .put("userId", subscriptionState.getUserId()) - .put("emailUserId", emailSubscriptionState.getEmailUserId()) - .put("emailAddress", emailSubscriptionState.getEmailAddress()); - - Log.d("onesignal", "permission subscription state: " + result.toString()); - - callback.invoke(RNUtils.jsonToWritableMap(result)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - @ReactMethod public void enableVibrate(Boolean enable) { OneSignal.enableVibrate(enable); diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 7f0246a0..da17727b 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -123,33 +123,6 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { }]; } -RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback) { - if (RCTRunningInAppExtension()) { - callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]); - return; - } - - __block NSUInteger types = 0; - - dispatch_sync(dispatch_get_main_queue(), ^{ - if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) { - types = [RCTSharedApplication() currentUserNotificationSettings].types; - } else { - -#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0 - types = [RCTSharedApplication() enabledRemoteNotificationTypes]; -#endif - - } - }); - - callback(@[@{ - @"alert": @((types & UIUserNotificationTypeAlert) > 0), - @"badge": @((types & UIUserNotificationTypeBadge) > 0), - @"sound": @((types & UIUserNotificationTypeSound) > 0), - }]); -} - RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions) { if (RCTRunningInAppExtension()) { return; @@ -234,52 +207,6 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { }]; } -RCT_EXPORT_METHOD(getPermissionSubscriptionState:(RCTResponseSenderBlock)callback) -{ - if (RCTRunningInAppExtension()) { - callback(@[@{ - @"hasPrompted": @NO, - @"notificationsEnabled": @NO, - @"subscriptionEnabled": @NO, - @"userSubscriptionEnabled": @NO, - @"pushToken": [NSNull null], - @"userId": [NSNull null], - @"emailUserId" : [NSNull null], - @"emailAddress" : [NSNull null], - @"emailSubscribed" : @false - }]); - } - - OSPermissionSubscriptionState *state = [OneSignal getPermissionSubscriptionState]; - OSPermissionState *permissionState = state.permissionStatus; - OSSubscriptionState *subscriptionState = state.subscriptionStatus; - OSEmailSubscriptionState *emailState = state.emailSubscriptionStatus; - - // Received push notification prompt? (iOS only property) - BOOL hasPrompted = permissionState.hasPrompted == 1; - - // Notifications enabled for app? (iOS Settings) - BOOL notificationsEnabled = permissionState.status == 2; - - // User subscribed to OneSignal? (automatically toggles with notificationsEnabled) - BOOL subscriptionEnabled = subscriptionState.subscribed == 1; - - // User's original subscription preference (regardless of notificationsEnabled) - BOOL userSubscriptionEnabled = subscriptionState.userSubscriptionSetting == 1; - - callback(@[@{ - @"hasPrompted": @(hasPrompted), - @"notificationsEnabled": @(notificationsEnabled), - @"subscriptionEnabled": @(subscriptionEnabled), - @"userSubscriptionEnabled": @(userSubscriptionEnabled), - @"pushToken": subscriptionState.pushToken ?: [NSNull null], - @"userId": subscriptionState.userId ?: [NSNull null], - @"emailUserId" : emailState.emailUserId ?: [NSNull null], - @"emailSubscribed" : @(emailState.subscribed), - @"emailAddress" : emailState.emailAddress ?: [NSNull null] - }]); -} - RCT_EXPORT_METHOD(promptForPushNotificationsWithUserResponse:(RCTResponseSenderBlock)callback) { [OneSignal promptForPushNotificationsWithUserResponse:^(BOOL accepted) { [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Prompt For Push Notifications Success"]; diff --git a/src/index.js b/src/index.js index 2bf7a683..436dd53d 100644 --- a/src/index.js +++ b/src/index.js @@ -159,10 +159,8 @@ export default class OneSignal { /** * Gets the device state. - * // TO DO: add more details here */ static getDeviceState() { - // TODO: check if we need to return promise? if (!checkIfInitialized(RNOneSignal)) return Promise.resolve(); const deviceState = await RNOneSignal.getDeviceState(); @@ -173,13 +171,6 @@ export default class OneSignal { return deviceState; } - - static getPermissionSubscriptionState(handler) { - if (!checkIfInitialized(RNOneSignal)) return; - isValidCallback(handler); - RNOneSignal.getPermissionSubscriptionState(handler); - } - static userProvidedPrivacyConsent() { if (!checkIfInitialized(RNOneSignal)) return; From 928f7f0367d799f05145f77cb1618af990ed5457 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 8 Oct 2020 17:57:57 -0500 Subject: [PATCH 18/69] Removed `enableVibrate` & `enableSound` Motivation: this was removed in the native SDK --- .../rnonesignalandroid/RNOneSignal.java | 10 ------- src/index.js | 26 +++---------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index b5ab1ebd..cdd0453f 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -308,16 +308,6 @@ public void onFailure(EmailUpdateError error) { }); } - @ReactMethod - public void enableVibrate(Boolean enable) { - OneSignal.enableVibrate(enable); - } - - @ReactMethod - public void enableSound(Boolean enable) { - OneSignal.enableSound(enable); - } - @ReactMethod public void promptLocation() { OneSignal.promptLocation(); diff --git a/src/index.js b/src/index.js index 436dd53d..7e977712 100644 --- a/src/index.js +++ b/src/index.js @@ -142,6 +142,8 @@ export default class OneSignal { RNOneSignal.disablePush(disable); } + /* L O C A T I O N */ + static setLocationShared(shared) { if (!checkIfInitialized(RNOneSignal)) return; @@ -160,7 +162,7 @@ export default class OneSignal { /** * Gets the device state. */ - static getDeviceState() { + static async getDeviceState() { if (!checkIfInitialized(RNOneSignal)) return Promise.resolve(); const deviceState = await RNOneSignal.getDeviceState(); @@ -217,28 +219,6 @@ export default class OneSignal { RNOneSignal.deleteTags(tagKeys) } - /* V I B R A T I O N */ - - static enableVibrate(enable) { - if (!checkIfInitialized(RNOneSignal)) return; - - if (Platform.OS === 'android') { - RNOneSignal.enableVibrate(enable); - } else { - console.log("This function is not supported on iOS"); - } - } - - static enableSound(enable) { - if (!checkIfInitialized(RNOneSignal)) return; - - if (Platform.OS === 'android') { - RNOneSignal.enableSound(enable); - } else { - console.log("This function is not supported on iOS"); - } - } - /* E M A I L */ static setEmail(email, emailAuthCode, handler) { From 62b0e5df8ea21437eca766e879f0b3ce5f76108e Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 9 Oct 2020 16:46:02 -0500 Subject: [PATCH 19/69] iOS: Renamed Completion Method / Added Underscores to Instance Vars Motivation: * Because the completion block needs to be called with _something_ otherwise it will auto-show after 25 seconds, we introduce a second parameter that's a boolean to dictate whether the notification should be displayed or should be silent. * We should also protect the completion block from attempting to fire if it is not found in the completion block cache * Cache cleanup: after the notification is either fired or silenced, we should clean the notification & corresponding completion block from our cache --- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 44 +++++++++++++-------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index da17727b..5b3ba9d4 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -12,9 +12,9 @@ @implementation RCTOneSignalEventEmitter { - BOOL hasListeners; - NSMutableDictionary* notificationCompletionCache; - NSMutableDictionary* receivedNotificationCache; + BOOL _hasListeners; + NSMutableDictionary* _notificationCompletionCache; + NSMutableDictionary* _receivedNotificationCache; } static BOOL _didStartObserving = false; @@ -40,8 +40,8 @@ +(BOOL)requiresMainQueueSetup { -(instancetype)init { if (self = [super init]) { [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Initialized RCTOneSignalEventEmitter"]; - notificationCompletionCache = [NSMutableDictionary new]; - receivedNotificationCache = [NSMutableDictionary new]; + _notificationCompletionCache = [NSMutableDictionary new]; + _receivedNotificationCache = [NSMutableDictionary new]; for (NSString *eventName in [self supportedEvents]) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitEvent:) name:eventName object:nil]; @@ -51,7 +51,7 @@ -(instancetype)init { } -(void)startObserving { - hasListeners = true; + _hasListeners = true; [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did start observing"]; [[NSNotificationCenter defaultCenter] postNotificationName:@"didSetBridge" object:nil]; @@ -60,7 +60,7 @@ -(void)startObserving { } -(void)stopObserving { - hasListeners = false; + _hasListeners = false; [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did stop observing"]; } @@ -77,7 +77,7 @@ -(void)stopObserving { #pragma mark Send Event Methods - (void)emitEvent:(NSNotification *)notification { - if (!hasListeners) { + if (!_hasListeners) { [OneSignal onesignal_Log:ONE_S_LL_WARN message:[NSString stringWithFormat:@"Attempted to send an event (%@) when no listeners were set.", notification.name]]; return; } @@ -176,18 +176,30 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_EXPORT_METHOD(setNotificationWillShowInForegroundHandler) { [OneSignal setNotificationWillShowInForegroundHandler:^(OSNotification *notif, OSNotificationDisplayResponse completion) { - self->receivedNotificationCache[notif.notificationId] = notif; - self->notificationCompletionCache[notif.notificationId] = completion; + self->_receivedNotificationCache[notif.notificationId] = notif; + self->_notificationCompletionCache[notif.notificationId] = completion; [RCTOneSignalEventEmitter sendEventWithName:@"OneSignal-notificationWillShowInForeground" withBody:[notif jsonRepresentation]]; }]; } -RCT_EXPORT_METHOD(completeNotificationJob:(NSString*)notificationId) { - OSNotification *notif = self->receivedNotificationCache[notificationId]; - OSNotificationDisplayResponse completion = self->notificationCompletionCache[notificationId]; - dispatch_async(dispatch_get_main_queue(), ^{ - completion(notif); - }); +RCT_EXPORT_METHOD(completeNotificationEvent:(NSString*)notificationId displayOption:(BOOL)shouldDisplay) { + OSNotificationDisplayResponse completion = self->_notificationCompletionCache[notificationId]; + if (!completion) { + [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"OneSignal (objc): could not find notification completion block with id: %@", notificationId]]; + return; + } + + if (shouldDisplay) { + OSNotification *notif = self->_receivedNotificationCache[notificationId]; + dispatch_async(dispatch_get_main_queue(), ^{ + completion(notif); + }); + } else { + completion(nil); + } + + [_notificationCompletionCache removeObjectForKey:notificationId]; + [_receivedNotificationCache removeObjectForKey:notificationId]; } RCT_EXPORT_METHOD(setEmail:(NSString *)email withAuthHash:(NSString *)authHash withResponse:(RCTResponseSenderBlock)callback) { From da2507572f5cae660f0f35a57aaa9ff9e011e600 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 9 Oct 2020 16:51:40 -0500 Subject: [PATCH 20/69] Android: rename notif complete method / add display control BOOL & more Motivation: * We moved the event object sent to JS in the `notificationWillShowInForeground` override method a level up since there is no need for the entire notificationReceivedEvent on the JS wrapper side * We added a `shouldDisplay` boolean to control display vs silencing of notifs * We now check that the cached `receivedEvent` pulled via the notif UUID is non-null and log an error if so --- .../rnonesignalandroid/RNOneSignal.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index cdd0453f..15941729 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -195,19 +195,19 @@ public void setAppId(String appId) { /* Observers */ @Override public void onOSPermissionChanged(OSPermissionStateChanges stateChanges) { - Log.e("Onesignal", "sending permission change event"); + Log.i("Onesignal", "sending permission change event"); sendEvent("OneSignal-permissionChanged", RNUtils.jsonToWritableMap(stateChanges.toJSONObject())); } @Override public void onOSSubscriptionChanged(OSSubscriptionStateChanges stateChanges) { - Log.e("Onesignal", "sending subscription change event"); + Log.i("Onesignal", "sending subscription change event"); sendEvent("OneSignal-subscriptionChanged", RNUtils.jsonToWritableMap(stateChanges.toJSONObject())); } @Override public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateChanges) { - Log.e("Onesignal", "sending email subscription change event"); + Log.i("Onesignal", "sending email subscription change event"); sendEvent("OneSignal-emailSubscriptionChanged", RNUtils.jsonToWritableMap(stateChanges.toJSONObject())); } @@ -439,19 +439,29 @@ public void setNotificationWillShowInForegroundHandler() { @Override public void notificationWillShowInForeground(OSNotificationReceivedEvent notificationReceivedEvent) { OSNotification notification = notificationReceivedEvent.getNotification(); - String notificationJobId = notification.getNotificationId(); - notificationReceivedEventCache.put(notificationJobId, notificationReceivedEvent); + String notificationId = notification.getNotificationId(); + notificationReceivedEventCache.put(notificationId, notificationReceivedEvent); - sendEvent("OneSignal-notificationWillShowInForeground", RNUtils.jsonToWritableMap(notificationReceivedEvent.toJSONObject())); + sendEvent("OneSignal-notificationWillShowInForeground", RNUtils.jsonToWritableMap(notification.toJSONObject())); } }); } @ReactMethod - public void completeNotificationJob(String uuid) { + public void completeNotificationEvent(final String uuid, final boolean shouldDisplay) { OSNotificationReceivedEvent receivedEvent = notificationReceivedEventCache.get(uuid); - OSNotification notification = receivedEvent.getNotification(); - receivedEvent.complete(notification); + + if (receivedEvent == null) { + Log.e("OneSignal (java): could not find cached notification received event with id "+uuid); + return; + } + + if (shouldDisplay) { + receivedEvent.complete(receivedEvent.getNotification()); + } else { + receivedEvent.complete(null); + } + notificationReceivedEventCache.remove(uuid); } From fd47d8cde0ec533c30bef24f63147c1e29274868 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 12 Oct 2020 20:13:47 -0500 Subject: [PATCH 21/69] Deduplicate Observers, added `onCatalystInstanceDestroy` Lifecycle Func Motivation: * This commit adds logic to de-duplicate observers from being added multiple times. * We also take advantage of the `onCatalystInstanceDestroy` React Native lifecycle function to remove all handlers and observers. This prevents the observers from staying mounted after reloading in a dev environment. --- .../rnonesignalandroid/RNOneSignal.java | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 15941729..8b23167f 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -119,6 +119,9 @@ public class RNOneSignal extends ReactContextBaseJavaModule private boolean hasSetNotificationOpenedHandler = false; private boolean hasSetInAppClickedHandler = false; private boolean hasSetRequiresPrivacyConsent = false; + private boolean hasSetSubscriptionObserver = false; + private boolean hasSetEmailSubscriptionObserver = false; + private boolean hasSetPermissionObserver = false; private boolean waitingForUserPrivacyConsent = false; // A native module is supposed to invoke its callback only once. It can, however, store the callback and invoke it later. @@ -139,6 +142,21 @@ private String appIdFromManifest(ReactApplicationContext context) { } } + private void removeObservers() { + OneSignal.removeEmailSubscriptionObserver(this); + OneSignal.removePermissionObserver(this); + OneSignal.removeSubscriptionObserver(this); + hasSetEmailSubscriptionObserver = false; + hasSetPermissionObserver = false; + hasSetSubscriptionObserver = false; + } + + private void removeHandlers() { + OneSignal.setInAppMessageClickHandler(null); + OneSignal.setNotificationOpenedHandler(null); + OneSignal.setNotificationWillShowInForegroundHandler(null); + } + private void sendEvent(String eventName, Object params) { mReactContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) @@ -213,17 +231,26 @@ public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateCh @ReactMethod public void addPermissionObserver() { - OneSignal.addPermissionObserver(this); + if (!hasSetPermissionObserver) { + OneSignal.addPermissionObserver(this); + hasSetSubscriptionObserver = true; + } } @ReactMethod public void addSubscriptionObserver() { - OneSignal.addSubscriptionObserver(this); + if (!hasSetSubscriptionObserver) { + OneSignal.addSubscriptionObserver(this); + hasSetSubscriptionObserver = true; + } } @ReactMethod public void addEmailSubscriptionObserver() { - OneSignal.addEmailSubscriptionObserver(this); + if (!hasSetEmailSubscriptionObserver) { + OneSignal.addEmailSubscriptionObserver(this); + hasSetEmailSubscriptionObserver = true; + } } /* Other methods */ @@ -452,7 +479,7 @@ public void completeNotificationEvent(final String uuid, final boolean shouldDis OSNotificationReceivedEvent receivedEvent = notificationReceivedEventCache.get(uuid); if (receivedEvent == null) { - Log.e("OneSignal (java): could not find cached notification received event with id "+uuid); + Log.e("OneSignal", "(java): could not find cached notification received event with id "+uuid); return; } @@ -606,7 +633,8 @@ public String getName() { @Override public void onHostDestroy() { - + removeHandlers(); + removeObservers(); } @Override @@ -618,4 +646,10 @@ public void onHostPause() { public void onHostResume() { initOneSignal(); } + + @Override + public void onCatalystInstanceDestroy() { + removeHandlers(); + removeObservers(); + } } From 96cbd42a670b28ffc850bcb417dc1a43216f0e83 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 14 Oct 2020 14:54:22 -0500 Subject: [PATCH 22/69] Added error logging for functions with easy-to-mistaken argument types Motivation: Some functions names are not obvious what the argument type should be or what it should look like. To facilitate this process as much as possible, we can do a simple type/format check in certain functions and log an error if the argument is incorrect. --- src/index.js | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 7e977712..2edab1e2 100644 --- a/src/index.js +++ b/src/index.js @@ -31,6 +31,7 @@ export default class OneSignal { static addPermissionObserver(observer) { if (!checkIfInitialized(RNOneSignal)) return; isValidCallback(observer); + if (Platform.OS === 'android') { RNOneSignal.addPermissionObserver(); } @@ -40,6 +41,7 @@ export default class OneSignal { static addSubscriptionObserver(observer) { if (!checkIfInitialized(RNOneSignal)) return; isValidCallback(observer); + if (Platform.OS === 'android') { RNOneSignal.addSubscriptionObserver(); } @@ -49,6 +51,7 @@ export default class OneSignal { static addEmailSubscriptionObserver(observer) { if (!checkIfInitialized(RNOneSignal)) return; isValidCallback(observer); + if (Platform.OS === 'android') { RNOneSignal.addEmailSubscriptionObserver(); } @@ -128,8 +131,8 @@ export default class OneSignal { static promptForPushNotificationPermissions(handler) { if (!checkIfInitialized(RNOneSignal)) return; - if (Platform.OS === 'ios') { + isValidCallback(handler); RNOneSignal.promptForPushNotificationPermissions(handler); } else { console.log('promptForPushNotificationPermissions: this function is not supported on Android'); @@ -185,6 +188,10 @@ export default class OneSignal { static sendTag(key, value) { if (!checkIfInitialized(RNOneSignal)) return; + if (!key || !value) { + console.error("OneSignal: sendTag: must include a key and a value"); + } + if (typeof value === "boolean") { value = value.toString(); } @@ -194,6 +201,11 @@ export default class OneSignal { static sendTags(tags) { if (!checkIfInitialized(RNOneSignal)) return; + let keys = Object.keys(tags); + + if (keys.length === 0) { + console.error(`OneSignal: sendTags: argument must be of type object of the form { key : 'value' }`); + } Object.keys(tags).forEach((key)=>{ if (typeof tags[key] === "boolean"){ @@ -211,11 +223,19 @@ export default class OneSignal { static deleteTag(key) { if (!checkIfInitialized(RNOneSignal)) return; + if (typeof key !== "string") { + console.error("OneSignal: deleteTag: key argument must be of type string"); + } RNOneSignal.deleteTags([key]); } static deleteTags(tagKeys) { if (!checkIfInitialized(RNOneSignal)) return; + + if (!Array.isArray(tagKeys)) { + console.error("OneSignal: deleteTags: argument must be of array type"); + } + RNOneSignal.deleteTags(tagKeys) } @@ -308,6 +328,10 @@ export default class OneSignal { static addTrigger(key, value) { if (!checkIfInitialized(RNOneSignal)) return; + if (!key || !value) { + console.error("OneSignal: addTrigger: must include a key and a value"); + } + let trigger = {}; trigger[key] = value; RNOneSignal.addTriggers(trigger); @@ -318,6 +342,12 @@ export default class OneSignal { static addTriggers(triggers) { if (!checkIfInitialized(RNOneSignal)) return; + let keys = Object.keys(triggers); + + if (keys.length === 0) { + console.error(`OneSignal: addTriggers: argument must be an object of the form { key : 'value' }`); + } + RNOneSignal.addTriggers(triggers); } From 401b86cc3a265f92e90c802190b165054fdac71a Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 15 Oct 2020 17:00:08 -0500 Subject: [PATCH 23/69] Code Cleanup, Exposed Observer Methods in ObjC Bridge --- ios/RCTOneSignal/RCTOneSignal.h | 2 +- ios/RCTOneSignal/RCTOneSignal.m | 21 ++------------------- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignal.h b/ios/RCTOneSignal/RCTOneSignal.h index bf9039ba..f1e615bb 100644 --- a/ios/RCTOneSignal/RCTOneSignal.h +++ b/ios/RCTOneSignal/RCTOneSignal.h @@ -7,7 +7,7 @@ #define INIT_DEPRECATION_NOTICE "Objective-C Initialization of the OneSignal SDK has been deprecated. Use JavaScript init instead." -@interface RCTOneSignal : NSObject +@interface RCTOneSignal : NSObject + (RCTOneSignal *) sharedInstance; diff --git a/ios/RCTOneSignal/RCTOneSignal.m b/ios/RCTOneSignal/RCTOneSignal.m index c6c8ac55..c4d1ca37 100644 --- a/ios/RCTOneSignal/RCTOneSignal.m +++ b/ios/RCTOneSignal/RCTOneSignal.m @@ -47,9 +47,6 @@ - (void)initOneSignal { return; didInitialize = true; - [OneSignal addSubscriptionObserver:self]; - [OneSignal addEmailSubscriptionObserver:self]; - [OneSignal initWithLaunchOptions:nil]; } - (void)handleRemoteNotificationOpened:(NSString *)result { @@ -81,25 +78,11 @@ - (void)onOSSubscriptionChanged:(OSSubscriptionStateChanges * _Nonnull)stateChan } - (void)onOSEmailSubscriptionChanged:(OSEmailSubscriptionStateChanges * _Nonnull)stateChanges { - // Example of detecting subscribing to OneSignal - if (!stateChanges.from.subscribed && stateChanges.to.subscribed) { - //Subscribed for OneSignal push notifications! - } - [self sendEvent:OSEventString(EmailSubscriptionChanged) withBody:stateChanges.to.toDictionary]; } -- (void)didBeginObserving { - // To continue supporting deprecated initialization methods (which create a new RCTOneSignal instance), - // we will only access the didStartObserving property of the shared instance to avoid issues - RCTOneSignal.sharedInstance.didStartObserving = true; - - dispatch_async(dispatch_get_main_queue(), ^{ - if (coldStartOSNotificationOpenedResult) { - [self handleRemoteNotificationOpened:[coldStartOSNotificationOpenedResult stringify]]; - coldStartOSNotificationOpenedResult = nil; - } - }); +- (void)onOSPermissionChanged:(OSPermissionStateChanges *)stateChanges { + [self sendEvent:OSEventString(PermissionChanged) withBody:stateChanges.to.toDictionary]; } - (void)dealloc { diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 5b3ba9d4..68b6c1f6 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -92,6 +92,18 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { #pragma mark Exported Methods +RCT_EXPORT_METHOD(addPermissionObserver) { + [OneSignal addPermissionObserver:[RCTOneSignal sharedInstance]]; +} + +RCT_EXPORT_METHOD(addSubscriptionObserver) { + [OneSignal addSubscriptionObserver:[RCTOneSignal sharedInstance]]; +} + +RCT_EXPORT_METHOD(addEmailSubscriptionObserver) { + [OneSignal addEmailSubscriptionObserver:[RCTOneSignal sharedInstance]]; +} + RCT_EXPORT_METHOD(setRequiresUserPrivacyConsent:(BOOL)required) { [OneSignal setRequiresUserPrivacyConsent:required]; } @@ -335,7 +347,6 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal removeTriggerForKey:key]; } -// to do, check this still works RCT_REMAP_METHOD(getTriggerValueForKey, key:(NSString *)key getTriggerValueForKeyResolver:(RCTPromiseResolveBlock)resolve @@ -362,6 +373,10 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { }]; } +RCT_EXPORT_METHOD(initInAppMessageClickHandlerParams) { + // iOS Stub +} + /* * Outcomes */ From 96a62a20e0d74836c52a8f1766c114551f66ca9e Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 15 Oct 2020 17:01:43 -0500 Subject: [PATCH 24/69] Removed Platform Checks in Index.js After Adding Observers to iOS --- src/index.js | 66 ++++------------------------------------------------ 1 file changed, 5 insertions(+), 61 deletions(-) diff --git a/src/index.js b/src/index.js index 2edab1e2..47150cc6 100644 --- a/src/index.js +++ b/src/index.js @@ -31,30 +31,21 @@ export default class OneSignal { static addPermissionObserver(observer) { if (!checkIfInitialized(RNOneSignal)) return; isValidCallback(observer); - - if (Platform.OS === 'android') { - RNOneSignal.addPermissionObserver(); - } + RNOneSignal.addPermissionObserver(); eventManager.addEventHandler(PERMISSION_CHANGED, observer); } static addSubscriptionObserver(observer) { if (!checkIfInitialized(RNOneSignal)) return; isValidCallback(observer); - - if (Platform.OS === 'android') { - RNOneSignal.addSubscriptionObserver(); - } + RNOneSignal.addSubscriptionObserver(); eventManager.addEventHandler(SUBSCRIPTION_CHANGED, observer); } static addEmailSubscriptionObserver(observer) { if (!checkIfInitialized(RNOneSignal)) return; isValidCallback(observer); - - if (Platform.OS === 'android') { - RNOneSignal.addEmailSubscriptionObserver(); - } + RNOneSignal.addEmailSubscriptionObserver(); eventManager.addEventHandler(EMAIL_SUBSCRIPTION_CHANGED, observer); } @@ -84,16 +75,6 @@ export default class OneSignal { /* R E G I S T R A T I O N E T C */ - static registerForPushNotifications() { - if (!checkIfInitialized(RNOneSignal)) return; - - if (Platform.OS === 'ios') { - RNOneSignal.registerForPushNotifications(); - } else { - console.log("registerForPushNotifications: this function is not supported on Android"); - } - } - static promptForPushNotificationsWithUserResponse(handler) { if (!checkIfInitialized(RNOneSignal)) return; @@ -105,40 +86,6 @@ export default class OneSignal { } } - static requestPermissions(permissions) { - if (!checkIfInitialized(RNOneSignal)) return; - - let requestedPermissions = {}; - if (Platform.OS === 'ios') { - if (permissions) { - requestedPermissions = { - alert: !!permissions.alert, - badge: !!permissions.badge, - sound: !!permissions.sound - }; - } else { - requestedPermissions = { - alert: true, - badge: true, - sound: true - }; - } - RNOneSignal.requestPermissions(requestedPermissions); - } else { - console.log("requestPermissions: this function is not supported on Android"); - } - } - - static promptForPushNotificationPermissions(handler) { - if (!checkIfInitialized(RNOneSignal)) return; - if (Platform.OS === 'ios') { - isValidCallback(handler); - RNOneSignal.promptForPushNotificationPermissions(handler); - } else { - console.log('promptForPushNotificationPermissions: this function is not supported on Android'); - } - } - static disablePush(disable) { if (!checkIfInitialized(RNOneSignal)) return; @@ -176,6 +123,7 @@ export default class OneSignal { return deviceState; } + static userProvidedPrivacyConsent() { if (!checkIfInitialized(RNOneSignal)) return; @@ -315,11 +263,7 @@ export default class OneSignal { static setInAppMessageClickHandler(handler) { if (!checkIfInitialized(RNOneSignal)) return; isValidCallback(handler); - - if (Platform.OS === 'android') { - RNOneSignal.initInAppMessageClickHandlerParams(); - } - + RNOneSignal.initInAppMessageClickHandlerParams(); RNOneSignal.setInAppMessageClickHandler(); eventManager.setEventHandler(IN_APP_MESSAGE_CLICKED, handler); } From 42451b11d322cad7ca5aead579d471c0eaded087 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 15 Oct 2020 19:12:01 -0500 Subject: [PATCH 25/69] New `OSNotification` class & `NotificationReceivedEvent` encapsulation Motivation: We want to be able to modify the notification in the future via the `notificationWillShowInForegroundHandler`. To do this, we can create an extra class `OSNotification` to better match with the native API (at least for Java). See App.js in this commit for an example --- examples/RNOneSignal/App.js | 7 +++-- src/NotificationReceivedEvent.js | 51 +++++++------------------------- src/OSNotification.js | 43 +++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 44 deletions(-) create mode 100644 src/OSNotification.js diff --git a/examples/RNOneSignal/App.js b/examples/RNOneSignal/App.js index 8ef086b7..e0bb138b 100644 --- a/examples/RNOneSignal/App.js +++ b/examples/RNOneSignal/App.js @@ -90,9 +90,10 @@ export default class App extends Component { console.log("Prompt response:", response); }); /* O N E S I G N A L H A N D L E R S */ - OneSignal.setNotificationWillShowInForegroundHandler(notifReceived => { - console.log("OneSignal: notification will show in foreground:", notifReceived); - setTimeout(()=>notifReceived.complete(notifReceived), 0); + OneSignal.setNotificationWillShowInForegroundHandler(notifReceivedEvent => { + console.log("OneSignal: notification will show in foreground:", notifReceivedEvent); + let notif = notifReceivedEvent.getNotification(); + setTimeout(()=>notifReceivedEvent.complete(notif), 0); }); OneSignal.setNotificationOpenedHandler(notification => { console.log("OneSignal: notification opened:", notification); diff --git a/src/NotificationReceivedEvent.js b/src/NotificationReceivedEvent.js index b4b3e824..e5d4ec78 100644 --- a/src/NotificationReceivedEvent.js +++ b/src/NotificationReceivedEvent.js @@ -1,58 +1,27 @@ import { NativeModules, Platform } from 'react-native'; +import OSNotification from './OSNotification'; const RNOneSignal = NativeModules.OneSignal; export default class NotificationReceivedEvent { constructor(receivedEvent){ - this.body = receivedEvent.body; - this.sound = receivedEvent.sound; - this.title = receivedEvent.title; - this.launchURL = receivedEvent.launchURL; - this.rawPayload = receivedEvent.rawPayload; - this.actionButtons = receivedEvent.actionButtons; - this.additionalData = receivedEvent.additionalData; - this.notificationId = receivedEvent.notificationId; - - if (Platform.OS === 'android') { - this.groupKey = receivedEvent.groupKey; - this.ledColor = receivedEvent.ledColor; - this.priority = receivedEvent.priority; - this.smallIcon = receivedEvent.smallIcon; - this.largeIcon = receivedEvent.largeIcon; - this.bigPicture = receivedEvent.bigPicture; - this.collapseId = receivedEvent.collapseId; - this.groupMessage = receivedEvent.groupMessage; - this.fromProjectNumber = receivedEvent.fromProjectNumber; - this.smallIconAccentColor = receivedEvent.smallIconAccentColor; - this.lockScreenVisibility = receivedEvent.lockScreenVisibililty; - this.androidNotificationId = receivedEvent.androidNotificationId; - } - - if (Platform.OS = 'ios') { - this.badge = receivedEvent.badge; - this.category = receivedEvent.category; - this.threadId = receivedEvent.threadId; - this.subtitle = receivedEvent.subtitle; - this.templateId = receivedEvent.templateId; - this.attachments = receivedEvent.attachments; - this.templateName = receivedEvent.templateName; - this.actionButtons = receivedEvent.actionButtons; - this.mutableContent = receivedEvent.mutableContent; - this.badgeIncrement = receivedEvent.badgeIncrement; - this.contentAvailable = receivedEvent.contentAvailable; - } + this.notification = new OSNotification(receivedEvent); } - complete(notificationReceivedEvent) { - if (!notificationReceivedEvent) { + complete(notification) { + if (!notification) { // if the notificationReceivedEvent is null, we want to call the native-side // complete/completion with null to silence the notification - RNOneSignal.completeNotificationEvent(this.notificationId, false); + RNOneSignal.completeNotificationEvent(notification.notificationId, false); return; } // if the notificationReceivedEvent is not null, we want to pass the specific event // future: Android side: make the notification modifiable // iOS & Android: the notification id is associated with the native-side complete handler / completion block - RNOneSignal.completeNotificationEvent(notificationReceivedEvent.notificationId, true); + RNOneSignal.completeNotificationEvent(notification.notificationId, true); + } + + getNotification() { + return this.notification; } } \ No newline at end of file diff --git a/src/OSNotification.js b/src/OSNotification.js new file mode 100644 index 00000000..c7e1052a --- /dev/null +++ b/src/OSNotification.js @@ -0,0 +1,43 @@ +import { Platform } from 'react-native'; + +export default class OSNotification { + constructor(receivedEvent) { + this.body = receivedEvent.body; + this.sound = receivedEvent.sound; + this.title = receivedEvent.title; + this.launchURL = receivedEvent.launchURL; + this.rawPayload = receivedEvent.rawPayload; + this.actionButtons = receivedEvent.actionButtons; + this.additionalData = receivedEvent.additionalData; + this.notificationId = receivedEvent.notificationId; + + if (Platform.OS === 'android') { + this.groupKey = receivedEvent.groupKey; + this.ledColor = receivedEvent.ledColor; + this.priority = receivedEvent.priority; + this.smallIcon = receivedEvent.smallIcon; + this.largeIcon = receivedEvent.largeIcon; + this.bigPicture = receivedEvent.bigPicture; + this.collapseId = receivedEvent.collapseId; + this.groupMessage = receivedEvent.groupMessage; + this.fromProjectNumber = receivedEvent.fromProjectNumber; + this.smallIconAccentColor = receivedEvent.smallIconAccentColor; + this.lockScreenVisibility = receivedEvent.lockScreenVisibililty; + this.androidNotificationId = receivedEvent.androidNotificationId; + } + + if (Platform.OS = 'ios') { + this.badge = receivedEvent.badge; + this.category = receivedEvent.category; + this.threadId = receivedEvent.threadId; + this.subtitle = receivedEvent.subtitle; + this.templateId = receivedEvent.templateId; + this.attachments = receivedEvent.attachments; + this.templateName = receivedEvent.templateName; + this.actionButtons = receivedEvent.actionButtons; + this.mutableContent = receivedEvent.mutableContent; + this.badgeIncrement = receivedEvent.badgeIncrement; + this.contentAvailable = receivedEvent.contentAvailable; + } + } +} \ No newline at end of file From 6f1dc6c53d7495c65f876a345483a6b42f743a1d Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 15 Oct 2020 19:17:52 -0500 Subject: [PATCH 26/69] Update RCTOneSignalEventEmitter to Correctly use References Motivation: Because this code is within a block, we need to be able to create a weak and then strong reference to "self" in order for those changes to occur on the RCTOneSignalEventEmitter object. --- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 68b6c1f6..0066bbe8 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -187,22 +187,27 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { } RCT_EXPORT_METHOD(setNotificationWillShowInForegroundHandler) { + __weak RCTOneSignalEventEmitter *weakSelf = self; [OneSignal setNotificationWillShowInForegroundHandler:^(OSNotification *notif, OSNotificationDisplayResponse completion) { - self->_receivedNotificationCache[notif.notificationId] = notif; - self->_notificationCompletionCache[notif.notificationId] = completion; + RCTOneSignalEventEmitter *strongSelf = weakSelf; + if(!strongSelf) { + return; + } + strongSelf->_receivedNotificationCache[notif.notificationId] = notif; + strongSelf->_notificationCompletionCache[notif.notificationId] = completion; [RCTOneSignalEventEmitter sendEventWithName:@"OneSignal-notificationWillShowInForeground" withBody:[notif jsonRepresentation]]; }]; } RCT_EXPORT_METHOD(completeNotificationEvent:(NSString*)notificationId displayOption:(BOOL)shouldDisplay) { - OSNotificationDisplayResponse completion = self->_notificationCompletionCache[notificationId]; + OSNotificationDisplayResponse completion = _notificationCompletionCache[notificationId]; if (!completion) { [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"OneSignal (objc): could not find notification completion block with id: %@", notificationId]]; return; } if (shouldDisplay) { - OSNotification *notif = self->_receivedNotificationCache[notificationId]; + OSNotification *notif = _receivedNotificationCache[notificationId]; dispatch_async(dispatch_get_main_queue(), ^{ completion(notif); }); From 657fe752dd8e25ab94b471f2f9f2839ca56d1db0 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 15 Oct 2020 19:21:21 -0500 Subject: [PATCH 27/69] iOS: Add Checks So That Observers Aren't Being Added Multiple Times --- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 0066bbe8..90950d7a 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -13,6 +13,9 @@ @implementation RCTOneSignalEventEmitter { BOOL _hasListeners; + BOOL _hasSetSubscriptionObserver; + BOOL _hasSetPermissionObserver; + BOOL _hasSetEmailSubscriptionObserver; NSMutableDictionary* _notificationCompletionCache; NSMutableDictionary* _receivedNotificationCache; } @@ -93,15 +96,24 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { #pragma mark Exported Methods RCT_EXPORT_METHOD(addPermissionObserver) { - [OneSignal addPermissionObserver:[RCTOneSignal sharedInstance]]; + if (!_hasSetPermissionObserver) { + [OneSignal addPermissionObserver:[RCTOneSignal sharedInstance]]; + _hasSetPermissionObserver = true; + } } RCT_EXPORT_METHOD(addSubscriptionObserver) { - [OneSignal addSubscriptionObserver:[RCTOneSignal sharedInstance]]; + if (!_hasSetSubscriptionObserver) { + [OneSignal addSubscriptionObserver:[RCTOneSignal sharedInstance]]; + _hasSetSubscriptionObserver = true; + } } RCT_EXPORT_METHOD(addEmailSubscriptionObserver) { - [OneSignal addEmailSubscriptionObserver:[RCTOneSignal sharedInstance]]; + if (!_hasSetEmailSubscriptionObserver) { + [OneSignal addEmailSubscriptionObserver:[RCTOneSignal sharedInstance]]; + _hasSetEmailSubscriptionObserver = true; + } } RCT_EXPORT_METHOD(setRequiresUserPrivacyConsent:(BOOL)required) { From 0753f6621de2b7f5bcb4263890d4ef614346cfc1 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 16 Oct 2020 18:37:37 -0500 Subject: [PATCH 28/69] Update `RNOneSignal.java`: remove unused imports, variables, 1 typo nit * Removed unused imports * Removed `OSPermissionSubscriptionState` which was removed native-side * A couple nits --- .../rnonesignalandroid/RNOneSignal.java | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 8b23167f..39e99ca8 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -44,10 +44,8 @@ of this software and associated documentation files (the "Software"), to deal import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.WritableNativeMap; @@ -60,27 +58,16 @@ of this software and associated documentation files (the "Software"), to deal import com.onesignal.OneSignal; import com.onesignal.OutcomeEvent; import com.onesignal.OSDeviceState; -import com.onesignal.OSPermissionState; import com.onesignal.OSInAppMessageAction; import com.onesignal.OSNotification; import com.onesignal.OSNotificationReceivedEvent; import com.onesignal.OSNotificationOpenedResult; import com.onesignal.OneSignal.OutcomeCallback; import com.onesignal.OneSignal.EmailUpdateError; -import com.onesignal.OSNotificationGenerationJob; - -import com.onesignal.OSSubscriptionState; -import com.onesignal.OSEmailSubscriptionState; -import com.onesignal.OSPermissionSubscriptionState; import com.onesignal.OneSignal.EmailUpdateHandler; import com.onesignal.OneSignal.OSInAppMessageClickHandler; import com.onesignal.OneSignal.OSNotificationOpenedHandler; -import com.onesignal.OneSignal.OSExternalUserIdUpdateCompletionHandler; -import com.onesignal.OneSignal.OutcomeCallback; -import com.onesignal.OneSignal.OSInAppMessageClickHandler; -import com.onesignal.OutcomeEvent; -import com.onesignal.OSDeviceState; import com.onesignal.OSPermissionObserver; import com.onesignal.OSSubscriptionObserver; @@ -88,7 +75,6 @@ of this software and associated documentation files (the "Software"), to deal import com.onesignal.OSPermissionStateChanges; import com.onesignal.OSSubscriptionStateChanges; -import com.onesignal.OSEmailSubscriptionObserver; import org.json.JSONObject; import org.json.JSONArray; @@ -110,26 +96,21 @@ public class RNOneSignal extends ReactContextBaseJavaModule private ReactContext mReactContext; private boolean oneSignalInitDone; - private boolean registeredEvents = false; private OSInAppMessageAction inAppMessageActionResult; private HashMap notificationReceivedEventCache; - private boolean hasSetNotificationOpenedHandler = false; private boolean hasSetInAppClickedHandler = false; - private boolean hasSetRequiresPrivacyConsent = false; private boolean hasSetSubscriptionObserver = false; private boolean hasSetEmailSubscriptionObserver = false; private boolean hasSetPermissionObserver = false; - private boolean waitingForUserPrivacyConsent = false; // A native module is supposed to invoke its callback only once. It can, however, store the callback and invoke it later. // It is very important to highlight that the callback is not invoked immediately after the native function completes // - remember that bridge communication is asynchronous, and this too is tied to the run loop. // Once you have done invoke() on the callback, you cannot use it again. Store it here. private Callback pendingGetTagsCallback; - private Callback inAppMessageClickedCallback; private String appIdFromManifest(ReactApplicationContext context) { try { @@ -200,9 +181,6 @@ private void initOneSignal() { OneSignal.setInAppMessageClickHandler(this); OneSignal.initWithContext(context); - - if (this.hasSetRequiresPrivacyConsent) - this.waitingForUserPrivacyConsent = true; } @ReactMethod @@ -233,7 +211,7 @@ public void onOSEmailSubscriptionChanged(OSEmailSubscriptionStateChanges stateCh public void addPermissionObserver() { if (!hasSetPermissionObserver) { OneSignal.addPermissionObserver(this); - hasSetSubscriptionObserver = true; + hasSetPermissionObserver = true; } } From 3617b170a19400a93b3ce50d9cc5eb7eda4d834a Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 16 Oct 2020 18:38:42 -0500 Subject: [PATCH 29/69] Update Example App * Commented out `NotificationNotDisplayingExtender` for now --- .../NotificationNotDisplayingExtender.java | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 android/src/main/java/com/geektime/rnonesignalandroid/NotificationNotDisplayingExtender.java diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/NotificationNotDisplayingExtender.java b/android/src/main/java/com/geektime/rnonesignalandroid/NotificationNotDisplayingExtender.java deleted file mode 100644 index e4486f7d..00000000 --- a/android/src/main/java/com/geektime/rnonesignalandroid/NotificationNotDisplayingExtender.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.geektime.rnonesignalandroid; - -import android.util.Log; - -import com.onesignal.NotificationExtenderService; -import com.onesignal.OSNotificationReceivedResult; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Created by Andrey Beletsky on 6/5/17. - */ -public class NotificationNotDisplayingExtender extends NotificationExtenderService { - @Override - protected boolean onNotificationProcessing(OSNotificationReceivedResult receivedResult) { - JSONObject additionalData = receivedResult.payload.additionalData; - boolean hidden = false; - try { - if (additionalData.has(RNOneSignal.HIDDEN_MESSAGE_KEY)) { - hidden = additionalData.getBoolean(RNOneSignal.HIDDEN_MESSAGE_KEY); - } - } catch (JSONException e) { - Log.e("OneSignal", "onNotificationProcessing Failure: " + e.getMessage()); - } - - // Return true to stop the notification from displaying. - return hidden; - } -} From 92fd5e0a2ff2dc83e8533b366123bc060006dc07 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 20 Oct 2020 15:54:10 -0500 Subject: [PATCH 30/69] Update package.json versions --- examples/RNOneSignal/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/RNOneSignal/package.json b/examples/RNOneSignal/package.json index 21a6e2a5..3b92694c 100644 --- a/examples/RNOneSignal/package.json +++ b/examples/RNOneSignal/package.json @@ -10,7 +10,7 @@ "dependencies": { "react": "16.9.0", "react-native": "^0.61.2", - "react-native-onesignal": "^3.9.1" + "react-native-onesignal": "^4.0.0-beta.2" }, "devDependencies": { "@babel/core": "^7.5.5", diff --git a/package.json b/package.json index 4d56695d..62e45817 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-onesignal", - "version": "3.9.1", + "version": "4.0.0-beta.2", "description": "React Native OneSignal SDK", "main": "src/index", "scripts": { From e9d1ddf65b769cc4dfc209de9debf6011c7a7b09 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 20 Oct 2020 16:20:18 -0500 Subject: [PATCH 31/69] Update Native SDK Versions --- android/build.gradle | 2 +- react-native-onesignal.podspec | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index aca22412..4a330fda 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -24,7 +24,7 @@ dependencies { // api is used instead of implementation so the parent :app project can access any of the OneSignal Java // classes if needed. Such as com.onesignal.NotificationExtenderService - api 'com.onesignal:OneSignal:3.15.3' + api 'com.onesignal:OneSignal:4.0.0-beta2' testImplementation 'junit:junit:4.12' } diff --git a/react-native-onesignal.podspec b/react-native-onesignal.podspec index dd2fd6b7..2e699198 100644 --- a/react-native-onesignal.podspec +++ b/react-native-onesignal.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.platform = :ios, "8.0" s.source = { :git => "#{package_json["repository"]["url"]}.git", :tag => "#{s.version}" } s.source_files = 'ios/RCTOneSignal/*.{h,m}' - s.static_framework = true + s.static_framework = true # The "React" pod is required due to the use of RCTBridgeModule, RCTEventEmitter, etc # Ensuring we have version 0.13.0 or greater to avoid a cocoapods issue noted in React Native's release notes # https://github.com/facebook/react-native/releases/tag/v0.13.0 @@ -22,5 +22,5 @@ Pod::Spec.new do |s| # pod 'React', :path => '../node_modules/react-native/' # The Native OneSignal-iOS-SDK from cocoapods. - s.dependency 'OneSignal', '2.15.2' + s.dependency 'OneSignal', '3.0.0-beta2' end From c2d4c1472eaa6c619b85b1b04c083f90d968ad5f Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 21 Oct 2020 17:59:13 -0500 Subject: [PATCH 32/69] Remove duplicate`actionButtons` parameter --- src/OSNotification.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OSNotification.js b/src/OSNotification.js index c7e1052a..eec4f0c4 100644 --- a/src/OSNotification.js +++ b/src/OSNotification.js @@ -34,7 +34,6 @@ export default class OSNotification { this.templateId = receivedEvent.templateId; this.attachments = receivedEvent.attachments; this.templateName = receivedEvent.templateName; - this.actionButtons = receivedEvent.actionButtons; this.mutableContent = receivedEvent.mutableContent; this.badgeIncrement = receivedEvent.badgeIncrement; this.contentAvailable = receivedEvent.contentAvailable; From b3e444353f915d28aaa43a221076038dcf55e256 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 21 Oct 2020 17:58:26 -0500 Subject: [PATCH 33/69] Update Lock Files --- examples/RNOneSignal/ios/Podfile.lock | 10 +++++----- examples/RNOneSignal/yarn.lock | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/RNOneSignal/ios/Podfile.lock b/examples/RNOneSignal/ios/Podfile.lock index 42fe0fbd..f0f520ac 100644 --- a/examples/RNOneSignal/ios/Podfile.lock +++ b/examples/RNOneSignal/ios/Podfile.lock @@ -19,7 +19,7 @@ PODS: - DoubleConversion - glog - glog (0.3.5) - - OneSignal (2.12.1) + - OneSignal (3.0.0-beta2) - RCTRequired (0.61.5) - RCTTypeSafety (0.61.5): - FBLazyVector (= 0.61.5) @@ -183,8 +183,8 @@ PODS: - React-cxxreact (= 0.61.5) - React-jsi (= 0.61.5) - React-jsinspector (0.61.5) - - react-native-onesignal (3.6.0): - - OneSignal (= 2.12.1) + - react-native-onesignal (4.0.0-beta.2): + - OneSignal (= 3.0.0-beta2) - React (< 1.0.0, >= 0.13.0) - React-RCTActionSheet (0.61.5): - React-Core/RCTActionSheetHeaders (= 0.61.5) @@ -320,7 +320,7 @@ SPEC CHECKSUMS: FBReactNativeSpec: 118d0d177724c2d67f08a59136eb29ef5943ec75 Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51 glog: 1f3da668190260b06b429bb211bfbee5cd790c28 - OneSignal: ffcd02077b835a96620cdeef11f87ad1136e56ee + OneSignal: d7e28427429b55b1d84a4281fd8fadb33275d7cf RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1 RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320 React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78 @@ -330,7 +330,7 @@ SPEC CHECKSUMS: React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7 React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386 React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0 - react-native-onesignal: 08c721d49876950d303ab12948bdf1abb62e1f52 + react-native-onesignal: c6cb86fd1a000d7b9ebcd93c2a90ad398200056a React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76 React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360 React-RCTBlob: d89293cc0236d9cb0933d85e430b0bbe81ad1d72 diff --git a/examples/RNOneSignal/yarn.lock b/examples/RNOneSignal/yarn.lock index 0fe6e6a1..71752e3b 100644 --- a/examples/RNOneSignal/yarn.lock +++ b/examples/RNOneSignal/yarn.lock @@ -5186,8 +5186,10 @@ react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== -"react-native-onesignal@file:../..": - version "3.6.0" +react-native-onesignal@^4.0.0-beta.2: + version "4.0.0-beta.2" + resolved "https://registry.yarnpkg.com/react-native-onesignal/-/react-native-onesignal-4.0.0-beta.2.tgz#25ac8b34d979ef2a54b4a4f6002d1afe0448ab8f" + integrity sha512-4cnr6ZYHO4p9BKsk4dwn9aHBng8sDsjlaHfKQonFf6DTFZyHrVRBdO9zC68MI/nOx6SgfOsZrmGMABnA8ev/rg== dependencies: invariant "^2.2.2" From 804f2e1889d70ac934d42d81b76677efc64bc627 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 21 Oct 2020 18:11:14 -0500 Subject: [PATCH 34/69] Fix Initialization in iOS bridge * Was missing `initWithLaunchOptions` * Removed exposed `initialize` method from event emitter bridge * Updated `initOneSignal` method to accept the launch options passed to it via the `UIApplication+RCTOneSignal.m` file --- ios/RCTOneSignal/RCTOneSignal.h | 2 +- ios/RCTOneSignal/RCTOneSignal.m | 3 ++- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 6 ------ ios/RCTOneSignal/UIApplication+RCTOnesignal.m | 4 ++-- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignal.h b/ios/RCTOneSignal/RCTOneSignal.h index f1e615bb..9cee757c 100644 --- a/ios/RCTOneSignal/RCTOneSignal.h +++ b/ios/RCTOneSignal/RCTOneSignal.h @@ -13,6 +13,6 @@ @property (nonatomic) BOOL didStartObserving; -- (void)initOneSignal; +- (void)initOneSignal:(NSDictionary *)launchOptions; @end diff --git a/ios/RCTOneSignal/RCTOneSignal.m b/ios/RCTOneSignal/RCTOneSignal.m index c4d1ca37..b867aa0a 100644 --- a/ios/RCTOneSignal/RCTOneSignal.m +++ b/ios/RCTOneSignal/RCTOneSignal.m @@ -41,11 +41,12 @@ + (RCTOneSignal *) sharedInstance { return _sharedInstance; } -- (void)initOneSignal { +- (void)initOneSignal:(NSDictionary *)launchOptions { if (didInitialize) return; + [OneSignal initWithLaunchOptions:launchOptions]; didInitialize = true; } diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 90950d7a..b3e561d7 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -131,12 +131,6 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { resolve(@(!OneSignal.requiresUserPrivacyConsent)); } -RCT_EXPORT_METHOD(initialize) { - dispatch_async(dispatch_get_main_queue(), ^{ - [[RCTOneSignal sharedInstance] initOneSignal]; - }); -} - RCT_EXPORT_METHOD(setAppId:(NSString* _Nonnull)newAppId) { [OneSignal setAppId:newAppId]; } diff --git a/ios/RCTOneSignal/UIApplication+RCTOnesignal.m b/ios/RCTOneSignal/UIApplication+RCTOnesignal.m index a7a3102d..04d5bc6d 100644 --- a/ios/RCTOneSignal/UIApplication+RCTOnesignal.m +++ b/ios/RCTOneSignal/UIApplication+RCTOnesignal.m @@ -3,7 +3,7 @@ @interface RCTOneSignal + (RCTOneSignal *) sharedInstance; -- (void)initOneSignal; +- (void)initOneSignal:(NSDictionary *)launchOptions; @end @implementation UIApplication(OneSignalReactNative) @@ -56,7 +56,7 @@ - (void) setOneSignalReactNativeDelegate:(id)delegate { } - (BOOL)oneSignalApplication:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { - [RCTOneSignal.sharedInstance initOneSignal]; + [[RCTOneSignal sharedInstance] initOneSignal:launchOptions]; if ([self respondsToSelector:@selector(oneSignalApplication:didFinishLaunchingWithOptions:)]) return [self oneSignalApplication:application didFinishLaunchingWithOptions:launchOptions]; return YES; From d0fcfa8e2aeff431cb1b85cbb15dee7f02bb8c74 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 21 Oct 2020 14:07:25 -0500 Subject: [PATCH 35/69] Match Format Returned to Javascript from iOS Bridge for State Change Motivation: we want this format to match the one returned by the Android bridge as well --- ios/RCTOneSignal/RCTOneSignal.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignal.m b/ios/RCTOneSignal/RCTOneSignal.m index b867aa0a..d6897f1e 100644 --- a/ios/RCTOneSignal/RCTOneSignal.m +++ b/ios/RCTOneSignal/RCTOneSignal.m @@ -75,15 +75,15 @@ - (void)sendEvent:(NSString *)eventName withBody:(NSDictionary *)body { } - (void)onOSSubscriptionChanged:(OSSubscriptionStateChanges * _Nonnull)stateChanges { - [self sendEvent:OSEventString(SubscriptionChanged) withBody:stateChanges.to.toDictionary]; + [self sendEvent:OSEventString(SubscriptionChanged) withBody:stateChanges.toDictionary]; } - (void)onOSEmailSubscriptionChanged:(OSEmailSubscriptionStateChanges * _Nonnull)stateChanges { - [self sendEvent:OSEventString(EmailSubscriptionChanged) withBody:stateChanges.to.toDictionary]; + [self sendEvent:OSEventString(EmailSubscriptionChanged) withBody:stateChanges.toDictionary]; } - (void)onOSPermissionChanged:(OSPermissionStateChanges *)stateChanges { - [self sendEvent:OSEventString(PermissionChanged) withBody:stateChanges.to.toDictionary]; + [self sendEvent:OSEventString(PermissionChanged) withBody:stateChanges.toDictionary]; } - (void)dealloc { From f22e3ef3e8c5dbbe591dfcd28ae0953e533df474 Mon Sep 17 00:00:00 2001 From: Carlos Cuesta Date: Wed, 7 Oct 2020 10:45:34 +0200 Subject: [PATCH 36/69] chore(ios): Remove VALID_ARCHS as User-Defined setting on RCTOneSignal --- ios/RCTOneSignal.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/ios/RCTOneSignal.xcodeproj/project.pbxproj b/ios/RCTOneSignal.xcodeproj/project.pbxproj index 291b878a..1942ea57 100644 --- a/ios/RCTOneSignal.xcodeproj/project.pbxproj +++ b/ios/RCTOneSignal.xcodeproj/project.pbxproj @@ -291,7 +291,6 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - VALID_ARCHS = "arm64 armv7 armv7s"; }; name = Debug; }; @@ -317,7 +316,6 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - VALID_ARCHS = "arm64 armv7 armv7s"; }; name = Release; }; From 3322af9a10889f76d25a4831080a831f4ef2b48b Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 4 Nov 2020 04:49:57 -0600 Subject: [PATCH 37/69] Fix Notification Id Bug where Notification Obj is Undefined --- src/NotificationReceivedEvent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NotificationReceivedEvent.js b/src/NotificationReceivedEvent.js index e5d4ec78..7110b996 100644 --- a/src/NotificationReceivedEvent.js +++ b/src/NotificationReceivedEvent.js @@ -11,7 +11,7 @@ export default class NotificationReceivedEvent { if (!notification) { // if the notificationReceivedEvent is null, we want to call the native-side // complete/completion with null to silence the notification - RNOneSignal.completeNotificationEvent(notification.notificationId, false); + RNOneSignal.completeNotificationEvent(this.notification.notificationId, false); return; } From 4fb66772a301f5d59159db7469aff74faa083615 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 27 Oct 2020 16:00:42 -0500 Subject: [PATCH 38/69] Update `postNotification` in Java Bridge Motivation: * We want to simplify the `postNotification` function. * The function now takes a json object string and a success and failure callback --- .../rnonesignalandroid/RNOneSignal.java | 61 +++++-------------- 1 file changed, 16 insertions(+), 45 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 39e99ca8..4262b2d7 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -329,52 +329,23 @@ public void setLocationShared(Boolean shared) { } @ReactMethod - public void postNotification(String contents, String data, String playerId, String otherParameters) { - try { - JSONObject postNotification = new JSONObject(); - postNotification.put("contents", new JSONObject(contents)); - - if (playerId != null) { - JSONArray playerIds = new JSONArray(playerId); - postNotification.put("include_player_ids", playerIds); - } - - if (data != null) { - JSONObject additionalData = new JSONObject(); - additionalData.put("p2p_notification", new JSONObject(data)); - postNotification.put("data", additionalData); + public void postNotification(String jsonObjectString, final Callback successCallback, final Callback failureCallback) { + OneSignal.postNotification( + jsonObjectString, + new OneSignal.PostNotificationResponseHandler() { + @Override + public void onSuccess(JSONObject response) { + Log.i("OneSignal", "postNotification Success: " + response.toString()); + successCallback.invoke(RNUtils.jsonToWritableMap(response)); + } + + @Override + public void onFailure(JSONObject response) { + Log.e("OneSignal", "postNotification Failure: " + response.toString()); + failureCallback.invoke(RNUtils.jsonToWritableMap(response)); + } } - - if (otherParameters != null && !otherParameters.trim().isEmpty()) { - JSONObject parametersJson = new JSONObject(otherParameters.trim()); - Iterator keys = parametersJson.keys(); - while (keys.hasNext()) { - String key = keys.next(); - postNotification.put(key, parametersJson.get(key)); - } - - if (parametersJson.has(HIDDEN_MESSAGE_KEY) && parametersJson.getBoolean(HIDDEN_MESSAGE_KEY)) { - postNotification.getJSONObject("data").put(HIDDEN_MESSAGE_KEY, true); - } - } - - OneSignal.postNotification( - postNotification, - new OneSignal.PostNotificationResponseHandler() { - @Override - public void onSuccess(JSONObject response) { - Log.i("OneSignal", "postNotification Success: " + response.toString()); - } - - @Override - public void onFailure(JSONObject response) { - Log.e("OneSignal", "postNotification Failure: " + response.toString()); - } - } - ); - } catch (JSONException e) { - e.printStackTrace(); - } + ); } @ReactMethod From 0e89dc6eb79147731ade79fc615f87883456756a Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 27 Oct 2020 16:03:33 -0500 Subject: [PATCH 39/69] Update Index.js Motivation: change the API to be more consistent with Cordova & other wrappers. We are now only taking 3 arguments: 1) json object string, 2) success + 3) failure callbacks --- src/index.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 47150cc6..52703739 100644 --- a/src/index.js +++ b/src/index.js @@ -209,13 +209,9 @@ export default class OneSignal { /* N O T I F I C A T I O N S */ - static postNotification(contents, data, player_id, otherParameters) { + static postNotification(notificationObjectString, onSuccess=()=>{}, onFailure=()=>{}) { if (!checkIfInitialized(RNOneSignal)) return; - - if (Platform.OS === 'android') - RNOneSignal.postNotification(JSON.stringify(contents), JSON.stringify(data), JSON.stringify(player_id), JSON.stringify(otherParameters)); - else - RNOneSignal.postNotification(contents, data, player_id, otherParameters); + RNOneSignal.postNotification(notificationObjectString, onSuccess, onFailure); } static clearOneSignalNotifications() { From 2216b726f0d00d66e69d33bf42924cc7469b8eb9 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 27 Oct 2020 16:05:54 -0500 Subject: [PATCH 40/69] Update Example App Motivation: update example app to have a "Post Notification" testing button --- examples/RNOneSignal/App.js | 49 +++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/examples/RNOneSignal/App.js b/examples/RNOneSignal/App.js index e0bb138b..56d2f694 100644 --- a/examples/RNOneSignal/App.js +++ b/examples/RNOneSignal/App.js @@ -129,7 +129,10 @@ export default class App extends Component { } let deviceState = await OneSignal.getDeviceState(); - this.setState({ isSubscribed: deviceState.isSubscribed }); + this.setState({ + isSubscribed: deviceState.isSubscribed, + userId : deviceState.userId + }); // Examples for using native IAM public methods // this.oneSignalInAppMessagingExamples(); @@ -227,6 +230,7 @@ export default class App extends Component { { this.createEmailFields() } { this.createExternalUserIdFields() } { this.createSubscriptionElements() } + { this.createNotificationElements() } @@ -553,7 +557,7 @@ export default class App extends Component { isExternalUserIdLoading || isPrivacyConsentLoading, () => { console.log('Attempting to set external user id: ' + externalUserId); - this.setState({isExternalUserIdLoading:true}, () => { + this.setState({ isExternalUserIdLoading:true }, () => { // OneSignal setExternalUserId OneSignal.setExternalUserId(externalUserId, (results) => { console.log('Results of setting external user id'); @@ -571,22 +575,53 @@ export default class App extends Component { isExternalUserIdLoading || isPrivacyConsentLoading, () => { console.log('Attempting to remove external user id'); - this.setState({isExternalUserIdLoading:true}, () => { + this.setState({ isExternalUserIdLoading: true }, () => { // OneSignal setExternalUserId OneSignal.removeExternalUserId((results) => { console.log('Results of removing external user id'); console.log(results); - this.setState({isExternalUserIdLoading:false}); + this.setState({ isExternalUserIdLoading:false }); }); }); } ) + } + + createNotificationElements() { + // States used through-out the email fields + const { + externalUserId, + isExternalUserIdLoading, + isPrivacyConsentLoading + } = this.state; + + let elements = []; + + // Remove External User Id Button + let postNotificationButton = this.renderButtonView( + "Post Notification", + isExternalUserIdLoading || isPrivacyConsentLoading, + async () => { + const { userId } = await OneSignal.getDeviceState(); + const notificationObj = { + contents: {en: "Message Body"}, + include_player_ids: [userId] + }; + const json = JSON.stringify(notificationObj); + + console.log('Attempting to send notification to '+userId); + + OneSignal.postNotification(json, (success) => { + console.log("Success:", success); + }, (failure) => { + console.log("Failure:", failure ); + }); + } + ) elements.push( - externalUserIdTextInput, - setExternalUserIdButton, - removeExternalUserIdButton + postNotificationButton ); return elements; From 048cfb1f1339d7bf17030e721c9014577429bf62 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 27 Oct 2020 17:08:22 -0500 Subject: [PATCH 41/69] Update `postNotification` in iOS Bridge Motivation: * We want to simplify the `postNotification` function. * The function now takes a json object string and uses `postNotificationWithJsonString` to send a notification --- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 34 +++++++-------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index b3e561d7..945a7baa 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -286,30 +286,18 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal promptLocation]; } -// The post notification endpoint accepts four parameters. -RCT_EXPORT_METHOD(postNotification:(NSDictionary *)contents data:(NSDictionary *)data player_id:(NSArray *)player_ids other_parameters:(NSDictionary *)other_parameters) { - NSDictionary * additionalData = data ? @{@"p2p_notification": data} : @{}; - - NSMutableDictionary * extendedData = [additionalData mutableCopy]; - BOOL isHidden = [[other_parameters ?: @{} objectForKey:@"hidden"] boolValue]; - if (isHidden) { - [extendedData setObject:[NSNumber numberWithBool:YES] forKey:@"hidden"]; - } - - NSMutableDictionary *notification = [NSMutableDictionary new]; - notification[@"contents"] = contents; - notification[@"data"] = extendedData; - - if (player_ids) { - // Array of player ids - notification[@"include_player_ids"] = player_ids; - } - - if (other_parameters) { - [notification addEntriesFromDictionary:other_parameters]; +RCT_EXPORT_METHOD(postNotification:(NSString *)jsonObjectString successCallback:(RCTResponseSenderBlock)successCallback failureCallback:(RCTResponseSenderBlock)failureCallback) { + if (!successCallback || !failureCallback) { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"postNotification must contain success & failure callbacks"]; + return; } - - [OneSignal postNotification:notification]; + [OneSignal postNotificationWithJsonString:jsonObjectString onSuccess:^(NSDictionary *success) { + [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Successfully sent notification."]; + successCallback(@[success]); + } onFailure:^(NSError *error) { + [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Notification Send Failure with Error: %@", error]]; + failureCallback(@[error.userInfo[@"error"] ?: error.localizedDescription]); + }]; } RCT_EXPORT_METHOD(setLogLevel:(int)logLevel visualLogLevel:(int)visualLogLevel) { From 9211325576126739dc2b807abdc87b72c244bbc0 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 27 Oct 2020 19:28:44 -0500 Subject: [PATCH 42/69] Types File Path in Package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 62e45817..6ce13dc3 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "4.0.0-beta.2", "description": "React Native OneSignal SDK", "main": "src/index", + "typings": "src/index.d.ts", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, From 92731a2f57c1b7719583a7e084ee9ce1f185e11c Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 27 Oct 2020 19:29:00 -0500 Subject: [PATCH 43/69] Nit: rename argument --- src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 52703739..caf0523e 100644 --- a/src/index.js +++ b/src/index.js @@ -164,9 +164,9 @@ export default class OneSignal { RNOneSignal.sendTags(tags || {}); } - static getTags(next) { + static getTags(callback) { if (!checkIfInitialized(RNOneSignal)) return; - RNOneSignal.getTags(next); + RNOneSignal.getTags(callback); } static deleteTag(key) { From 16a245fa0372f010113f1d2d357aef20fedef805 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 27 Oct 2020 19:28:32 -0500 Subject: [PATCH 44/69] Types Definitions --- src/index.d.ts | 396 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 src/index.d.ts diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 00000000..e3777c1a --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1,396 @@ +declare module 'react-native-onesignal' { + /* O P T I O N T Y P E V A L U E S */ + // 0 = None, 1 = Fatal, 2 = Errors, 3 = Warnings, 4 = Info, 5 = Debug, 6 = Verbose + export type LogLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6; + + // 0 = NotDetermined, 1 = Authorized, 2 = Denied, 3 = Provisional, 4 = Ephemeral + export type IosPermissionStatus = 0 | 1 | 2 | 3 | 4; + + // 0 = NotificationClicked, 1 = ButtonClicked + export type OpenedEventActionType = 0 | 1; + + /* O B S E R V E R C H A N G E E V E N T S */ + export interface ChangeEvent { + from : T; + to : T; + } + + export interface PermissionChange { + status ?: IosPermissionStatus; // ios + hasPrompted ?: boolean; // ios + provisional ?: boolean; // ios + areNotificationsEnabled ?: boolean; // android + }; + + export interface SubscriptionChange { + userId ?: string; + pushToken ?: string; + isSubscribed : boolean; + isPushDisabled : boolean; + }; + + export interface EmailSubscriptionChange { + emailAddress ?: string; + emailUserId ?: string; + isEmailSubscribed : boolean; + }; + + /* N O T I F I C A T I O N S */ + export interface OSNotification { + body : string; + sound ?: string; + title ?: string; + launchURL ?: string; + rawPayload : object | string; // platform bridges return different types + actionButtons ?: object[]; + additionalData : object; + notificationId : string; + // android only + groupKey ?: string; + groupMessage ?: string; + ledColor ?: string; + priority ?: number; + smallIcon ?: string; + largeIcon ?: string; + bigPicture ?: string; + collapseId ?: string; + fromProjectNumber ?: string; + smallIconAccentColor ?: string; + lockScreenVisibility ?: string; + androidNotificationId ?: number; + // ios only + badge ?: string; + badgeIncrement ?: string; + category ?: string; + threadId ?: string; + subtitle ?: string; + templateId ?: string; + templateName ?: string; + attachments ?: object; + mutableContent ?: boolean; + contentAvailable ?: string; + } + + /* N O T I F I C A T I O N & I A M E V E N T S */ + export interface NotificationReceivedEvent { + complete : (notification: OSNotification) => void; + getNotification : () => OSNotification; + }; + + export interface OpenedEvent { + action : OpenedEventAction; + notification : OSNotification; + } + + export interface OpenedEventAction { + type : OpenedEventActionType + } + + export interface InAppMessageAction { + closes_message : boolean; + first_click : boolean; + click_name ?: string; + click_url ?: string; + outcomes ?: object[]; + tags ?: object; + } + + export interface OutcomeEvent { + session : string; + id : string; + timestamp : number; + weight : number; + notification_ids: string[]; + } + + /* D E V I C E */ + export interface DeviceState { + userId : string; + pushToken : string; + emailUserId : string; + emailAddress : string; + isSubscribed : boolean; + isPushDisabled : boolean; + isEmailSubscribed : boolean; + hasNotificationPermission ?: boolean; // ios only + notificationPermissionStatus ?: number; // ios only + // areNotificationsEnabled (android) not included since it is converted to hasNotificationPermission in bridge + } + + /* O N E S I G N A L I N T E R F A C E */ + export interface OneSignal { + /** + * Completes OneSignal initialization by setting the OneSignal Application ID. + * @param {string} appId + * @returns void + */ + setAppId(appId: string): void; + + /** + * Add a callback that fires when the native push permission changes. + * @param {(event:ChangeEvent)=>void} observer + * @returns void + */ + addPermissionObserver(observer: (event: ChangeEvent) => void): void; + + /** + * Add a callback that fires when the OneSignal subscription state changes. + * @param {(event:ChangeEvent)=>void} observer + * @returns void + */ + addSubscriptionObserver(observer: (event: ChangeEvent) => void): void; + + /** + * Add a callback that fires when the OneSignal email subscription changes. + * @param {(event:ChangeEvent)=>void} observer + * @returns void + */ + addEmailSubscriptionObserver(observer: (event: ChangeEvent) => void): void; + + /** + * Set the callback to run just before displaying a notification while the app is in focus. + * @param {(event:NotificationReceivedEvent)=>void} handler + * @returns void + */ + setNotificationWillShowInForegroundHandler(handler: (event: NotificationReceivedEvent) => void): void; + + /** + * Set the callback to run on notification open. + * @param {(openedEvent:OpenedEvent)=>void} handler + * @returns void + */ + setNotificationOpenedHandler(handler: (openedEvent: OpenedEvent) => void): void; + + /** + * Prompts the iOS user for push notifications. + * @param {(response:boolean)=>void} handler + * @returns void + */ + promptForPushNotificationsWithUserResponse(handler?: (response: boolean) => void): void; + + /** + * Disable the push notification subscription to OneSignal. + * @param {boolean} disable + * @returns void + */ + disablePush(disable: boolean): void; + + /** + * Disable or enable location collection (defaults to enabled if your app has location permission). + * @param {boolean} shared + * @returns void + */ + setLocationShared(shared: boolean): void; + + /** + * Prompts the user for location permissions to allow geotagging from the OneSignal dashboard. + * @returns void + */ + promptLocation(): void; + + /** + * This method returns a "snapshot" of the device state for when it was called. + * @returns Promise + */ + getDeviceState(): Promise; + + /** + * Did the user provide privacy consent for GDPR purposes. + * @returns Promise + */ + userProvidedPrivacyConsent(): Promise; + + /** + * Tag a user based on an app event of your choosing so they can be targeted later via segments. + * @param {string} key + * @param {string} value + * @returns void + */ + sendTag(key: string, value: string): void; + + /** + * Tag a user wiht multiple tags based on an app event of your choosing so they can be targeted later via segments. + * @param {object} tags + * @returns void + */ + sendTags(tags: object): void; + + /** + * Retrieve a list of tags that have been set on the user from the OneSignal server. + * @param {(tags:object)=>void} handler + * @returns void + */ + getTags(handler: (tags: object) => void): void; + + /** + * Deletes a single tag that was previously set on a user. + * @param {string} key + * @returns void + */ + deleteTag(key: string): void; + + /** + * Deletes multiple tags that were previously set on a user. + * @param {string[]} keys + */ + deleteTags(keys: string[]); + + /** + * Allows you to set the user's email address with the OneSignal SDK. + * @param {string} email + * @param {string} authCode + * @param {Function} handler + * @returns void + */ + setEmail(email: string, authCode?: string, handler?: Function): void; + + /** + * If your app implements logout functionality, you can call logoutEmail to dissociate the email from the device. + * @param {Function} handler + */ + logoutEmail(handler?: Function); + + /** + * Send a notification + * @param {string} notificationObjectString - JSON string payload (see REST API reference) + * @param {(success:object)=>void} onSuccess + * @param {(failure:object)=>void} onFailure + * @returns void + */ + postNotification(notificationObjectString: string, onSuccess: (success: object) => void, onFailure: (failure: object) => void): void; + + /** + * Android Only. iOS provides a standard way to clear notifications by clearing badge count. + * @returns void + */ + clearOneSignalNotifications(): void; + + /** + * Cancels a single OneSignal notification based on its Android notification integer id. + * @param {number} id - notification id to cancel + * @returns void + */ + cancelNotification(id: number): void; + + /** + * Allows you to use your own system's user ID's to send push notifications to your users. + * @param {string} externalId + * @param {(results:object)=>void} handler + * @returns void + */ + setExternalUserId(externalId: string, handler?: (results: object) => void): void; + + /** + * Removes whatever was set as the current user's external user ID. + * @param {(results:object)=>void} handler + * @returns void + */ + removeExternalUserId(handler?: (results: object) => void): void; + + /** + * Sets an In-App Message click event handler. + * @param {(action:InAppMessageAction)=>void} handler + * @returns void + */ + setInAppMessageClickHandler(handler: (action: InAppMessageAction) => void): void; + + /** + * Add an In-App Message Trigger. + * @param {string} key + * @param {string} value + * @returns void + */ + addTrigger(key: string, value: string): void; + + /** + * Adds Multiple In-App Message Triggers. + * @param {object} triggers + * @returns void + */ + addTriggers(triggers: object): void; + + /** + * Removes a list of triggers based on a collection of keys. + * @param {string[]} keys + * @returns void + */ + removeTriggersForKeys(keys: string[]): void; + + /** + * Removes a list of triggers based on a key. + * @param {string} key + * @returns void + */ + removeTriggerForKey(key: string): void; + + /** + * Gets a trigger value for a provided trigger key. + * @param {string} key + * @returns void + */ + getTriggerValueForKey(key: string): Promise; + + /** + * Pause & unpause In-App Messages + * @param {boolean} pause + * @returns void + */ + pauseInAppMessages(pause: boolean): void; + + /** + * Increases the "Count" of this Outcome by 1 and will be counted each time sent. + * @param {string} name + * @param {(event:OutcomeEvent)=>void} handler + * @returns void + */ + sendOutcome(name: string, handler?: (event: OutcomeEvent) => void): void; + + /** + * Increases "Count" by 1 only once. This can only be attributed to a single notification. + * @param {string} name + * @param {(event:OutcomeEvent)=>void} handler + * @returns void + */ + sendUniqueOutcome(name: string, handler?: (event: OutcomeEvent) => void): void; + + /** + * Increases the "Count" of this Outcome by 1 and the "Sum" by the value. Will be counted each time sent. + * If the method is called outside of an attribution window, it will be unattributed until a new session occurs. + * @param {string} name + * @param {string|number} value + * @param {(event:OutcomeEvent)=>void} handler + * @returns void + */ + sendOutcomeWithValue(name: string, value: string|number, handler?: (event: OutcomeEvent) => void): void; + + /** + * Enable logging to help debug if you run into an issue setting up OneSignal. + * @param {LogLevel} nsLogLevel - Sets the logging level to print to the Android LogCat log or Xcode log. + * @param {LogLevel} visualLogLevel - Sets the logging level to show as alert dialogs. + * @returns void + */ + setLogLevel(nsLogLevel: LogLevel, visualLogLevel: LogLevel): void; + + /** + * Clears all handlers and observers. + * @returns void + */ + clearHandlers(): void; + + /** + * For GDPR users, your application should call this method before setting the App ID. + * @param {boolean} required + * @returns void + */ + setRequiresUserPrivacyConsent(required: boolean): void; + + /** + * If your application is set to require the user's privacy consent, you can provide this consent using this method. + * @param {boolean} granted + * @returns void + */ + provideUserConsent(granted: boolean): void; + } + const OneSignal: OneSignal; + export default OneSignal; +} \ No newline at end of file From 616826264243d885918b57e6728bdf1954a28eb3 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 17 Nov 2020 12:59:32 -0600 Subject: [PATCH 45/69] Make Complete Argument Optional in TS Typings --- src/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.d.ts b/src/index.d.ts index e3777c1a..84249f0e 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -73,7 +73,7 @@ declare module 'react-native-onesignal' { /* N O T I F I C A T I O N & I A M E V E N T S */ export interface NotificationReceivedEvent { - complete : (notification: OSNotification) => void; + complete : (notification?: OSNotification) => void; getNotification : () => OSNotification; }; From 2830ef28d786a58fff283105efb3ded3d8a9ff10 Mon Sep 17 00:00:00 2001 From: Josh Kasten Date: Sat, 5 Dec 2020 00:50:37 -0800 Subject: [PATCH 46/69] Removed Android OneSignal manifest placeholders * The `onesignal_app_id` and `onesignal_google_project_number` placehold values were droped from OneSignal-Android-SDK 4.0.0 --- android/build.gradle | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 4a330fda..9d9cfc06 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -29,45 +29,6 @@ dependencies { testImplementation 'junit:junit:4.12' } -// Adds required manifestPlaceholders keys to allow mainifest merge gradle step to complete -// The OneSignal app id should be set in your JS code. -// Google project number / FCM Sender ID will be pulled in from the OneSignal dashbaord -class DefaultManifestPlaceHolders { - static final MANIFEST_PLACEHOLDERS_DEFAULTS = [ - onesignal_app_id: '', - onesignal_google_project_number: 'REMOTE' - ] - - static void addManifestToAppProject(Project proj) { - def androidApp = proj.android - MANIFEST_PLACEHOLDERS_DEFAULTS.each { defKey, defValue -> - if (!androidApp.defaultConfig.manifestPlaceholders.containsKey(defKey)) { - androidApp.defaultConfig.manifestPlaceholders[defKey] = defValue - - androidApp.buildTypes.each { buildType -> - if (!buildType.manifestPlaceholders.containsKey(defKey)) - buildType.manifestPlaceholders[defKey] = defValue - } - } - } - } -} - -rootProject.childProjects.each { projName, proj -> - if (projName != 'app' && projName != 'react-native-onesignal') - return - - if (proj.hasProperty('android')) { - DefaultManifestPlaceHolders.addManifestToAppProject(proj) - return - } - - proj.afterEvaluate { - DefaultManifestPlaceHolders.addManifestToAppProject(proj) - } -} - - // Add the following to the top (Line 1) of your app/build.gradle if you run into any issues with duplicate classes. // Such as the following error // Error: more than one library with package name 'com.google.android.gms.license' From 4906bfc53dcbcd79edfe8ac6e7af9968158449ae Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 9 Dec 2020 15:02:47 -0600 Subject: [PATCH 47/69] Rename logLevel method from `onesignal_Log` to `onesignalLog` Motivation: the native iOS SDK changed the method name `onesignal_Log` to `onesignalLog` for consistency w/the native Android SDK method. --- ios/OneSignal.h | 2 +- ios/RCTOneSignal/RCTOneSignal.m | 2 +- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 36 ++++++++++----------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ios/OneSignal.h b/ios/OneSignal.h index 1903afe6..c5eb5a32 100755 --- a/ios/OneSignal.h +++ b/ios/OneSignal.h @@ -494,7 +494,7 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) { // - Logging + (void)setLogLevel:(ONE_S_LOG_LEVEL)logLevel visualLevel:(ONE_S_LOG_LEVEL)visualLogLevel; -+ (void)onesignal_Log:(ONE_S_LOG_LEVEL)logLevel message:(NSString*)message; ++ (void)onesignalLog:(ONE_S_LOG_LEVEL)logLevel message:(NSString*)message; // - Tagging + (void)sendTag:(NSString*)key value:(NSString*)value onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock; diff --git a/ios/RCTOneSignal/RCTOneSignal.m b/ios/RCTOneSignal/RCTOneSignal.m index d6897f1e..53494473 100644 --- a/ios/RCTOneSignal/RCTOneSignal.m +++ b/ios/RCTOneSignal/RCTOneSignal.m @@ -63,7 +63,7 @@ - (NSDictionary *)jsonObjectWithString:(NSString *)jsonString { NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError]; if (jsonError) { - [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Unable to serialize JSON string into an object: %@", jsonError]]; + [OneSignal onesignalLog:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Unable to serialize JSON string into an object: %@", jsonError]]; return nil; } diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 945a7baa..0a97fa51 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -42,7 +42,7 @@ +(BOOL)requiresMainQueueSetup { -(instancetype)init { if (self = [super init]) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Initialized RCTOneSignalEventEmitter"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"Initialized RCTOneSignalEventEmitter"]; _notificationCompletionCache = [NSMutableDictionary new]; _receivedNotificationCache = [NSMutableDictionary new]; @@ -55,7 +55,7 @@ -(instancetype)init { -(void)startObserving { _hasListeners = true; - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did start observing"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did start observing"]; [[NSNotificationCenter defaultCenter] postNotificationName:@"didSetBridge" object:nil]; @@ -64,7 +64,7 @@ -(void)startObserving { -(void)stopObserving { _hasListeners = false; - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did stop observing"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did stop observing"]; } -(NSArray *)supportedEvents { @@ -81,7 +81,7 @@ -(void)stopObserving { - (void)emitEvent:(NSNotification *)notification { if (!_hasListeners) { - [OneSignal onesignal_Log:ONE_S_LL_WARN message:[NSString stringWithFormat:@"Attempted to send an event (%@) when no listeners were set.", notification.name]]; + [OneSignal onesignalLog:ONE_S_LL_WARN message:[NSString stringWithFormat:@"Attempted to send an event (%@) when no listeners were set.", notification.name]]; return; } @@ -208,7 +208,7 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_EXPORT_METHOD(completeNotificationEvent:(NSString*)notificationId displayOption:(BOOL)shouldDisplay) { OSNotificationDisplayResponse completion = _notificationCompletionCache[notificationId]; if (!completion) { - [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"OneSignal (objc): could not find notification completion block with id: %@", notificationId]]; + [OneSignal onesignalLog:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"OneSignal (objc): could not find notification completion block with id: %@", notificationId]]; return; } @@ -244,7 +244,7 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_EXPORT_METHOD(promptForPushNotificationsWithUserResponse:(RCTResponseSenderBlock)callback) { [OneSignal promptForPushNotificationsWithUserResponse:^(BOOL accepted) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Prompt For Push Notifications Success"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"Prompt For Push Notifications Success"]; callback(@[@(accepted)]); }]; } @@ -255,17 +255,17 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_EXPORT_METHOD(sendTags:(NSDictionary *)properties) { [OneSignal sendTags:properties onSuccess:^(NSDictionary *sucess) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Send Tags Success"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"Send Tags Success"]; } onFailure:^(NSError *error) { - [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Send Tags Failure With Error: %@", error]]; + [OneSignal onesignalLog:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Send Tags Failure With Error: %@", error]]; }];} RCT_EXPORT_METHOD(getTags:(RCTResponseSenderBlock)callback) { [OneSignal getTags:^(NSDictionary *tags) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Get Tags Success"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"Get Tags Success"]; callback(@[tags]); } onFailure:^(NSError *error) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"Get Tags Failure with error: %@", error]]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"Get Tags Failure with error: %@", error]]; callback(@[error]); }]; } @@ -288,14 +288,14 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_EXPORT_METHOD(postNotification:(NSString *)jsonObjectString successCallback:(RCTResponseSenderBlock)successCallback failureCallback:(RCTResponseSenderBlock)failureCallback) { if (!successCallback || !failureCallback) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"postNotification must contain success & failure callbacks"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"postNotification must contain success & failure callbacks"]; return; } [OneSignal postNotificationWithJsonString:jsonObjectString onSuccess:^(NSDictionary *success) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Successfully sent notification."]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"Successfully sent notification."]; successCallback(@[success]); } onFailure:^(NSError *error) { - [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Notification Send Failure with Error: %@", error]]; + [OneSignal onesignalLog:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Notification Send Failure with Error: %@", error]]; failureCallback(@[error.userInfo[@"error"] ?: error.localizedDescription]); }]; } @@ -309,12 +309,12 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { } RCT_EXPORT_METHOD(setExternalUserId:(NSString*)externalId withCompletion:(RCTResponseSenderBlock)callback) { - [OneSignal setExternalUserId:externalId withCompletion:^(NSDictionary* results) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Set external user id complete"]; + [OneSignal setExternalUserId:externalId withSuccess:^(NSDictionary* results) { + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"Set external user id complete"]; if (callback) { callback(@[results]); } - }]; + } withFailure:^(NSError *error) {}]; } RCT_EXPORT_METHOD(removeExternalUserId) { @@ -323,11 +323,11 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { RCT_EXPORT_METHOD(removeExternalUserId:(RCTResponseSenderBlock)callback) { [OneSignal removeExternalUserId:^(NSDictionary* results) { - [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Remove external user id complete"]; + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:@"Remove external user id complete"]; if (callback) { callback(@[results]); } - }]; + } withFailure:^(NSError *error) {}]; } /* From 7c5ceee31f061fa098980122401c40d64d7afb0f Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 9 Dec 2020 16:42:29 -0600 Subject: [PATCH 48/69] Use Major Release Native SDK Versions Upgrade to use version 4 of the Android SDK, version 3 of the iOS SDK --- android/build.gradle | 2 +- react-native-onesignal.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9d9cfc06..499f1871 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -24,7 +24,7 @@ dependencies { // api is used instead of implementation so the parent :app project can access any of the OneSignal Java // classes if needed. Such as com.onesignal.NotificationExtenderService - api 'com.onesignal:OneSignal:4.0.0-beta2' + api 'com.onesignal:OneSignal:4.0.0' testImplementation 'junit:junit:4.12' } diff --git a/react-native-onesignal.podspec b/react-native-onesignal.podspec index 2e699198..1073728b 100644 --- a/react-native-onesignal.podspec +++ b/react-native-onesignal.podspec @@ -22,5 +22,5 @@ Pod::Spec.new do |s| # pod 'React', :path => '../node_modules/react-native/' # The Native OneSignal-iOS-SDK from cocoapods. - s.dependency 'OneSignal', '3.0.0-beta2' + s.dependency 'OneSignal', '3.0.0' end From 2f53ca2c90434616ece9f17cfcf123b4e2ee9c8a Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 9 Dec 2020 16:00:05 -0600 Subject: [PATCH 49/69] Pass Potential external Id method errors to JS via bridge Motivation: since we have added user verification to external id setting and modification, we want to surface the error via the function callback by passing it to the JS side in case the error has relevant details. E.g: "External User Id authentication (auth token) is set to REQUIRED for this application. Please provide an auth token from your backend server or change the setting in the OneSignal dashboard." --- .../rnonesignalandroid/RNOneSignal.java | 18 ++++++++++++++++-- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 10 ++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 4262b2d7..536f0c4f 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -377,11 +377,18 @@ public void userProvidedPrivacyConsent(Promise promise) { public void setExternalUserId(final String externalId, final Callback callback) { OneSignal.setExternalUserId(externalId, new OneSignal.OSExternalUserIdUpdateCompletionHandler() { @Override - public void onComplete(JSONObject results) { + public void onSuccess(JSONObject results) { Log.i("OneSignal", "Completed setting external user id: " + externalId + "with results: " + results.toString()); + if (callback != null) callback.invoke(RNUtils.jsonToWritableMap(results)); } + + @Override + public void onFailure(OneSignal.ExternalIdError error) { + if (callback != null) + callback.invoke(error.getMessage()); + } }); } @@ -389,11 +396,18 @@ public void onComplete(JSONObject results) { public void removeExternalUserId(final Callback callback) { OneSignal.removeExternalUserId(new OneSignal.OSExternalUserIdUpdateCompletionHandler() { @Override - public void onComplete(JSONObject results) { + public void onSuccess(JSONObject results) { Log.i("OneSignal", "Completed removing external user id with results: " + results.toString()); + if (callback != null) callback.invoke(RNUtils.jsonToWritableMap(results)); } + + @Override + public void onFailure(OneSignal.ExternalIdError error) { + if (callback != null) + callback.invoke(error.getMessage()); + } }); } diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 0a97fa51..5e0188df 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -314,7 +314,10 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { if (callback) { callback(@[results]); } - } withFailure:^(NSError *error) {}]; + } withFailure:^(NSError *error) { + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"OneSignal setExternalUserId error: %@", error]]; + callback(@[error.userInfo[@"error"] ?: error.localizedDescription]); + }]; } RCT_EXPORT_METHOD(removeExternalUserId) { @@ -327,7 +330,10 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { if (callback) { callback(@[results]); } - } withFailure:^(NSError *error) {}]; + } withFailure:^(NSError *error) { + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"OneSignal removeExternalUserId error: %@", error]]; + callback(@[error.userInfo[@"error"] ?: error.localizedDescription]); + }]; } /* From d3c2d13e2b5ff45f90ae128a7c36b2f985f2dfab Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 10 Dec 2020 18:04:29 -0600 Subject: [PATCH 50/69] Update outcome event symbol to OSOutcomeEvent Native SDK renamed the outcome event variable to `OSOutcomeEvent` --- .../java/com/geektime/rnonesignalandroid/RNOneSignal.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 536f0c4f..ebbc8562 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -56,7 +56,7 @@ of this software and associated documentation files (the "Software"), to deal import com.onesignal.OSEmailSubscriptionStateChanges; import com.onesignal.OneSignal; -import com.onesignal.OutcomeEvent; +import com.onesignal.OSOutcomeEvent; import com.onesignal.OSDeviceState; import com.onesignal.OSInAppMessageAction; import com.onesignal.OSNotification; @@ -535,7 +535,7 @@ public void pauseInAppMessages(Boolean pause) { public void sendOutcome(final String name, final Callback callback) { OneSignal.sendOutcome(name, new OutcomeCallback() { @Override - public void onSuccess(OutcomeEvent outcomeEvent) { + public void onSuccess(OSOutcomeEvent outcomeEvent) { if (outcomeEvent == null) callback.invoke(new WritableNativeMap()); else { @@ -553,7 +553,7 @@ public void onSuccess(OutcomeEvent outcomeEvent) { public void sendUniqueOutcome(final String name, final Callback callback) { OneSignal.sendUniqueOutcome(name, new OutcomeCallback() { @Override - public void onSuccess(OutcomeEvent outcomeEvent) { + public void onSuccess(OSOutcomeEvent outcomeEvent) { if (outcomeEvent == null) callback.invoke(new WritableNativeMap()); else { @@ -571,7 +571,7 @@ public void onSuccess(OutcomeEvent outcomeEvent) { public void sendOutcomeWithValue(final String name, final float value, final Callback callback) { OneSignal.sendOutcomeWithValue(name, value, new OutcomeCallback() { @Override - public void onSuccess(OutcomeEvent outcomeEvent) { + public void onSuccess(OSOutcomeEvent outcomeEvent) { if (outcomeEvent == null) callback.invoke(new WritableNativeMap()); else { From 3991710c173c00117a3bbfb1f69ee81c0f554855 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 10 Dec 2020 18:05:20 -0600 Subject: [PATCH 51/69] Rename `cancelNotification` to `removeNotification` Motivation: this function was renamed to be clearer --- .../java/com/geektime/rnonesignalandroid/RNOneSignal.java | 4 ++-- src/index.js | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index ebbc8562..426695f5 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -354,8 +354,8 @@ public void clearOneSignalNotifications() { } @ReactMethod - public void cancelNotification(int id) { - OneSignal.cancelNotification(id); + public void removeNotification(int id) { + OneSignal.removeNotification(id); } @ReactMethod diff --git a/src/index.js b/src/index.js index caf0523e..1c4f0bc2 100644 --- a/src/index.js +++ b/src/index.js @@ -224,13 +224,14 @@ export default class OneSignal { } } - static cancelNotification(id) { + // TO DO: add to migration guide + static removeNotification(id) { if (!checkIfInitialized(RNOneSignal)) return; if (Platform.OS === 'android') { - RNOneSignal.cancelNotification(id); + RNOneSignal.removeNotification(id); } else { - console.log("cancelNotification: this function is not supported on iOS"); + console.log("removeNotification: this function is not supported on iOS"); } } From 93f6dd8f23a17509cec604131507332191b56fc2 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 10 Dec 2020 18:28:36 -0600 Subject: [PATCH 52/69] Update Version Number to Beta 5 --- examples/RNOneSignal/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/RNOneSignal/package.json b/examples/RNOneSignal/package.json index 3b92694c..8c6f45fe 100644 --- a/examples/RNOneSignal/package.json +++ b/examples/RNOneSignal/package.json @@ -10,7 +10,7 @@ "dependencies": { "react": "16.9.0", "react-native": "^0.61.2", - "react-native-onesignal": "^4.0.0-beta.2" + "react-native-onesignal": "^4.0.0-beta.5" }, "devDependencies": { "@babel/core": "^7.5.5", diff --git a/package.json b/package.json index 6ce13dc3..2709b7ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-onesignal", - "version": "4.0.0-beta.2", + "version": "4.0.0-beta.5", "description": "React Native OneSignal SDK", "main": "src/index", "typings": "src/index.d.ts", From 90180b38fba0b40d6bf78319ad16c6ebaa198eea Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 10 Dec 2020 18:31:11 -0600 Subject: [PATCH 53/69] Remove TO DO comment --- src/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.js b/src/index.js index 1c4f0bc2..7b6f17f5 100644 --- a/src/index.js +++ b/src/index.js @@ -224,7 +224,6 @@ export default class OneSignal { } } - // TO DO: add to migration guide static removeNotification(id) { if (!checkIfInitialized(RNOneSignal)) return; From 20cc30bee9d2cec2452ac5d1273faa074283aa09 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 10 Dec 2020 22:18:33 -0600 Subject: [PATCH 54/69] Update Example App Dependencies --- examples/RNOneSignal/package.json | 8 +- examples/RNOneSignal/yarn.lock | 265 +++++++++++++++++++++++++++++- 2 files changed, 261 insertions(+), 12 deletions(-) diff --git a/examples/RNOneSignal/package.json b/examples/RNOneSignal/package.json index 8c6f45fe..06e75e39 100644 --- a/examples/RNOneSignal/package.json +++ b/examples/RNOneSignal/package.json @@ -13,13 +13,13 @@ "react-native-onesignal": "^4.0.0-beta.5" }, "devDependencies": { - "@babel/core": "^7.5.5", - "@babel/runtime": "^7.5.5", + "@babel/core": "^7.12.10", + "@babel/runtime": "^7.12.5", "@react-native-community/eslint-config": "^0.0.5", "babel-jest": "^24.9.0", - "eslint": "^6.5.1", + "eslint": "^6.8.0", "jest": "^24.9.0", - "metro-react-native-babel-preset": "^0.56.0", + "metro-react-native-babel-preset": "^0.56.4", "react-test-renderer": "16.9.0" }, "jest": { diff --git a/examples/RNOneSignal/yarn.lock b/examples/RNOneSignal/yarn.lock index 71752e3b..820b57f9 100644 --- a/examples/RNOneSignal/yarn.lock +++ b/examples/RNOneSignal/yarn.lock @@ -9,7 +9,14 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.5.5": +"@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/core@^7.0.0", "@babel/core@^7.1.0": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.4.tgz#37e864532200cb6b50ee9a4045f5f817840166ab" integrity sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ== @@ -29,6 +36,27 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.12.10": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" + integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.10" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.5" + "@babel/parser" "^7.12.10" + "@babel/template" "^7.12.7" + "@babel/traverse" "^7.12.10" + "@babel/types" "^7.12.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/generator@^7.0.0", "@babel/generator@^7.4.0", "@babel/generator@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" @@ -39,6 +67,15 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.12.10": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.10.tgz#2b188fc329fb8e4f762181703beffc0fe6df3460" + integrity sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww== + dependencies: + "@babel/types" "^7.12.10" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz#bb3faf1e74b74bd547e867e48f551fa6b098b6ce" @@ -108,6 +145,15 @@ "@babel/traverse" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + "@babel/helper-function-name@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" @@ -117,6 +163,13 @@ "@babel/template" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-get-function-arity@^7.10.4": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz#b158817a3165b5faa2047825dfa61970ddcc16cf" + integrity sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag== + dependencies: + "@babel/types" "^7.12.10" + "@babel/helper-get-function-arity@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" @@ -131,6 +184,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-member-expression-to-functions@^7.12.1": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855" + integrity sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw== + dependencies: + "@babel/types" "^7.12.7" + "@babel/helper-member-expression-to-functions@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz#356438e2569df7321a8326644d4b790d2122cb74" @@ -138,6 +198,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-module-imports@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" + integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== + dependencies: + "@babel/types" "^7.12.5" + "@babel/helper-module-imports@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz#e5a92529f8888bf319a6376abfbd1cebc491ad91" @@ -145,6 +212,21 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-module-transforms@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" + integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-simple-access" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/helper-validator-identifier" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + lodash "^4.17.19" + "@babel/helper-module-transforms@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz#8d7cdb1e1f8ea3d8c38b067345924ac4f8e0879a" @@ -157,6 +239,13 @@ "@babel/types" "^7.7.4" lodash "^4.17.13" +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz#94ca4e306ee11a7dd6e9f42823e2ac6b49881e2d" + integrity sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ== + dependencies: + "@babel/types" "^7.12.10" + "@babel/helper-optimise-call-expression@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz#034af31370d2995242aa4df402c3b7794b2dcdf2" @@ -187,6 +276,16 @@ "@babel/traverse" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-replace-supers@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz#f009a17543bbbbce16b06206ae73b63d3fca68d9" + integrity sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.12.1" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" + "@babel/helper-replace-supers@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz#3c881a6a6a7571275a72d82e6107126ec9e2cdd2" @@ -197,6 +296,13 @@ "@babel/traverse" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-simple-access@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136" + integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA== + dependencies: + "@babel/types" "^7.12.1" + "@babel/helper-simple-access@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz#a169a0adb1b5f418cfc19f22586b2ebf58a9a294" @@ -205,6 +311,13 @@ "@babel/template" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" + "@babel/helper-split-export-declaration@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" @@ -212,6 +325,11 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + "@babel/helper-wrap-function@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" @@ -222,6 +340,15 @@ "@babel/traverse" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helpers@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e" + integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" + "@babel/helpers@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302" @@ -240,11 +367,25 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== +"@babel/parser@^7.12.10", "@babel/parser@^7.12.7": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.10.tgz#824600d59e96aea26a5a2af5a9d812af05c3ae81" + integrity sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA== + "@babel/plugin-external-helpers@^7.0.0": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.7.4.tgz#8aa7aa402f0e2ecb924611cbf30942a497dfd17e" @@ -614,13 +755,20 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.5.5": +"@babel/runtime@^7.0.0": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.4.tgz#b23a856751e4bf099262f867767889c0e3fe175b" integrity sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw== dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.0.0", "@babel/template@^7.4.0", "@babel/template@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" @@ -630,6 +778,15 @@ "@babel/parser" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/template@^7.10.4", "@babel/template@^7.12.7": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" + integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.12.7" + "@babel/types" "^7.12.7" + "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" @@ -645,6 +802,21 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.10.tgz#2d1f4041e8bf42ea099e5b2dc48d6a594c00017a" + integrity sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.10" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.12.10" + "@babel/types" "^7.12.10" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + "@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" @@ -654,6 +826,15 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.5", "@babel/types@^7.12.7": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.10.tgz#7965e4a7260b26f09c56bcfcb0498af1f6d9b260" + integrity sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@cnakazawa/watch@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" @@ -2310,10 +2491,10 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@^6.5.1: - version "6.7.2" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.7.2.tgz#c17707ca4ad7b2d8af986a33feba71e18a9fecd1" - integrity sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng== +eslint@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -2808,6 +2989,11 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gensync@^1.0.0-beta.1: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -3854,6 +4040,13 @@ json5@^2.1.0: dependencies: minimist "^1.2.0" +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -4023,10 +4216,15 @@ lodash.unescape@4.0.1: integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@^4.3.0: - version "4.17.15" + version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.17.19: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -4196,7 +4394,7 @@ metro-minify-uglify@0.56.3: dependencies: uglify-es "^3.1.9" -metro-react-native-babel-preset@0.56.3, metro-react-native-babel-preset@^0.56.0: +metro-react-native-babel-preset@0.56.3: version "0.56.3" resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.56.3.tgz#5a1097c2f94e8ee0797a8ba2ab8f86d096f4c093" integrity sha512-tGPzX2ZwI8vQ8SiNVBPUIgKqmaRNVB6rtJtHCBQZAYRiMbxh0NHCUoFfKBej6U5qVgxiYYHyN8oB23evG4/Oow== @@ -4237,6 +4435,47 @@ metro-react-native-babel-preset@0.56.3, metro-react-native-babel-preset@^0.56.0: "@babel/template" "^7.0.0" react-refresh "^0.4.0" +metro-react-native-babel-preset@^0.56.4: + version "0.56.4" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.56.4.tgz#dcedc64b7ff5c0734839458e70eb0ebef6d063a8" + integrity sha512-CzbBDM9Rh6w8s1fq+ZqihAh7DDqUAcfo9pPww25+N/eJ7UK436Q7JdfxwdIPpBwLFn6o6MyYn+uwL9OEWBJarA== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-export-default-from" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.0.0" + "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-exponentiation-operator" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-object-assign" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.0.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + "@babel/template" "^7.0.0" + react-refresh "^0.4.0" + metro-react-native-babel-transformer@^0.56.0: version "0.56.3" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.56.3.tgz#e68205230be65c07290b932f7684226013dae310" @@ -4418,6 +4657,11 @@ minimist@^1.1.1, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" @@ -5323,6 +5567,11 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" From 76aaf46d9fa35ef5db760eae4daed35f2ad164f4 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 11 Dec 2020 19:49:28 -0600 Subject: [PATCH 55/69] Remove Requirement of a Callback to the `logoutEmail` function Motivation: this should never have been required --- src/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 7b6f17f5..eb144b07 100644 --- a/src/index.js +++ b/src/index.js @@ -203,7 +203,10 @@ export default class OneSignal { static logoutEmail(handler) { if (!checkIfInitialized(RNOneSignal)) return; - isValidCallback(handler); + + if (!handler) + handler = function(){}; + RNOneSignal.logoutEmail(handler); } From 9ae150feabcafef8c8ecb0576b2fa3852325a9f4 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 11 Dec 2020 19:35:47 -0600 Subject: [PATCH 56/69] Small Nit: We Should Allow for the setting of blank strings as values Motivation: tags can be removed by sending a blank string. Here we're updating the logic to allow for that --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index eb144b07..c023c9ad 100644 --- a/src/index.js +++ b/src/index.js @@ -136,7 +136,7 @@ export default class OneSignal { static sendTag(key, value) { if (!checkIfInitialized(RNOneSignal)) return; - if (!key || !value) { + if (!key || (!value && value !== "")) { console.error("OneSignal: sendTag: must include a key and a value"); } From 35919e3f3b42467fddbf552875ec57641873996b Mon Sep 17 00:00:00 2001 From: Jeasmine Nahui Date: Mon, 14 Dec 2020 15:40:02 -0300 Subject: [PATCH 57/69] Add external Id overloading method to index.js --- src/index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index c023c9ad..9580e75f 100644 --- a/src/index.js +++ b/src/index.js @@ -239,13 +239,15 @@ export default class OneSignal { /* E X T E R N A L U S E R I D */ - static setExternalUserId(externalId, handler) { + static setExternalUserId(externalId, varArg1, varArg2) { if (!checkIfInitialized(RNOneSignal)) return; - if (handler === undefined) - handler = function(){}; + if (typeof varArg1 === "function") { + RNOneSignal.setExternalUserId(externalId, null, varArg1); + return; + } - RNOneSignal.setExternalUserId(externalId, handler); + RNOneSignal.setExternalUserId(externalId, varArg1, varArg2 || function(){}); } static removeExternalUserId(handler) { From 7d8268ff8aeb1127a991a111047939a665f5be63 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 11 Dec 2020 17:24:01 -0600 Subject: [PATCH 58/69] Remove Arrow Functions in Favor of Normal Function Motivation: older devices may have older versions of Chrome which don't have support for ES6 syntax --- src/index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 9580e75f..903a5325 100644 --- a/src/index.js +++ b/src/index.js @@ -212,8 +212,15 @@ export default class OneSignal { /* N O T I F I C A T I O N S */ - static postNotification(notificationObjectString, onSuccess=()=>{}, onFailure=()=>{}) { + static postNotification(notificationObjectString, onSuccess, onFailure) { if (!checkIfInitialized(RNOneSignal)) return; + + if (!onSuccess) + onSuccess = function(){}; + + if (!onFailure) + onFailure = function(){}; + RNOneSignal.postNotification(notificationObjectString, onSuccess, onFailure); } From 3dffa7e39f8b93cff9615b34bdacf07e3f4ca9a3 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Fri, 11 Dec 2020 19:43:42 -0600 Subject: [PATCH 59/69] Make `postNotification` callbacks optional --- src/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.d.ts b/src/index.d.ts index 84249f0e..65f5d12f 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -257,7 +257,7 @@ declare module 'react-native-onesignal' { * @param {(failure:object)=>void} onFailure * @returns void */ - postNotification(notificationObjectString: string, onSuccess: (success: object) => void, onFailure: (failure: object) => void): void; + postNotification(notificationObjectString: string, onSuccess?: (success: object) => void, onFailure?: (failure: object) => void): void; /** * Android Only. iOS provides a standard way to clear notifications by clearing badge count. From a90a11a5d1c347ca90003782f327c04657afb507 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 14 Dec 2020 19:18:43 -0600 Subject: [PATCH 60/69] Update Typescript Types Motivation: Rename `cancelNotification` to `removeNotification` for clarity --- src/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.d.ts b/src/index.d.ts index 65f5d12f..8bc6fdc6 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -266,11 +266,11 @@ declare module 'react-native-onesignal' { clearOneSignalNotifications(): void; /** - * Cancels a single OneSignal notification based on its Android notification integer id. + * Removes a single OneSignal notification based on its Android notification integer id. * @param {number} id - notification id to cancel * @returns void */ - cancelNotification(id: number): void; + removeNotification(id: number): void; /** * Allows you to use your own system's user ID's to send push notifications to your users. From 70ceb0bbb30bfea72a090d6d2e7cd81e12fb8496 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Tue, 15 Dec 2020 19:40:35 -0600 Subject: [PATCH 61/69] Add authHash String as optional param in external user id function sig Motivation: update the types to reflect recent changes for user verification for setExternalUserId --- src/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.d.ts b/src/index.d.ts index 8bc6fdc6..94e35d47 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -278,7 +278,7 @@ declare module 'react-native-onesignal' { * @param {(results:object)=>void} handler * @returns void */ - setExternalUserId(externalId: string, handler?: (results: object) => void): void; + setExternalUserId(externalId: string, handlerOrAuth?: ((results: object) => void) | string, handler?: (results: object) => void): void; /** * Removes whatever was set as the current user's external user ID. From d880f283a29383290d67aa746a538748a79f3c6d Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 16 Dec 2020 14:40:31 -0600 Subject: [PATCH 62/69] Fix iOS permission status comment in types Motivation: In the typings, the values for Authorized and Denied were backwards --- src/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.d.ts b/src/index.d.ts index 94e35d47..d1aba2f3 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -3,7 +3,7 @@ declare module 'react-native-onesignal' { // 0 = None, 1 = Fatal, 2 = Errors, 3 = Warnings, 4 = Info, 5 = Debug, 6 = Verbose export type LogLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6; - // 0 = NotDetermined, 1 = Authorized, 2 = Denied, 3 = Provisional, 4 = Ephemeral + // 0 = NotDetermined, 1 = Denied, 2 = Authorized, 3 = Provisional, 4 = Ephemeral export type IosPermissionStatus = 0 | 1 | 2 | 3 | 4; // 0 = NotificationClicked, 1 = ButtonClicked From f8a8e018cf1597bd38a2ee1cd0f9c885ffc3dade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eray=20K=C3=B6se?= Date: Thu, 17 Dec 2020 21:39:25 +0300 Subject: [PATCH 63/69] Platform.OS assign fix Platform.OS is assigned to 'ios' in OSNotification.js and it affects all android settings in apps. --- src/OSNotification.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OSNotification.js b/src/OSNotification.js index eec4f0c4..ce7017f2 100644 --- a/src/OSNotification.js +++ b/src/OSNotification.js @@ -26,7 +26,7 @@ export default class OSNotification { this.androidNotificationId = receivedEvent.androidNotificationId; } - if (Platform.OS = 'ios') { + if (Platform.OS === 'ios') { this.badge = receivedEvent.badge; this.category = receivedEvent.category; this.threadId = receivedEvent.threadId; @@ -39,4 +39,4 @@ export default class OSNotification { this.contentAvailable = receivedEvent.contentAvailable; } } -} \ No newline at end of file +} From 0c1461de2b6b75b879e2fdbeace5bd29134a4f32 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 23 Dec 2020 13:55:45 -0600 Subject: [PATCH 64/69] Nil checks in iOS bridge for outcomes methods Motivation: there are multiple places in native `OneSignalOutcomeEventsController` where we call `success(nil)`. One example is calling `sendUniqueOutcome` multiple times. We should check that the `outcome` object is non-nil before passing it back to JS with the `jsonRepresentation` native method. --- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index d5cb9fb5..75a48c38 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -389,19 +389,25 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { */ RCT_EXPORT_METHOD(sendOutcome:(NSString *)name :(RCTResponseSenderBlock)callback) { [OneSignal sendOutcome:name onSuccess:^(OSOutcomeEvent *outcome){ - callback(@[[outcome jsonRepresentation]]); + if (outcome) { + callback(@[[outcome jsonRepresentation]]); + } }]; } RCT_EXPORT_METHOD(sendUniqueOutcome:(NSString *)name :(RCTResponseSenderBlock)callback) { [OneSignal sendUniqueOutcome:name onSuccess:^(OSOutcomeEvent *outcome){ - callback(@[[outcome jsonRepresentation]]); + if (outcome) { + callback(@[[outcome jsonRepresentation]]); + } }]; } RCT_EXPORT_METHOD(sendOutcomeWithValue:(NSString *)name :(NSNumber * _Nonnull)value :(RCTResponseSenderBlock)callback) { [OneSignal sendOutcomeWithValue:name value:value onSuccess:^(OSOutcomeEvent *outcome){ - callback(@[[outcome jsonRepresentation]]); + if (outcome) { + callback(@[[outcome jsonRepresentation]]); + } }]; } From 5e9d8c4a5e5b3454fe14938bbfc8aca7fdc2b384 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 23 Dec 2020 17:30:01 -0600 Subject: [PATCH 65/69] Add native logging to outcomes methods in iOS bridge Motivation: - [Context](https://bit.ly/2WJbxHG) - Adds some logging in the iOS bridge to address the case that `outcome` object is nil --- ios/RCTOneSignal/RCTOneSignalEventEmitter.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m index 75a48c38..e2ce07bd 100644 --- a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m +++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m @@ -391,7 +391,10 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal sendOutcome:name onSuccess:^(OSOutcomeEvent *outcome){ if (outcome) { callback(@[[outcome jsonRepresentation]]); + return; } + + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"sendOutcome OSOutcomeEvent is nil."]]; }]; } @@ -399,7 +402,10 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal sendUniqueOutcome:name onSuccess:^(OSOutcomeEvent *outcome){ if (outcome) { callback(@[[outcome jsonRepresentation]]); + return; } + + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"sendUniqueOutcome OSOutcomeEvent is nil."]]; }]; } @@ -407,7 +413,10 @@ + (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body { [OneSignal sendOutcomeWithValue:name value:value onSuccess:^(OSOutcomeEvent *outcome){ if (outcome) { callback(@[[outcome jsonRepresentation]]); + return; } + + [OneSignal onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"sendOutcomeWithValue OSOutcomeEvent is nil."]]; }]; } From b65018c58c4f1d6ab401625ec3af9f2d9841b2d9 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 4 Jan 2021 15:17:24 -0600 Subject: [PATCH 66/69] Add logging in Android bridge for cases where outcome object is null --- .../main/java/com/geektime/rnonesignalandroid/RNOneSignal.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 9c9a0da3..1a0c09dc 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -538,6 +538,7 @@ public void sendOutcome(final String name, final Callback callback) { public void onSuccess(OSOutcomeEvent outcomeEvent) { if (outcomeEvent == null) callback.invoke(new WritableNativeMap()); + Log.e("OneSignal", "sendOutcome OSOutcomeEvent is null"); else { try { callback.invoke(RNUtils.jsonToWritableMap(outcomeEvent.toJSONObject())); @@ -556,6 +557,7 @@ public void sendUniqueOutcome(final String name, final Callback callback) { public void onSuccess(OSOutcomeEvent outcomeEvent) { if (outcomeEvent == null) callback.invoke(new WritableNativeMap()); + Log.e("OneSignal", "sendUniqueOutcome OSOutcomeEvent is null"); else { try { callback.invoke(RNUtils.jsonToWritableMap(outcomeEvent.toJSONObject())); @@ -574,6 +576,7 @@ public void sendOutcomeWithValue(final String name, final float value, final Cal public void onSuccess(OSOutcomeEvent outcomeEvent) { if (outcomeEvent == null) callback.invoke(new WritableNativeMap()); + Log.e("OneSignal", "sendOutcomeWithValue OSOutcomeEvent is null"); else { try { callback.invoke(RNUtils.jsonToWritableMap(outcomeEvent.toJSONObject())); From ad9f9b6c27a336d7db7ecf71bcbd76a4596c566f Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 4 Jan 2021 15:55:46 -0600 Subject: [PATCH 67/69] Refactor to match iOS Motivation: we want Android bridge to match the iOS bridge. For this reason, we are removing the invocation of the callback altogether in the case that the outcome object is null. --- .../rnonesignalandroid/RNOneSignal.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java index 1a0c09dc..6a9fa4b5 100644 --- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java +++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java @@ -536,16 +536,16 @@ public void sendOutcome(final String name, final Callback callback) { OneSignal.sendOutcome(name, new OutcomeCallback() { @Override public void onSuccess(OSOutcomeEvent outcomeEvent) { - if (outcomeEvent == null) - callback.invoke(new WritableNativeMap()); - Log.e("OneSignal", "sendOutcome OSOutcomeEvent is null"); - else { + if (outcomeEvent) { try { callback.invoke(RNUtils.jsonToWritableMap(outcomeEvent.toJSONObject())); } catch (JSONException e) { Log.e("OneSignal", "sendOutcome with name: " + name + ", failed with message: " + e.getMessage()); } + return; } + + Log.e("OneSignal", "sendOutcome OSOutcomeEvent is null"); } }); } @@ -555,16 +555,16 @@ public void sendUniqueOutcome(final String name, final Callback callback) { OneSignal.sendUniqueOutcome(name, new OutcomeCallback() { @Override public void onSuccess(OSOutcomeEvent outcomeEvent) { - if (outcomeEvent == null) - callback.invoke(new WritableNativeMap()); - Log.e("OneSignal", "sendUniqueOutcome OSOutcomeEvent is null"); - else { + if (outcomeEvent) { try { callback.invoke(RNUtils.jsonToWritableMap(outcomeEvent.toJSONObject())); } catch (JSONException e) { Log.e("OneSignal", "sendUniqueOutcome with name: " + name + ", failed with message: " + e.getMessage()); } + return; } + + Log.e("OneSignal", "sendUniqueOutcome OSOutcomeEvent is null"); } }); } @@ -574,16 +574,16 @@ public void sendOutcomeWithValue(final String name, final float value, final Cal OneSignal.sendOutcomeWithValue(name, value, new OutcomeCallback() { @Override public void onSuccess(OSOutcomeEvent outcomeEvent) { - if (outcomeEvent == null) - callback.invoke(new WritableNativeMap()); - Log.e("OneSignal", "sendOutcomeWithValue OSOutcomeEvent is null"); - else { + if (outcomeEvent) { try { callback.invoke(RNUtils.jsonToWritableMap(outcomeEvent.toJSONObject())); } catch (JSONException e) { Log.e("OneSignal", "sendOutcomeWithValue with name: " + name + " and value: " + value + ", failed with message: " + e.getMessage()); } + return; } + + Log.e("OneSignal", "sendOutcomeWithValue OSOutcomeEvent is null"); } }); } From f8b33b6558d0ea1dc6a2d578eafadb83843c689d Mon Sep 17 00:00:00 2001 From: Rodrigo Gomez Palacio Date: Tue, 5 Jan 2021 17:31:26 -0600 Subject: [PATCH 68/69] Typescript Example App (#1128) * Initial Commit - Entire TS Example App * Update Yarn Lock to use latest Beta (beta 5) * Delete Non-TS Example App Motivation: moving forward we will only maintain the TS version * Refactor TS Example App Includes buttons for many functions * OSConsole to log events and variables * Finished Setting up Demo App * Update .gitignore Motivation: update .gitignore to ignore files from new example app * Commit XCode Config & Files * Commit Info.plist, Podfile lock file, and other project files * Add Error Handling for Getting Trigger Value For Key Motivation: Example app - add error handling for rejected `getTriggerValueForKey` promise. Also, remove JSON.stringify around second param to logging function as value is already stringified automatically inside that function. * Add Clear Handlers to Component Will Unmount Motivation: to avoid aggregating handlers/listeners, it is good practice to remove them before a component unmounts in the `componentWillUnmount` * Cross-Platform Conditional Formatting for Console Text * Add Location Permissions to Config Files Motivation: we want the example app to work with location out of the box. See reference: https://documentation.onesignal.com/docs/sdk-reference#location-data --- .gitignore | 19 +- examples/RNOneSignal/.flowconfig | 99 - examples/RNOneSignal/.yarnclean | 44 - examples/RNOneSignal/App.js | 676 --- examples/RNOneSignal/Util.js | 6 - .../java/com/rnonesignal/MainActivity.java | 15 - .../java/com/rnonesignal/MainApplication.java | 50 - .../app/src/main/res/values/strings.xml | 3 - examples/RNOneSignal/android/settings.gradle | 5 - examples/RNOneSignal/app.json | 4 - examples/RNOneSignal/ios/Podfile | 46 - examples/RNOneSignal/ios/Podfile.lock | 348 -- .../ios/RNOneSignal.xcodeproj/project.pbxproj | 494 -- .../RNOneSignal/Base.lproj/LaunchScreen.xib | 42 - examples/RNOneSignal/package.json | 28 - .../.buckconfig | 0 .../.eslintrc.js | 2 + .../.gitattributes | 0 .../{RNOneSignal => RNOneSignalTS}/.gitignore | 6 +- .../.prettierrc.js | 0 .../.watchmanconfig | 0 examples/RNOneSignalTS/__tests__/App-test.tsx | 14 + .../BUCK => RNOneSignalTS/android/app/_BUCK} | 4 +- .../android/app/build.gradle | 47 +- .../android/app/build_defs.bzl | 0 .../android/app/proguard-rules.pro | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../com/rnonesignalts/ReactNativeFlipper.java | 72 + .../android/app/src/main/AndroidManifest.xml | 6 +- .../java/com/rnonesignalts/MainActivity.java | 15 + .../com/rnonesignalts/MainApplication.java | 80 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 0 .../android/build.gradle | 11 +- .../android/gradle.properties | 7 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../android/gradlew | 35 +- .../android/gradlew.bat | 5 +- .../RNOneSignalTS/android/settings.gradle | 3 + examples/RNOneSignalTS/app.json | 4 + .../babel.config.js | 0 .../{RNOneSignal => RNOneSignalTS}/index.js | 2 +- .../Info.plist | 0 .../NotificationService.h | 3 +- .../NotificationService.m | 0 examples/RNOneSignalTS/ios/Podfile | 33 + examples/RNOneSignalTS/ios/Podfile.lock | 473 ++ .../ios/RNOneSignalTS-tvOS}/Info.plist | 8 - .../ios/RNOneSignalTS-tvOSTests/Info.plist | 24 + .../RNOneSignalTS.xcodeproj/project.pbxproj | 985 +++ .../xcschemes/RNOneSignalTS-tvOS.xcscheme} | 69 +- .../xcschemes/RNOneSignalTS.xcscheme} | 69 +- .../contents.xcworkspacedata | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist} | 4 +- .../ios/RNOneSignalTS}/AppDelegate.h | 7 - .../ios/RNOneSignalTS}/AppDelegate.m | 32 +- .../AppIcon.appiconset/Contents.json | 0 .../Images.xcassets/Contents.json | 0 .../ios/RNOneSignalTS/Info.plist | 68 + .../ios/RNOneSignalTS/LaunchScreen.storyboard | 58 + .../RNOneSignalTS/RNOneSignalTS.entitlements} | 6 - .../ios/RNOneSignalTS}/main.m | 7 - .../ios/RNOneSignalTSTests/Info.plist | 24 + .../RNOneSignalTSTests/RNOneSignalTSTests.m | 65 + .../metro.config.js | 0 examples/RNOneSignalTS/package.json | 44 + examples/RNOneSignalTS/src/App.tsx | 83 + examples/RNOneSignalTS/src/Helpers.tsx | 64 + examples/RNOneSignalTS/src/OSButtons.tsx | 417 ++ examples/RNOneSignalTS/src/OSConsole.tsx | 86 + examples/RNOneSignalTS/src/OSDemo.tsx | 164 + .../src/models/SubscribeFields.tsx | 4 + examples/RNOneSignalTS/tsconfig.json | 62 + .../{RNOneSignal => RNOneSignalTS}/yarn.lock | 5333 +++++++++-------- 85 files changed, 5712 insertions(+), 4680 deletions(-) delete mode 100644 examples/RNOneSignal/.flowconfig delete mode 100644 examples/RNOneSignal/.yarnclean delete mode 100644 examples/RNOneSignal/App.js delete mode 100644 examples/RNOneSignal/Util.js delete mode 100644 examples/RNOneSignal/android/app/src/main/java/com/rnonesignal/MainActivity.java delete mode 100644 examples/RNOneSignal/android/app/src/main/java/com/rnonesignal/MainApplication.java delete mode 100644 examples/RNOneSignal/android/app/src/main/res/values/strings.xml delete mode 100644 examples/RNOneSignal/android/settings.gradle delete mode 100644 examples/RNOneSignal/app.json delete mode 100644 examples/RNOneSignal/ios/Podfile delete mode 100644 examples/RNOneSignal/ios/Podfile.lock delete mode 100644 examples/RNOneSignal/ios/RNOneSignal.xcodeproj/project.pbxproj delete mode 100644 examples/RNOneSignal/ios/RNOneSignal/Base.lproj/LaunchScreen.xib delete mode 100644 examples/RNOneSignal/package.json rename examples/{RNOneSignal => RNOneSignalTS}/.buckconfig (100%) rename examples/{RNOneSignal => RNOneSignalTS}/.eslintrc.js (50%) rename examples/{RNOneSignal => RNOneSignalTS}/.gitattributes (100%) rename examples/{RNOneSignal => RNOneSignalTS}/.gitignore (94%) rename examples/{RNOneSignal => RNOneSignalTS}/.prettierrc.js (100%) rename examples/{RNOneSignal => RNOneSignalTS}/.watchmanconfig (100%) create mode 100644 examples/RNOneSignalTS/__tests__/App-test.tsx rename examples/{RNOneSignal/android/app/BUCK => RNOneSignalTS/android/app/_BUCK} (94%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/build.gradle (85%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/build_defs.bzl (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/proguard-rules.pro (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/debug/AndroidManifest.xml (100%) create mode 100644 examples/RNOneSignalTS/android/app/src/debug/java/com/rnonesignalts/ReactNativeFlipper.java rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/AndroidManifest.xml (84%) create mode 100644 examples/RNOneSignalTS/android/app/src/main/java/com/rnonesignalts/MainActivity.java create mode 100644 examples/RNOneSignalTS/android/app/src/main/java/com/rnonesignalts/MainApplication.java rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png (100%) create mode 100644 examples/RNOneSignalTS/android/app/src/main/res/values/strings.xml rename examples/{RNOneSignal => RNOneSignalTS}/android/app/src/main/res/values/styles.xml (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/build.gradle (79%) rename examples/{RNOneSignal => RNOneSignalTS}/android/gradle.properties (71%) rename examples/{RNOneSignal => RNOneSignalTS}/android/gradle/wrapper/gradle-wrapper.jar (100%) rename examples/{RNOneSignal => RNOneSignalTS}/android/gradle/wrapper/gradle-wrapper.properties (80%) rename examples/{RNOneSignal => RNOneSignalTS}/android/gradlew (83%) rename examples/{RNOneSignal => RNOneSignalTS}/android/gradlew.bat (91%) create mode 100644 examples/RNOneSignalTS/android/settings.gradle create mode 100644 examples/RNOneSignalTS/app.json rename examples/{RNOneSignal => RNOneSignalTS}/babel.config.js (100%) rename examples/{RNOneSignal => RNOneSignalTS}/index.js (84%) rename examples/{RNOneSignal => RNOneSignalTS}/ios/OneSignalNotificationServiceExtension/Info.plist (100%) rename examples/{RNOneSignal => RNOneSignalTS}/ios/OneSignalNotificationServiceExtension/NotificationService.h (66%) rename examples/{RNOneSignal => RNOneSignalTS}/ios/OneSignalNotificationServiceExtension/NotificationService.m (100%) create mode 100644 examples/RNOneSignalTS/ios/Podfile create mode 100644 examples/RNOneSignalTS/ios/Podfile.lock rename examples/{RNOneSignal/ios/RNOneSignal => RNOneSignalTS/ios/RNOneSignalTS-tvOS}/Info.plist (88%) create mode 100644 examples/RNOneSignalTS/ios/RNOneSignalTS-tvOSTests/Info.plist create mode 100644 examples/RNOneSignalTS/ios/RNOneSignalTS.xcodeproj/project.pbxproj rename examples/{RNOneSignal/ios/RNOneSignal.xcodeproj/xcshareddata/xcschemes/RNOneSignal-tvOS.xcscheme => RNOneSignalTS/ios/RNOneSignalTS.xcodeproj/xcshareddata/xcschemes/RNOneSignalTS-tvOS.xcscheme} (51%) rename examples/{RNOneSignal/ios/RNOneSignal.xcodeproj/xcshareddata/xcschemes/RNOneSignal.xcscheme => RNOneSignalTS/ios/RNOneSignalTS.xcodeproj/xcshareddata/xcschemes/RNOneSignalTS.xcscheme} (51%) rename examples/{RNOneSignal/ios/RNOneSignal.xcworkspace => RNOneSignalTS/ios/RNOneSignalTS.xcworkspace}/contents.xcworkspacedata (78%) rename examples/{RNOneSignal/ios/OneSignalNotificationServiceExtension/OneSignalNotificationServiceExtension.entitlements => RNOneSignalTS/ios/RNOneSignalTS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist} (66%) rename examples/{RNOneSignal/ios/RNOneSignal => RNOneSignalTS/ios/RNOneSignalTS}/AppDelegate.h (50%) rename examples/{RNOneSignal/ios/RNOneSignal => RNOneSignalTS/ios/RNOneSignalTS}/AppDelegate.m (54%) rename examples/{RNOneSignal/ios/RNOneSignal => RNOneSignalTS/ios/RNOneSignalTS}/Images.xcassets/AppIcon.appiconset/Contents.json (100%) rename examples/{RNOneSignal/ios/RNOneSignal => RNOneSignalTS/ios/RNOneSignalTS}/Images.xcassets/Contents.json (100%) create mode 100644 examples/RNOneSignalTS/ios/RNOneSignalTS/Info.plist create mode 100644 examples/RNOneSignalTS/ios/RNOneSignalTS/LaunchScreen.storyboard rename examples/{RNOneSignal/ios/RNOneSignal/RNOneSignal.entitlements => RNOneSignalTS/ios/RNOneSignalTS/RNOneSignalTS.entitlements} (58%) rename examples/{RNOneSignal/ios/RNOneSignal => RNOneSignalTS/ios/RNOneSignalTS}/main.m (51%) create mode 100644 examples/RNOneSignalTS/ios/RNOneSignalTSTests/Info.plist create mode 100644 examples/RNOneSignalTS/ios/RNOneSignalTSTests/RNOneSignalTSTests.m rename examples/{RNOneSignal => RNOneSignalTS}/metro.config.js (100%) create mode 100644 examples/RNOneSignalTS/package.json create mode 100644 examples/RNOneSignalTS/src/App.tsx create mode 100644 examples/RNOneSignalTS/src/Helpers.tsx create mode 100644 examples/RNOneSignalTS/src/OSButtons.tsx create mode 100644 examples/RNOneSignalTS/src/OSConsole.tsx create mode 100644 examples/RNOneSignalTS/src/OSDemo.tsx create mode 100644 examples/RNOneSignalTS/src/models/SubscribeFields.tsx create mode 100644 examples/RNOneSignalTS/tsconfig.json rename examples/{RNOneSignal => RNOneSignalTS}/yarn.lock (58%) diff --git a/.gitignore b/.gitignore index b658d0bb..6cb7556c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,15 +15,16 @@ examples/CocoapodsDemo/ios/CocoapodsDemo.xcodeproj/xcuserdata examples/CocoapodsDemo/ios/CocoapodsDemo.xcworkspace/xcshareddata examples/CocoapodsDemo/ios/CocoapodsDemo.xcworkspace/xcuserdata examples/CocoapodsDemo/ios/Pods/Pods.xcodeproj/xcuserdata -examples/RNOneSignal/android/app/build -examples/RNOneSignal/android/.gradle -examples/RNOneSignal/android/.idea -examples/RNOneSignal/android/build -examples/RNOneSignal/ios/RNOneSignal.xcodeproj/project.xcworkspace/xcshareddata -examples/RNOneSignal/ios/RNOneSignal.xcodeproj/project.xcworkspace/xcuserdata -examples/RNOneSignal/ios/RNOneSignal.xcodeproj/xcuserdata -examples/RNOneSignal/ios/RNOneSignal.xcworkspace/xcshareddata -examples/RNOneSignal/ios/RNOneSignal.xcworkspace/xcuserdata +examples/RNOneSignalTS/android/app/build +examples/RNOneSignalTS/android/app/debug.keystore +examples/RNOneSignalTS/android/.gradle +examples/RNOneSignalTS/android/.idea +examples/RNOneSignalTS/android/build +examples/RNOneSignalTS/ios/RNOneSignal.xcodeproj/project.xcworkspace/xcshareddata +examples/RNOneSignalTS/ios/RNOneSignal.xcodeproj/project.xcworkspace/xcuserdata +examples/RNOneSignalTS/ios/RNOneSignal.xcodeproj/xcuserdata +examples/RNOneSignalTS/ios/RNOneSignal.xcworkspace/xcshareddata +examples/RNOneSignalTS/ios/RNOneSignal.xcworkspace/xcuserdata ios/RCTOneSignal.xcodeproj/project.xcworkspace/xcshareddata examples/RNOneSignal/ios/Pods/Pods.xcodeproj/xcuserdata android/.idea diff --git a/examples/RNOneSignal/.flowconfig b/examples/RNOneSignal/.flowconfig deleted file mode 100644 index 1319ea12..00000000 --- a/examples/RNOneSignal/.flowconfig +++ /dev/null @@ -1,99 +0,0 @@ -[ignore] -; We fork some components by platform -.*/*[.]android.js - -; Ignore "BUCK" generated dirs -/\.buckd/ - -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -node_modules/react-native/Libraries/react-native/React.js - -; Ignore polyfills -node_modules/react-native/Libraries/polyfills/.* - -; These should not be required directly -; require from fbjs/lib instead: require('fbjs/lib/warning') -node_modules/warning/.* - -; Flow doesn't support platforms -.*/Libraries/Utilities/HMRLoadingView.js - -[untyped] -.*/node_modules/@react-native-community/cli/.*/.* - -[include] - -[libs] -node_modules/react-native/Libraries/react-native/react-native-interface.js -node_modules/react-native/flow/ - -[options] -emoji=true - -esproposal.optional_chaining=enable -esproposal.nullish_coalescing=enable - -module.file_ext=.js -module.file_ext=.json -module.file_ext=.ios.js - -module.system=haste -module.system.haste.use_name_reducers=true -# get basename -module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' -# strip .js or .js.flow suffix -module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' -# strip .ios suffix -module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' -module.system.haste.paths.blacklist=.*/__tests__/.* -module.system.haste.paths.blacklist=.*/__mocks__/.* -module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* -module.system.haste.paths.whitelist=/node_modules/react-native/RNTester/.* -module.system.haste.paths.whitelist=/node_modules/react-native/IntegrationTests/.* -module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* - -munge_underscores=true - -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FlowFixMeProps -suppress_type=$FlowFixMeState - -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ -suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError - -[lints] -sketchy-null-number=warn -sketchy-null-mixed=warn -sketchy-number=warn -untyped-type-import=warn -nonstrict-import=warn -deprecated-type=warn -unsafe-getters-setters=warn -inexact-spread=warn -unnecessary-invariant=warn -signature-verification-failure=warn -deprecated-utility=error - -[strict] -deprecated-type -nonstrict-import -sketchy-null -unclear-type -unsafe-getters-setters -untyped-import -untyped-type-import - -[version] -^0.98.0 diff --git a/examples/RNOneSignal/.yarnclean b/examples/RNOneSignal/.yarnclean deleted file mode 100644 index 3d1e1cd5..00000000 --- a/examples/RNOneSignal/.yarnclean +++ /dev/null @@ -1,44 +0,0 @@ -# test directories -__tests__ -test -tests -powered-test - -# asset directories -docs -doc -website -images - -# examples -example -examples - -# code coverage directories -coverage -.nyc_output - -# build scripts -Makefile -Gulpfile.js -Gruntfile.js - -# configs -appveyor.yml -circle.yml -codeship-services.yml -codeship-steps.yml -wercker.yml -.tern-project -.gitattributes -.editorconfig -.*ignore -.eslintrc -.jshintrc -.flowconfig -.documentup.json -.yarn-metadata.json -.travis.yml - -# misc -*.md diff --git a/examples/RNOneSignal/App.js b/examples/RNOneSignal/App.js deleted file mode 100644 index 56d2f694..00000000 --- a/examples/RNOneSignal/App.js +++ /dev/null @@ -1,676 +0,0 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - * - * @format - * @flow - */ - -import React, { Component } from 'react'; -import { - Platform, - StyleSheet, - Text, - View, - ScrollView, - KeyboardAvoidingView, - TextInput, - Image, - Button, -} from 'react-native'; -import OneSignal from 'react-native-onesignal'; -import { sleep } from './Util'; - -const imageUri = 'https://cdn-images-1.medium.com/max/300/1*7xHdCFeYfD8zrIivMiQcCQ.png'; -const buttonColor = Platform.OS == 'ios' ? '#3C8AE7' : '#D45653'; -const textInputBorderColor = Platform.OS == 'ios' ? '#3C8AE7' : '#D45653'; -const disabledColor = '#BEBEBE'; - -/** - Change to desired app id (dashboard app) - React Native Demo App: ce8572ae-ff57-4e77-a265-5c91f00ecc4c - */ -var appId = 'ce8572ae-ff57-4e77-a265-5c91f00ecc4c'; - -/** - Controls whether the app needs privacy consent or not - Will hide the button when false and show it when true - */ -var requiresPrivacyConsent = false; - -export default class App extends Component { - - constructor(properties) { - super(properties); - - this.state = { - /* OneSignal states*/ - // Privacy Consent states - hasPrivacyConsent: false, // App starts without privacy consent - isPrivacyConsentLoading: requiresPrivacyConsent, - - // Device states - userId: '', - pushToken: '', - - // Subscription states - isSubscribed: false, - isSubscriptionLoading: false, - - // External User Id states - externalUserId: '', - isExternalUserIdLoading: false, - - // Email states - email: '', - isEmailLoading: false, - - // In-App Messaging states - iamPaused: false, - - // Demo App states - debugText: '' - - // Add more states here... - }; - - } - - /* R E A C T L I F E C Y C L E */ - - async componentDidMount() { - console.log("Mounted!"); - /* O N E S I G N A L S E T U P */ - // Log level logcat is 6 (VERBOSE) and log level alert is 0 (NONE) - OneSignal.setLogLevel(6, 0); - OneSignal.setAppId(appId); - OneSignal.setRequiresUserPrivacyConsent(requiresPrivacyConsent); - OneSignal.setLocationShared(true); - OneSignal.promptForPushNotificationsWithUserResponse(response => { - console.log("Prompt response:", response); - }); - /* O N E S I G N A L H A N D L E R S */ - OneSignal.setNotificationWillShowInForegroundHandler(notifReceivedEvent => { - console.log("OneSignal: notification will show in foreground:", notifReceivedEvent); - let notif = notifReceivedEvent.getNotification(); - setTimeout(()=>notifReceivedEvent.complete(notif), 0); - }); - OneSignal.setNotificationOpenedHandler(notification => { - console.log("OneSignal: notification opened:", notification); - }); - OneSignal.setInAppMessageClickHandler(event => { - console.log("OneSignal IAM clicked:", event); - }); - OneSignal.addEmailSubscriptionObserver((event) => { - console.log("OneSignal: email subscription changed: ", event); - }); - OneSignal.addSubscriptionObserver(event => { - console.log("OneSignal: subscription changed:", event); - if (Platform.OS === "android") { - this.setState({ isSubscribed: event.to.isSubscribed }); - } else { - this.setState({ isSubscribed: event.subscribed }); - } - }); - OneSignal.addPermissionObserver(event => { - console.log("OneSignal: permission changed:", event); - }); - - //If the app requires privacy consent check if it has been set yet - if (requiresPrivacyConsent) { - // async 'then' is only so I can sleep using the Promise helper method - OneSignal.userProvidedPrivacyConsent().then(async (granted) => { - // For UI testing purposes wait X seconds to see the loading state - await sleep(0); - - console.log('OneSignal: Privacy Consent status: ' + granted); - this.setState({hasPrivacyConsent:granted, isPrivacyConsentLoading:false}); - }); - } - - let deviceState = await OneSignal.getDeviceState(); - this.setState({ - isSubscribed: deviceState.isSubscribed, - userId : deviceState.userId - }); - - // Examples for using native IAM public methods - // this.oneSignalInAppMessagingExamples(); - - // Examples for using native Outcome Event public methods - // this.oneSignalOutcomeEventsExamples(); - - } - - componentWillUnmount() { - OneSignal.clearHandlers(); - } - - /* H E L P E R S */ - - /** - Validate email method - */ - validateEmail(email) { - var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - return re.test(String(email).toLowerCase()); - } - - /** - In-App Message public method examples - */ - oneSignalInAppMessagingExamples() { - // Add a single trigger with a value associated with it - OneSignal.addTrigger('trigger1', 'one'); - - // Get trigger value for the key - OneSignal.getTriggerValueForKey('trigger1') - .then(response => { - console.log('trigger1 value: ' + response); - }) - .catch(e => { - console.error(e); - }); - - // Create a set of triggers in a map and add them all at once - var triggers = { - trigger2: '2', - trigger3: true, - }; - OneSignal.addTriggers(triggers); - - // Get trigger value for the key - OneSignal.getTriggerValueForKey('trigger3') - .then(response => { - console.log('trigger3 value: ' + response); - }) - .catch(e => { - console.error(e); - }); - - // Create an array of keys to remove triggers for - var removeTriggers = ['trigger1', 'trigger2']; - OneSignal.removeTriggersForKeys(removeTriggers); - } - - /** - Outcomes public method examples - */ - oneSignalOutcomeEventsExamples() { - // Send an outcome event with and without a callback - OneSignal.sendOutcome('normal_1'); - OneSignal.sendOutcome('normal_2', response => { - console.log('Normal outcome sent successfully!'); - console.log(response); - }); - - // Send a unique outcome event with and without a callback - OneSignal.sendUniqueOutcome('unique_1'); - OneSignal.sendUniqueOutcome('unique_2', response => { - console.log('Unique outcome sent successfully!'); - console.log(response); - }); - - // Send an outcome event with and without a callback - OneSignal.sendOutcomeWithValue('value_1', 9.99); - OneSignal.sendOutcomeWithValue('value_2', 5, response => { - console.log('Outcome with value sent successfully!'); - console.log(response); - }); - } - - render() { - return ( - - { this.createTitleFields() } - - - { this.createSubscribeFields() } - { this.createPrivacyConsentFields() } - { this.createEmailFields() } - { this.createExternalUserIdFields() } - { this.createSubscriptionElements() } - { this.createNotificationElements() } - - - - ); - } - - /** - Create a red OneSignal Button with a name, loading state, and callback (onPress) - */ - renderButtonView = (name, isLoading, callback) => { - let isPrivacyConsentButton = name.includes("Consent"); - - if (isPrivacyConsentButton && !requiresPrivacyConsent) - return null; - - let isClickable = !isLoading - && (!requiresPrivacyConsent - || this.state.hasPrivacyConsent - || isPrivacyConsentButton); - - return ( - - -