diff --git a/README.md b/README.md
index 3d5457bb..71f4ce47 100755
--- a/README.md
+++ b/README.md
@@ -335,14 +335,12 @@ export default class App extends Component {
componentWillMount() {
OneSignal.addEventListener('received', this.onReceived);
OneSignal.addEventListener('opened', this.onOpened);
- OneSignal.addEventListener('registered', this.onRegistered);
OneSignal.addEventListener('ids', this.onIds);
}
componentWillUnmount() {
OneSignal.removeEventListener('received', this.onReceived);
OneSignal.removeEventListener('opened', this.onOpened);
- OneSignal.removeEventListener('registered', this.onRegistered);
OneSignal.removeEventListener('ids', this.onIds);
}
@@ -357,10 +355,6 @@ export default class App extends Component {
console.log('openResult: ', openResult);
}
- onRegistered(notifData) {
- console.log("Device had been registered for push notifications!", notifData);
- }
-
onIds(device) {
console.log('Device info: ', device);
}
@@ -435,6 +429,36 @@ Sync hashed email if you have a login system or collect it. Will be used to reac
OneSignal.syncHashedEmail("test@domain.com");
```
+### Using Email Features
+
+OneSignal now allows you to send emails to your userbase. This email can be set using the OneSignal react-native SDK.
+
+To set the email:
+
+```javascript
+let emailAuthCode = ""; //Your email auth code should be securely generated by your backend server
+
+OneSignal.setEmail("test@test.com", emailAuthCode, {(error) => {
+ //handle error if it occurred
+}});
+```
+
+If you don't want to implement email auth hashing on your backend (which is heavily recommended), you can still use the OneSignal email feature in an unauthenticated state like this:
+
+```javascript
+OneSignal.setEmail("test@test.com", {(error) => {
+ //handle error if it occurred
+}});
+```
+
+If your application implements logout functionality, you can logout of the OneSignal email for this user using the logout function:
+
+```javascript
+OneSignal.logoutEmail({(error) => {
+ //handle error if it occurred
+}});
+```
+
### Getting Player ID and Push Token
We exposed the idsAvailable API of OneSignal (both Android & iOS) as an event.
diff --git a/android/build.gradle b/android/build.gradle
index 9c4bb15c..025bccc9 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -5,7 +5,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.1.0'
+ classpath 'com.android.tools.build:gradle:2.2.2'
}
}
@@ -36,9 +36,9 @@ android {
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.facebook.react:react-native:+'
- compile 'com.onesignal:OneSignal:3.+@aar'
compile 'com.google.android.gms:play-services-gcm:+'
compile 'com.google.android.gms:play-services-analytics:+'
compile 'com.google.android.gms:play-services-location:+'
testCompile 'junit:junit:4.12'
+ compile 'com.onesignal:OneSignal:3.+@aar'
}
diff --git a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java
index ec9daef8..38625a04 100644
--- a/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java
+++ b/android/src/main/java/com/geektime/rnonesignalandroid/RNOneSignal.java
@@ -24,6 +24,8 @@
import com.onesignal.OSPermissionSubscriptionState;
import com.onesignal.OSSubscriptionState;
import com.onesignal.OneSignal;
+import com.onesignal.OneSignal.EmailUpdateHandler;
+import com.onesignal.OneSignal.EmailUpdateError;
import org.json.JSONObject;
import org.json.JSONException;
@@ -53,6 +55,7 @@ public RNOneSignal(ReactApplicationContext reactContext) {
// 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() {
+
Activity activity = getCurrentActivity();
if (activity == null || oneSignalInitDone)
return;
@@ -98,6 +101,66 @@ public void tagsAvailable(JSONObject tags) {
});
}
+ @ReactMethod
+ public void setUnauthenticatedEmail(String email, final Callback callback) {
+ OneSignal.setEmail(email, null, new OneSignal.EmailUpdateHandler() {
+ @Override
+ public void onSuccess() {
+ callback.invoke();
+ }
+
+ @Override
+ public void onFailure(EmailUpdateError error) {
+ try {
+ JSONObject errorObject = new JSONObject("{'error' : '" + error.getMessage() + "'}");
+ callback.invoke(RNUtils.jsonToWritableMap(errorObject));
+ } catch (JSONException exception) {
+ exception.printStackTrace();
+ }
+ }
+ });
+ }
+
+ @ReactMethod
+ public void setEmail(String email, String emailAuthToken, final Callback callback) {
+ OneSignal.setEmail(email, emailAuthToken, new EmailUpdateHandler() {
+ @Override
+ public void onSuccess() {
+ callback.invoke();
+ }
+
+ @Override
+ public void onFailure(EmailUpdateError error) {
+ try {
+ JSONObject errorObject = new JSONObject("{'error' : '" + error.getMessage() + "'}");
+ callback.invoke(RNUtils.jsonToWritableMap(errorObject));
+ } catch (JSONException exception) {
+ exception.printStackTrace();
+ }
+ }
+ });
+ }
+
+ @ReactMethod
+ public void logoutEmail(final Callback callback) {
+ OneSignal.logoutEmail(new EmailUpdateHandler() {
+ @Override
+ public void onSuccess() {
+ callback.invoke();
+ }
+
+ @Override
+ public void onFailure(EmailUpdateError error) {
+ try {
+ JSONObject errorObject = new JSONObject("{'error' : '" + error.getMessage() + "'}");
+ callback.invoke(RNUtils.jsonToWritableMap(errorObject));
+ } catch (JSONException exception) {
+ exception.printStackTrace();
+ }
+ }
+ });
+ }
+
@ReactMethod
public void configure() {
OneSignal.idsAvailable(new OneSignal.IdsAvailableHandler() {
@@ -178,7 +241,7 @@ public void syncHashedEmail(String email) {
}
@ReactMethod
- public void setlogLevel(int logLevel, int visualLogLevel) {
+ public void setLogLevel(int logLevel, int visualLogLevel) {
OneSignal.setLogLevel(logLevel, visualLogLevel);
}
diff --git a/examples/RNOneSignal/index.android.js b/examples/RNOneSignal/index.android.js
index edd7c9b8..d84f07d5 100644
--- a/examples/RNOneSignal/index.android.js
+++ b/examples/RNOneSignal/index.android.js
@@ -9,25 +9,71 @@ import {
AppRegistry,
StyleSheet,
Text,
- View
+ View,
+ Button,
+ Image,
+ TextInput,
+ Dimensions,
+ KeyboardAvoidingView,
+ ActivityIndicator,
+ Platform,
+ ScrollView,
+ Linking
} from 'react-native';
import OneSignal from 'react-native-onesignal';
+let imageUri = 'https://media.licdn.com/media/AAEAAQAAAAAAAAyOAAAAJDJhY2JlMmJjLWI1NzctNGNmNC1iMDU1LWE4NjI4Nzc1YTU2Zg.png'
+
export default class RNOneSignal extends Component {
-
+ constructor(properties) {
+ super(properties);
+ }
+
+ 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());
+ }
+
componentWillMount() {
+ console.log("setting log level");
+ OneSignal.setLogLevel(7, 0);
+ this.setState({emailEnabled: false,
+ animatingEmailButton : false,
+ initialOpenFromPush : "Did NOT open from push",
+ activityWidth : 0,
+ width: 0,
+ activityMargin: 0,
+ buttonColor : Platform.OS == "ios" ? "#ffffff" : "#d45653",
+ jsonDebugText : ""
+ });
+ OneSignal.setLocationShared(true);
+
+
+ OneSignal.inFocusDisplaying(2)
+ }
+
+ componentDidMount() {
+ this.onReceived = this.onReceived.bind(this);
+ this.onOpened = this.onOpened.bind(this);
+ this.onIds = this.onIds.bind(this);
+ this.onEmailRegistrationChange = this.onEmailRegistrationChange.bind(this);
+
OneSignal.addEventListener('received', this.onReceived);
OneSignal.addEventListener('opened', this.onOpened);
- OneSignal.addEventListener('registered', this.onRegistered);
OneSignal.addEventListener('ids', this.onIds);
+ OneSignal.addEventListener('emailSubscription', this.onEmailRegistrationChange);
}
componentWillUnmount() {
OneSignal.removeEventListener('received', this.onReceived);
OneSignal.removeEventListener('opened', this.onOpened);
- OneSignal.removeEventListener('registered', this.onRegistered);
OneSignal.removeEventListener('ids', this.onIds);
+ OneSignal.removeEventListener('emailSubscription', this.onEmailRegistrationChange);
+ }
+
+ onEmailRegistrationChange(registration) {
+ console.log("onEmailRegistrationChange: ", registration);
}
onReceived(notification) {
@@ -41,36 +87,136 @@ export default class RNOneSignal extends Component {
console.log('openResult: ', openResult);
}
- onRegistered(notifData) {
- console.log("Device had been registered for push notifications!", notifData);
- }
-
onIds(device) {
console.log('Device info: ', device);
}
render() {
return (
-
-
- Welcome to React Native!
-
-
- To get started, edit index.android.js
-
-
- Double tap R on your keyboard to reload,{'\n'}
- Shake or press menu button for dev menu
-
-
+
+
+
+
+
+
+ Welcome to React Native!
+
+
+ To get started, edit index.android.js
+
+
+ Double tap R on your keyboard to reload,{'\n'}
+ Shake or press menu button for dev menu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ console.log("New text: ", newText, ", is valid email? ", this.validateEmail(newText));
+ this.setState({emailEnabled : this.validateEmail(newText), email : newText});
+ }}
+ />
+
+
+
+
+ {this.state.jsonDebugText}
+
+
+
);
}
}
const styles = StyleSheet.create({
+ scrollView: {
+ backgroundColor: '#F5FCFF'
+ },
container: {
flex: 1,
- justifyContent: 'center',
+ flexDirection: 'column',
+ justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
@@ -83,7 +229,35 @@ const styles = StyleSheet.create({
textAlign: 'center',
color: '#333333',
marginBottom: 5,
+ marginHorizontal: 10
+ },
+ jsonDebugLabelText: {
+ textAlign: 'left',
+ color: '#333333',
+ marginBottom: 5,
+ marginHorizontal: 10
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ overflow: 'hidden',
+ borderRadius: 10,
+ marginVertical: 10,
+ marginHorizontal: 10,
+ backgroundColor: "#d45653"
},
+ button: {
+ color: '#000000',
+ flex: 1
+ },
+ imageStyle: {
+ height: 200,
+ width: 200,
+ marginTop: 20
+ },
+ textInput: {
+ marginHorizontal: 10,
+ height: 40
+ }
});
AppRegistry.registerComponent('RNOneSignal', () => RNOneSignal);
diff --git a/examples/RNOneSignal/index.ios.js b/examples/RNOneSignal/index.ios.js
index edd7c9b8..ebdfbbe1 100644
--- a/examples/RNOneSignal/index.ios.js
+++ b/examples/RNOneSignal/index.ios.js
@@ -9,25 +9,75 @@ import {
AppRegistry,
StyleSheet,
Text,
- View
+ View,
+ Button,
+ Image,
+ TextInput,
+ Dimensions,
+ KeyboardAvoidingView,
+ ActivityIndicator,
+ Platform,
+ ScrollView,
+ Linking
} from 'react-native';
import OneSignal from 'react-native-onesignal';
+let imageUri = 'https://media.licdn.com/media/AAEAAQAAAAAAAAyOAAAAJDJhY2JlMmJjLWI1NzctNGNmNC1iMDU1LWE4NjI4Nzc1YTU2Zg.png'
+
export default class RNOneSignal extends Component {
-
+ constructor(properties) {
+ super(properties);
+ }
+
+ 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());
+ }
+
componentWillMount() {
+ console.log("setting log level");
+ OneSignal.setLogLevel(7, 0);
+ this.setState({emailEnabled: false,
+ animatingEmailButton : false,
+ initialOpenFromPush : "Did NOT open from push",
+ activityWidth : 0,
+ width: 0,
+ activityMargin: 0,
+ buttonColor : Platform.OS == "ios" ? "#ffffff" : "#d45653",
+ jsonDebugText : ""
+ });
+ OneSignal.setLocationShared(true);
+
+
+ OneSignal.inFocusDisplaying(2)
+
+ OneSignal.getPermissionSubscriptionState((response) => {
+ console.log("Received permission subscription state: ", response);
+ });
+ }
+
+ componentDidMount() {
+ this.onReceived = this.onReceived.bind(this);
+ this.onOpened = this.onOpened.bind(this);
+ this.onIds = this.onIds.bind(this);
+ this.onEmailRegistrationChange = this.onEmailRegistrationChange.bind(this);
+
OneSignal.addEventListener('received', this.onReceived);
OneSignal.addEventListener('opened', this.onOpened);
- OneSignal.addEventListener('registered', this.onRegistered);
OneSignal.addEventListener('ids', this.onIds);
+ OneSignal.addEventListener('emailSubscription', this.onEmailRegistrationChange);
}
componentWillUnmount() {
OneSignal.removeEventListener('received', this.onReceived);
OneSignal.removeEventListener('opened', this.onOpened);
- OneSignal.removeEventListener('registered', this.onRegistered);
OneSignal.removeEventListener('ids', this.onIds);
+ OneSignal.removeEventListener('emailSubscription', this.onEmailRegistrationChange);
+ }
+
+ onEmailRegistrationChange(registration) {
+ console.log("onEmailRegistrationChange: ", registration);
}
onReceived(notification) {
@@ -41,36 +91,136 @@ export default class RNOneSignal extends Component {
console.log('openResult: ', openResult);
}
- onRegistered(notifData) {
- console.log("Device had been registered for push notifications!", notifData);
- }
-
onIds(device) {
console.log('Device info: ', device);
}
render() {
return (
-
-
- Welcome to React Native!
-
-
- To get started, edit index.android.js
-
-
- Double tap R on your keyboard to reload,{'\n'}
- Shake or press menu button for dev menu
-
-
+
+
+
+
+
+
+ Welcome to React Native!
+
+
+ To get started, edit index.ios.js
+
+
+ Double tap R on your keyboard to reload,{'\n'}
+ Shake or press menu button for dev menu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ console.log("New text: ", newText, ", is valid email? ", this.validateEmail(newText));
+ this.setState({emailEnabled : this.validateEmail(newText), email : newText});
+ }}
+ />
+
+
+
+
+ {this.state.jsonDebugText}
+
+
+
);
}
}
const styles = StyleSheet.create({
+ scrollView: {
+ backgroundColor: '#F5FCFF'
+ },
container: {
flex: 1,
- justifyContent: 'center',
+ flexDirection: 'column',
+ justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
@@ -83,7 +233,35 @@ const styles = StyleSheet.create({
textAlign: 'center',
color: '#333333',
marginBottom: 5,
+ marginHorizontal: 10
+ },
+ jsonDebugLabelText: {
+ textAlign: 'left',
+ color: '#333333',
+ marginBottom: 5,
+ marginHorizontal: 10
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ overflow: 'hidden',
+ borderRadius: 10,
+ marginVertical: 10,
+ marginHorizontal: 10,
+ backgroundColor: "#d45653"
},
+ button: {
+ color: '#000000',
+ flex: 1
+ },
+ imageStyle: {
+ height: 200,
+ width: 200,
+ marginTop: 20
+ },
+ textInput: {
+ marginHorizontal: 10,
+ height: 40
+ }
});
AppRegistry.registerComponent('RNOneSignal', () => RNOneSignal);
diff --git a/index.js b/index.js
index 81403762..176b5e35 100644
--- a/index.js
+++ b/index.js
@@ -1,39 +1,35 @@
'use strict';
-import { NativeModules, NativeAppEventEmitter, NetInfo, Platform } from 'react-native';
+import { NativeModules, NativeEventEmitter, NetInfo, Platform } from 'react-native';
import invariant from 'invariant';
-var _eventBroadcastNames = [
+const RNOneSignal = NativeModules.OneSignal;
+
+var oneSignalEventEmitter = new NativeEventEmitter(RNOneSignal);
+
+const eventBroadcastNames = [
'OneSignal-remoteNotificationReceived',
'OneSignal-remoteNotificationOpened',
- 'OneSignal-remoteNotificationsRegistered',
- 'OneSignal-idsAvailable'
+ 'OneSignal-idsAvailable',
+ 'OneSignal-emailSubscription'
];
-var _eventNames = [ "received", "opened", "registered", "ids" ];
+var _eventNames = [ "received", "opened", "ids", "emailSubscription"];
var _notificationHandler = new Map();
var _notificationCache = new Map();
var _listeners = [];
-for(var i = 0; i < _eventBroadcastNames.length; i++) {
- var eventBroadcastName = _eventBroadcastNames[i];
+for(var i = 0; i < eventBroadcastNames.length; i++) {
+ var eventBroadcastName = eventBroadcastNames[i];
var eventName = _eventNames[i];
_listeners[eventName] = handleEventBroadcast(eventName, eventBroadcastName)
}
-var RNOneSignal = NativeModules.OneSignal;
-
-
-var DEVICE_NOTIF_RECEIVED_EVENT = 'OneSignal-remoteNotificationReceived';
-var DEVICE_NOTIF_OPENED_EVENT = 'OneSignal-remoteNotificationOpened';
-var DEVICE_NOTIF_REG_EVENT = 'OneSignal-remoteNotificationsRegistered';
-var DEVICE_IDS_AVAILABLE = 'OneSignal-idsAvailable';
-
function handleEventBroadcast(type, broadcast) {
- return NativeAppEventEmitter.addListener(
+ return oneSignalEventEmitter.addListener(
broadcast, (notification) => {
// Check if we have added listener for this type yet
// Cache the result first if we have not.
@@ -46,6 +42,8 @@ function handleEventBroadcast(type, broadcast) {
}
}
);
+
+ console.log("NATIVE MODULES: ", NativeModules);
}
function handleConnectionStateChange(isConnected) {
@@ -68,7 +66,7 @@ export default class OneSignal {
// Listen to events of notification received, opened, device registered and IDSAvailable.
invariant(
- type === 'received' || type === 'opened' || type === 'registered' || type === 'ids',
+ type === 'received' || type === 'opened' || type === 'registered' || type === 'ids' || type == 'emailSubscription',
'OneSignal only supports `received`, `opened`, `registered`, and `ids` events'
);
@@ -84,7 +82,7 @@ export default class OneSignal {
static removeEventListener(type: any, handler: Function) {
invariant(
- type === 'received' || type === 'opened' || type === 'registered' || type === 'ids',
+ type === 'received' || type === 'opened' || type === 'registered' || type === 'ids' || type == 'emailSubscription',
'OneSignal only supports `received`, `opened`, `registered`, and `ids` events'
);
@@ -194,6 +192,31 @@ export default class OneSignal {
console.log("This function is not supported on iOS");
}
}
+
+ static setEmail(email, emailAuthCode, callback) {
+
+ if (callback == undefined && typeof emailAuthCode == 'function') {
+ //emailAuthCode is an optional parameter
+ //since JS does not support function overloading,
+ //unauthenticated setEmail calls will have emailAuthCode as the callback
+
+ var callback = emailAuthCode;
+
+ RNOneSignal.setUnauthenticatedEmail(email, callback);
+ } else {
+
+ RNOneSignal.setEmail(email, emailAuthCode, callback);
+ }
+ }
+
+ static logoutEmail(callback) {
+ invariant(
+ typeof callback === 'function',
+ 'Must provide a valid callback'
+ );
+
+ RNOneSignal.logoutEmail(callback);
+ }
static setLocationShared(shared) {
RNOneSignal.setLocationShared(shared);
diff --git a/ios/OneSignal.h b/ios/OneSignal.h
index 971a3e4c..b9bf7c80 100755
--- a/ios/OneSignal.h
+++ b/ios/OneSignal.h
@@ -50,6 +50,11 @@
#import
#endif
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstrict-prototypes"
+#pragma clang diagnostic ignored "-Wnullability-completeness"
+
/* The action type associated to an OSNotificationAction object */
typedef NS_ENUM(NSUInteger, OSNotificationActionType) {
OSNotificationActionTypeOpened,
@@ -236,19 +241,34 @@ typedef NS_ENUM(NSInteger, OSNotificationPermission) {
@end
-@interface OSSubscriptionStateChanges : NSObject
+@interface OSEmailSubscriptionState : NSObject
+@property (readonly, nonatomic) NSString* emailUserId; // The new Email user ID
+@property (readonly, nonatomic) NSString *emailAddress;
+@property (readonly, nonatomic) BOOL subscribed;
+- (NSDictionary*)toDictionary;
+@end
+
+@interface OSSubscriptionStateChanges : NSObject
@property (readonly) OSSubscriptionState* to;
@property (readonly) OSSubscriptionState* from;
-
- (NSDictionary*)toDictionary;
+@end
+@interface OSEmailSubscriptionStateChanges : NSObject
+@property (readonly) OSEmailSubscriptionState* to;
+@property (readonly) OSEmailSubscriptionState* from;
+- (NSDictionary*)toDictionary;
@end
@protocol OSSubscriptionObserver
- (void)onOSSubscriptionChanged:(OSSubscriptionStateChanges*)stateChanges;
@end
+@protocol OSEmailSubscriptionObserver
+- (void)onOSEmailSubscriptionChanged:(OSEmailSubscriptionStateChanges*)stateChanges;
+@end
+
// Permission+Subscription Classes
@@ -256,6 +276,7 @@ typedef NS_ENUM(NSInteger, OSNotificationPermission) {
@property (readonly) OSPermissionState* permissionStatus;
@property (readonly) OSSubscriptionState* subscriptionStatus;
+@property (readonly) OSEmailSubscriptionState *emailSubscriptionStatus;
- (NSDictionary*)toDictionary;
@end
@@ -356,6 +377,9 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) {
+ (void)addSubscriptionObserver:(NSObject*)observer;
+ (void)removeSubscriptionObserver:(NSObject*)observer;
++ (void)addEmailSubscriptionObserver:(NSObject*)observer;
++ (void)removeEmailSubscriptionObserver:(NSObject*)observer;
+
+ (void)setSubscription:(BOOL)enable;
// - Posting Notification
@@ -379,4 +403,29 @@ typedef NS_ENUM(NSUInteger, ONE_S_LOG_LEVEL) {
+ (UNMutableNotificationContent*)didReceiveNotificationExtensionRequest:(UNNotificationRequest*)request withMutableNotificationContent:(UNMutableNotificationContent*)replacementContent;
+ (UNMutableNotificationContent*)serviceExtensionTimeWillExpireRequest:(UNNotificationRequest*)request withMutableNotificationContent:(UNMutableNotificationContent*)replacementContent;
+// Email methods
+
+// Typedefs defining completion blocks for email & simultaneous HTTP requests
+typedef void (^OSEmailFailureBlock)(NSError* error);
+typedef void (^OSEmailSuccessBlock)();
+
+// Allows you to set the email for this user.
+// Email Auth Token is a (recommended) optional parameter that should *NOT* be generated on the client.
+// For security purposes, the emailAuthToken should be generated by your backend server.
+// If you do not have a backend server for your application, use the version of thge setEmail: method without an emailAuthToken parameter.
++ (void)setEmail:(NSString * _Nonnull)email withEmailAuthHashToken:(NSString * _Nullable)hashToken withSuccess:(OSEmailSuccessBlock _Nullable)successBlock withFailure:(OSEmailFailureBlock _Nullable)failureBlock;
+
+// Sets email without an authentication token
++ (void)setEmail:(NSString * _Nonnull)email withSuccess:(OSEmailSuccessBlock _Nullable)successBlock withFailure:(OSEmailFailureBlock _Nullable)failureBlock;
+
+// Logs the device out of the current email.
++ (void)logoutEmailWithSuccess:(OSEmailSuccessBlock _Nullable)successBlock withFailure:(OSEmailFailureBlock _Nullable)failureBlock;
+
+//convenience - no completion blocks
++ (void)logoutEmail;
++ (void)setEmail:(NSString * _Nonnull)email;
++ (void)setEmail:(NSString * _Nonnull)email withEmailAuthHashToken:(NSString * _Nullable)hashToken;
+
@end
+
+#pragma clang diagnostic pop
diff --git a/ios/RCTOneSignal.xcodeproj/project.pbxproj b/ios/RCTOneSignal.xcodeproj/project.pbxproj
index ce8643f3..d80b223f 100644
--- a/ios/RCTOneSignal.xcodeproj/project.pbxproj
+++ b/ios/RCTOneSignal.xcodeproj/project.pbxproj
@@ -8,7 +8,8 @@
/* Begin PBXBuildFile section */
CA1CC868200FE3C3005B66AA /* RCTOneSignalExtensionService.m in Sources */ = {isa = PBXBuildFile; fileRef = CA1CC867200FE3C3005B66AA /* RCTOneSignalExtensionService.m */; };
- CA1CCB572016BFC1005B66AA /* libOneSignal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CA1CCB562016BFC1005B66AA /* libOneSignal.a */; };
+ CACB39D6202D232A00D86CD1 /* RCTOneSignalEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = CACB39D5202D232A00D86CD1 /* RCTOneSignalEventEmitter.m */; };
+ CAE5CDE62033935A006992EC /* libOneSignal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAE5CDE52033935A006992EC /* libOneSignal.a */; };
FD2CCC851C772B4200B2B24E /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD2CCC841C772B4200B2B24E /* SystemConfiguration.framework */; };
FDB40CC41C5E4E5500CBF09B /* RCTOneSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = FDB40CC31C5E4E5500CBF09B /* RCTOneSignal.m */; };
/* End PBXBuildFile section */
@@ -29,8 +30,10 @@
3245CDED1BFEE35C00EABF68 /* libRCTOneSignal.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTOneSignal.a; sourceTree = BUILT_PRODUCTS_DIR; };
CA1CC866200FE3C3005B66AA /* RCTOneSignalExtensionService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTOneSignalExtensionService.h; sourceTree = ""; };
CA1CC867200FE3C3005B66AA /* RCTOneSignalExtensionService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTOneSignalExtensionService.m; sourceTree = ""; };
- CA1CCB552016BE92005B66AA /* OneSignal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignal.h; sourceTree = ""; };
- CA1CCB562016BFC1005B66AA /* libOneSignal.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOneSignal.a; sourceTree = ""; };
+ CACB39D4202D232A00D86CD1 /* RCTOneSignalEventEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTOneSignalEventEmitter.h; sourceTree = ""; };
+ CACB39D5202D232A00D86CD1 /* RCTOneSignalEventEmitter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTOneSignalEventEmitter.m; sourceTree = ""; };
+ CAE5CDE52033935A006992EC /* libOneSignal.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOneSignal.a; sourceTree = ""; };
+ CAE5CDE720339365006992EC /* OneSignal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignal.h; sourceTree = ""; };
FD2CCC841C772B4200B2B24E /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; };
FDB40CC21C5E4E5500CBF09B /* RCTOneSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTOneSignal.h; sourceTree = ""; };
FDB40CC31C5E4E5500CBF09B /* RCTOneSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTOneSignal.m; sourceTree = ""; };
@@ -41,7 +44,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- CA1CCB572016BFC1005B66AA /* libOneSignal.a in Frameworks */,
+ CAE5CDE62033935A006992EC /* libOneSignal.a in Frameworks */,
FD2CCC851C772B4200B2B24E /* SystemConfiguration.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -72,6 +75,8 @@
children = (
FDB40CC21C5E4E5500CBF09B /* RCTOneSignal.h */,
FDB40CC31C5E4E5500CBF09B /* RCTOneSignal.m */,
+ CACB39D4202D232A00D86CD1 /* RCTOneSignalEventEmitter.h */,
+ CACB39D5202D232A00D86CD1 /* RCTOneSignalEventEmitter.m */,
CA1CC866200FE3C3005B66AA /* RCTOneSignalExtensionService.h */,
CA1CC867200FE3C3005B66AA /* RCTOneSignalExtensionService.m */,
);
@@ -81,8 +86,8 @@
CA1CC858200FDEFC005B66AA /* Frameworks */ = {
isa = PBXGroup;
children = (
- CA1CCB552016BE92005B66AA /* OneSignal.h */,
- CA1CCB562016BFC1005B66AA /* libOneSignal.a */,
+ CAE5CDE720339365006992EC /* OneSignal.h */,
+ CAE5CDE52033935A006992EC /* libOneSignal.a */,
);
name = Frameworks;
sourceTree = "";
@@ -143,6 +148,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ CACB39D6202D232A00D86CD1 /* RCTOneSignalEventEmitter.m in Sources */,
CA1CC868200FE3C3005B66AA /* RCTOneSignalExtensionService.m in Sources */,
FDB40CC41C5E4E5500CBF09B /* RCTOneSignal.m in Sources */,
);
@@ -251,6 +257,7 @@
"$(inherited)",
"$(PROJECT_DIR)/**",
"$(PROJECT_DIR)/RCTOneSignal",
+ "$(PROJECT_DIR)",
);
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = "-ObjC";
@@ -277,6 +284,7 @@
"$(inherited)",
"$(PROJECT_DIR)/**",
"$(PROJECT_DIR)/RCTOneSignal",
+ "$(PROJECT_DIR)",
);
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
diff --git a/ios/RCTOneSignal/RCTOneSignal.h b/ios/RCTOneSignal/RCTOneSignal.h
index 48b704ad..f06690da 100644
--- a/ios/RCTOneSignal/RCTOneSignal.h
+++ b/ios/RCTOneSignal/RCTOneSignal.h
@@ -1,8 +1,3 @@
-#if __has_include()
-#import
-#elif __has_include("RCTBridgeModule.h")
-#import "RCTBridgeModule.h"
-#endif
#if __has_include()
#import
@@ -10,9 +5,9 @@
#import "OneSignal.h"
#endif
-@interface RCTOneSignal : NSObject
+@interface RCTOneSignal : NSObject
- (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appId;
- (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appId settings:(NSDictionary*)settings;
-+ (void)didReceiveRemoteNotification:(NSDictionary *)dictionary;
+
@end
diff --git a/ios/RCTOneSignal/RCTOneSignal.m b/ios/RCTOneSignal/RCTOneSignal.m
index 305c186b..a17d264b 100644
--- a/ios/RCTOneSignal/RCTOneSignal.m
+++ b/ios/RCTOneSignal/RCTOneSignal.m
@@ -11,6 +11,7 @@
#endif
#import "RCTOneSignal.h"
+#import "RCTOneSignalEventEmitter.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
@@ -25,28 +26,21 @@
@interface RCTOneSignal ()
@end
-@implementation RCTOneSignal
-
-@synthesize bridge = _bridge;
-
-RCT_EXPORT_MODULE(RCTOneSignal)
-
-static RCTBridge *curRCTBridge;
+@implementation RCTOneSignal {
+ BOOL didStartObserving;
+}
OSNotificationOpenedResult* coldStartOSNotificationOpenedResult;
-+ (void)didReceiveRemoteNotification:(NSDictionary *)dictionary {
-
-}
-
-- (void)setBridge:(RCTBridge *)receivedBridge {
- _bridge = receivedBridge;
- curRCTBridge = receivedBridge;
+- (void)didStartObserving {
+ didStartObserving = true;
- if (coldStartOSNotificationOpenedResult) {
- [self handleRemoteNotificationOpened:[coldStartOSNotificationOpenedResult stringify]];
- coldStartOSNotificationOpenedResult = nil;
- }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (coldStartOSNotificationOpenedResult) {
+ [self handleRemoteNotificationOpened:[coldStartOSNotificationOpenedResult stringify]];
+ coldStartOSNotificationOpenedResult = nil;
+ }
+ });
}
- (void)dealloc {
@@ -58,7 +52,9 @@ - (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appI
}
- (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appId settings:(NSDictionary*)settings {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didStartObserving) name:@"didSetBridge" object:nil];
[OneSignal addSubscriptionObserver:self];
+ [OneSignal addEmailSubscriptionObserver:self];
[OneSignal setValue:@"react" forKey:@"mSDKType"];
[OneSignal initWithLaunchOptions:launchOptions
appId:appId
@@ -66,241 +62,60 @@ - (id)initWithLaunchOptions:(NSDictionary *)launchOptions appId:(NSString *)appI
[self handleRemoteNotificationReceived:[notification stringify]];
}
handleNotificationAction:^(OSNotificationOpenedResult *result) {
- if (!curRCTBridge)
+ if (!didStartObserving)
coldStartOSNotificationOpenedResult = result;
else
[self handleRemoteNotificationOpened:[result stringify]];
+
}
settings:settings];
return self;
}
+-(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) {
- NSLog(@"Subscribed for OneSignal push notifications!");
+ //Subscribed for OneSignal push notifications!
}
- // prints out all properties
- NSLog(@"SubscriptionStateChanges:\n%@", stateChanges.to);
- [self.bridge.eventDispatcher sendAppEventWithName:@"OneSignal-idsAvailable" body:stateChanges.to];
+ [self sendEvent:OSEventString(IdsAvailable) withBody:stateChanges.to.toDictionary];
}
- (void)handleRemoteNotificationReceived:(NSString *)notification {
+ NSDictionary *json = [self jsonObjectWithString:notification];
- NSError *jsonError;
- NSData *objectData = [notification dataUsingEncoding:NSUTF8StringEncoding];
- NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
- options:NSJSONReadingMutableContainers
- error:&jsonError];
-
-
-
- [curRCTBridge.eventDispatcher sendAppEventWithName:@"OneSignal-remoteNotificationReceived" body:json];
+ if (json)
+ [self sendEvent:OSEventString(NotificationReceived) withBody:json];
}
- (void)handleRemoteNotificationOpened:(NSString *)result {
+ NSDictionary *json = [self jsonObjectWithString:result];
- NSError *jsonError;
- NSData *objectData = [result dataUsingEncoding:NSUTF8StringEncoding];
- NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
- options:NSJSONReadingMutableContainers
- error:&jsonError];
-
- [curRCTBridge.eventDispatcher sendAppEventWithName:@"OneSignal-remoteNotificationOpened" body:json];
-}
-
-- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification {
- [self.bridge.eventDispatcher sendAppEventWithName:@"OneSignal-remoteNotificationsRegistered" body:notification.userInfo];
+ if (json)
+ [self sendEvent:OSEventString(NotificationOpened) withBody:json];
}
-RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
-{
- if (RCTRunningInAppExtension()) {
- callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]);
- return;
- }
-
- NSUInteger types = 0;
- if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) {
- types = [RCTSharedApplication() currentUserNotificationSettings].types;
- } else {
-
-#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
- types = [RCTSharedApplication() enabledRemoteNotificationTypes];
-#endif
-
- }
+- (NSDictionary *)jsonObjectWithString:(NSString *)jsonString {
+ NSError *jsonError;
+ NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
+ NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
- callback(@[@{
- @"alert": @((types & UIUserNotificationTypeAlert) > 0),
- @"badge": @((types & UIUserNotificationTypeBadge) > 0),
- @"sound": @((types & UIUserNotificationTypeSound) > 0),
- }]);
-}
-
-RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions) {
- if (RCTRunningInAppExtension()) {
- return;
- }
-
- UIUserNotificationType types = UIUserNotificationTypeNone;
- if (permissions) {
- if ([RCTConvert BOOL:permissions[@"alert"]]) {
- types |= UIUserNotificationTypeAlert;
- }
- if ([RCTConvert BOOL:permissions[@"badge"]]) {
- types |= UIUserNotificationTypeBadge;
- }
- if ([RCTConvert BOOL:permissions[@"sound"]]) {
- types |= UIUserNotificationTypeSound;
- }
- } else {
- types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
- }
-
- UIApplication *app = RCTSharedApplication();
- if ([app respondsToSelector:@selector(registerUserNotificationSettings:)]) {
- UIUserNotificationSettings *notificationSettings =
- [UIUserNotificationSettings settingsForTypes:(NSUInteger)types categories:nil];
- [app registerUserNotificationSettings:notificationSettings];
- [app registerForRemoteNotifications];
- } else {
- [app registerForRemoteNotificationTypes:(NSUInteger)types];
- }
-}
-
-RCT_EXPORT_METHOD(getPermissionSubscriptionState:(RCTResponseSenderBlock)callback)
-{
- if (RCTRunningInAppExtension()) {
- callback(@[@{
- @"hasPrompted": @NO,
- @"notificationsEnabled": @NO,
- @"subscriptionEnabled": @NO,
- @"userSubscriptionEnabled": @NO,
- @"pushToken": [NSNull null],
- @"userId": [NSNull null],
- }]);
+ if (jsonError) {
+ [OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"Unable to serialize JSON string into an object: %@", jsonError]];
+ return nil;
}
- OSPermissionSubscriptionState *state = [OneSignal getPermissionSubscriptionState];
- OSPermissionState *permissionState = state.permissionStatus;
- OSSubscriptionState *subscriptionState = state.subscriptionStatus;
-
- // 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 != NULL ? subscriptionState.pushToken : [NSNull null],
- @"userId": subscriptionState.userId != NULL ? subscriptionState.userId : [NSNull null],
- }]);
-}
-
-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) {
- NSLog(@"Prompt For Push Notifications Success");
- callback(@[@(accepted)]);
- }];
-}
-
-RCT_EXPORT_METHOD(sendTag:(NSString *)key value:(NSString*)value) {
- [OneSignal sendTag:key value:value];
-}
-
-RCT_EXPORT_METHOD(configure) {
- [OneSignal IdsAvailable:^(NSString* userId, NSString* pushToken) {
-
- NSDictionary *params = @{
- @"pushToken": pushToken ?: [NSNull null],
- @"userId" : userId ?: [NSNull null]
- };
-
- [self.bridge.eventDispatcher sendAppEventWithName:@"OneSignal-idsAvailable" body:params];
- }];
-}
-
-RCT_EXPORT_METHOD(sendTags:(NSDictionary *)properties) {
- [OneSignal sendTags:properties onSuccess:^(NSDictionary *sucess) {
- NSLog(@"Send Tags Success");
- } onFailure:^(NSError *error) {
- NSLog(@"Send Tags Failure");
- }];}
-
-RCT_EXPORT_METHOD(getTags:(RCTResponseSenderBlock)callback) {
- [OneSignal getTags:^(NSDictionary *tags) {
- NSLog(@"Get Tags Success");
- callback(@[tags]);
- } onFailure:^(NSError *error) {
- NSLog(@"Get Tags Failure");
- callback(@[error]);
- }];
-}
-
-RCT_EXPORT_METHOD(setLocationShared:(BOOL)shared) {
- [OneSignal setLocationShared:shared];
-}
-
-RCT_EXPORT_METHOD(deleteTag:(NSString *)key) {
- [OneSignal deleteTag:key];
-}
-
-RCT_EXPORT_METHOD(setSubscription:(BOOL)enable) {
- [OneSignal setSubscription:enable];
-}
-
-RCT_EXPORT_METHOD(promptLocation) {
- [OneSignal promptLocation];
-}
-
-RCT_EXPORT_METHOD(postNotification:(NSDictionary *)contents data:(NSDictionary *)data player_id:(NSString*)player_id other_parameters:(NSDictionary *)other_parameters) {
- NSDictionary * additionalData = @{@"p2p_notification": data};
-
- NSMutableDictionary * extendedData = [additionalData mutableCopy];
- BOOL isHidden = [[other_parameters objectForKey:@"hidden"] boolValue];
- if (isHidden) {
- [extendedData setObject:[NSNumber numberWithBool:YES] forKey:@"hidden"];
- }
-
- NSDictionary *notification = @{
- @"contents" : contents,
- @"data" : extendedData,
- @"include_player_ids": @[player_id]
- };
- NSMutableDictionary * extendedNotification = [notification mutableCopy];
- [extendedNotification addEntriesFromDictionary: other_parameters];
-
- [OneSignal postNotification:extendedNotification];
-}
-
-RCT_EXPORT_METHOD(syncHashedEmail:(NSString*)email) {
- [OneSignal syncHashedEmail:email];
+ return json;
}
-RCT_EXPORT_METHOD(setLogLevel:(int)logLevel visualLogLevel:(int)visualLogLevel) {
- [OneSignal setLogLevel:logLevel visualLevel:visualLogLevel];
+- (void)sendEvent:(NSString *)eventName withBody:(NSDictionary *)body {
+ [RCTOneSignalEventEmitter sendEventWithName:eventName withBody:body];
}
@end
diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.h b/ios/RCTOneSignal/RCTOneSignalEventEmitter.h
new file mode 100644
index 00000000..98d686aa
--- /dev/null
+++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.h
@@ -0,0 +1,31 @@
+#if __has_include()
+#import
+#import
+#import
+#import
+#import
+#elif __has_include("RCTBridgeModule.h")
+#import "RCTBridgeModule.h"
+#import "RCTEventEmitter.h"
+#import "RCTConvert.h"
+#import "RCTEventDispatcher.h"
+#import "RCTUtils.h"
+#endif
+
+typedef NS_ENUM(NSInteger, OSNotificationEventTypes) {
+ NotificationReceived,
+ NotificationOpened,
+ IdsAvailable,
+ EmailSubscriptionChanged
+};
+
+#define OSNotificationEventTypesArray @[@"OneSignal-remoteNotificationReceived",@"OneSignal-remoteNotificationOpened",@"OneSignal-idsAvailable",@"OneSignal-emailSubscription"]
+#define OSEventString(enum) [OSNotificationEventTypesArray objectAtIndex:enum]
+
+
+@interface RCTOneSignalEventEmitter : RCTEventEmitter
+
++ (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body;
++ (BOOL)hasSetBridge;
+
+@end
diff --git a/ios/RCTOneSignal/RCTOneSignalEventEmitter.m b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m
new file mode 100644
index 00000000..65e50729
--- /dev/null
+++ b/ios/RCTOneSignal/RCTOneSignalEventEmitter.m
@@ -0,0 +1,307 @@
+//
+// RCTOneSignalEventEmitter.m
+// RCTOneSignal
+//
+// Created by Brad Hesse on 2/8/18.
+//
+
+#import "RCTOneSignalEventEmitter.h"
+#import "OneSignal.h"
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+
+@implementation RCTOneSignalEventEmitter {
+ BOOL hasListeners;
+}
+
+static BOOL _didStartObserving = false;
+
++ (BOOL)hasSetBridge {
+ return _didStartObserving;
+}
+
+/*
+ This class acts as the module & event emitter
+ It is initialized automatically by React-Native
+ This subclass handles communication between the SDK and JavaScript
+*/
+
+RCT_EXPORT_MODULE(RCTOneSignal)
+
+#pragma mark RCTEventEmitter Subclass Methods
+
+-(instancetype)init {
+ if (self = [super init]) {
+ [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"Initialized RCTOneSignalEventEmitter"];
+
+ for (NSString *eventName in [self supportedEvents])
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitEvent:) name:eventName object:nil];
+ }
+
+ return self;
+}
+
+-(void)startObserving {
+ hasListeners = true;
+ [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did start observing"];
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:@"didSetBridge" object:nil];
+
+ _didStartObserving = true;
+}
+
+-(void)stopObserving {
+ hasListeners = false;
+ [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"RCTOneSignalEventEmitter did stop observing"];
+}
+
+-(NSArray *)supportedEvents {
+ NSMutableArray *events = [NSMutableArray new];
+
+ for (int i = 0; i < OSNotificationEventTypesArray.count; i++)
+ [events addObject:OSEventString(i)];
+
+ return events;
+}
+
+
+#pragma mark Send Event Methods
+
+- (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]];
+ return;
+ }
+
+ [self sendEventWithName:notification.name body:notification.userInfo];
+}
+
++ (void)sendEventWithName:(NSString *)name withBody:(NSDictionary *)body {
+ [[NSNotificationCenter defaultCenter] postNotificationName:name object:nil userInfo:body];
+}
+
+
+#pragma mark Exported Methods
+
+RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
+{
+ if (RCTRunningInAppExtension()) {
+ callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]);
+ return;
+ }
+
+ NSUInteger types = 0;
+ 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;
+ }
+
+ UIUserNotificationType types = UIUserNotificationTypeNone;
+ if (permissions) {
+ if ([RCTConvert BOOL:permissions[@"alert"]]) {
+ types |= UIUserNotificationTypeAlert;
+ }
+ if ([RCTConvert BOOL:permissions[@"badge"]]) {
+ types |= UIUserNotificationTypeBadge;
+ }
+ if ([RCTConvert BOOL:permissions[@"sound"]]) {
+ types |= UIUserNotificationTypeSound;
+ }
+ } else {
+ types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
+ }
+
+ UIApplication *app = RCTSharedApplication();
+ if ([app respondsToSelector:@selector(registerUserNotificationSettings:)]) {
+ UIUserNotificationSettings *notificationSettings =
+ [UIUserNotificationSettings settingsForTypes:(NSUInteger)types categories:nil];
+ [app registerUserNotificationSettings:notificationSettings];
+ [app registerForRemoteNotifications];
+ } else {
+ [app registerForRemoteNotificationTypes:(NSUInteger)types];
+ }
+}
+
+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:^{
+ callback(@[]);
+ } withFailure:^(NSError *error) {
+ callback(@[error]);
+ }];
+}
+
+RCT_EXPORT_METHOD(setUnauthenticatedEmail:(NSString *)email withResponse:(RCTResponseSenderBlock)callback) {
+ // Does not use an email auth has token, uses unauthenticated state
+ [OneSignal setEmail:email withSuccess:^{
+ callback(@[]);
+ } withFailure:^(NSError *error) {
+ callback(@[error]);
+ }];
+}
+
+RCT_EXPORT_METHOD(logoutEmail:(RCTResponseSenderBlock)callback) {
+ [OneSignal logoutEmailWithSuccess:^{
+ callback(@[]);
+ } withFailure:^(NSError *error) {
+ callback(@[error]);
+ }];
+}
+
+RCT_EXPORT_METHOD(getPermissionSubscriptionState:(RCTResponseSenderBlock)callback)
+{
+ if (RCTRunningInAppExtension()) {
+ callback(@[@{
+ @"hasPrompted": @NO,
+ @"notificationsEnabled": @NO,
+ @"subscriptionEnabled": @NO,
+ @"userSubscriptionEnabled": @NO,
+ @"pushToken": [NSNull null],
+ @"userId": [NSNull null],
+ }]);
+ }
+
+ 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],
+ @"emailSubscribed" : @(emailState.subscribed),
+ @"emailAddress" : emailState.emailAddress ?: [NSNull null]
+ }]);
+}
+
+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"];
+ callback(@[@(accepted)]);
+ }];
+}
+
+RCT_EXPORT_METHOD(sendTag:(NSString *)key value:(NSString*)value) {
+ [OneSignal sendTag:key value:value];
+}
+
+RCT_EXPORT_METHOD(configure) {
+ [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"];
+ } onFailure:^(NSError *error) {
+ [OneSignal onesignal_Log: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"];
+ callback(@[tags]);
+ } onFailure:^(NSError *error) {
+ [OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"Get Tags Failure with error: %@", error]];
+ callback(@[error]);
+ }];
+}
+
+RCT_EXPORT_METHOD(setLocationShared:(BOOL)shared) {
+ [OneSignal setLocationShared:shared];
+}
+
+RCT_EXPORT_METHOD(deleteTag:(NSString *)key) {
+ [OneSignal deleteTag:key];
+}
+
+RCT_EXPORT_METHOD(setSubscription:(BOOL)enable) {
+ [OneSignal setSubscription:enable];
+}
+
+RCT_EXPORT_METHOD(promptLocation) {
+ [OneSignal promptLocation];
+}
+
+RCT_EXPORT_METHOD(postNotification:(NSDictionary *)contents data:(NSDictionary *)data player_id:(NSString*)player_id other_parameters:(NSDictionary *)other_parameters) {
+ NSDictionary * additionalData = @{@"p2p_notification": data};
+
+ NSMutableDictionary * extendedData = [additionalData mutableCopy];
+ BOOL isHidden = [[other_parameters objectForKey:@"hidden"] boolValue];
+ if (isHidden) {
+ [extendedData setObject:[NSNumber numberWithBool:YES] forKey:@"hidden"];
+ }
+
+ NSDictionary *notification = @{
+ @"contents" : contents,
+ @"data" : extendedData,
+ @"include_player_ids": @[player_id]
+ };
+ NSMutableDictionary * extendedNotification = [notification mutableCopy];
+ [extendedNotification addEntriesFromDictionary: other_parameters];
+
+ [OneSignal postNotification:extendedNotification];
+}
+
+RCT_EXPORT_METHOD(syncHashedEmail:(NSString*)email) {
+ [OneSignal syncHashedEmail:email];
+}
+
+RCT_EXPORT_METHOD(setLogLevel:(int)logLevel visualLogLevel:(int)visualLogLevel) {
+ [OneSignal setLogLevel:logLevel visualLevel:visualLogLevel];
+}
+
+
+@end
diff --git a/ios/RCTOneSignal/RCTOneSignalExtensionService.h b/ios/RCTOneSignal/RCTOneSignalExtensionService.h
index 98a38f4d..a94b9c43 100644
--- a/ios/RCTOneSignal/RCTOneSignalExtensionService.h
+++ b/ios/RCTOneSignal/RCTOneSignalExtensionService.h
@@ -9,6 +9,6 @@
#import
@interface RCTOneSignalExtensionService : NSObject
-+ (void)serviceExtensionTimeWillExpireRequest:(UNNotificationRequest *)request withMutableNotificationContent:(UNMutableNotificationContent * _Nullable)content;
-+ (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContent:(UNMutableNotificationContent * _Nullable)content;
++ (void)serviceExtensionTimeWillExpireRequest:(UNNotificationRequest * _Nonnull)request withMutableNotificationContent:(UNMutableNotificationContent * _Nullable)content;
++ (void)didReceiveNotificationRequest:(UNNotificationRequest * _Nonnull)request withContent:(UNMutableNotificationContent * _Nullable)content;
@end
diff --git a/ios/libOneSignal.a b/ios/libOneSignal.a
index 77ac2403..52f74f3d 100644
Binary files a/ios/libOneSignal.a and b/ios/libOneSignal.a differ