diff --git a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeConstants.java b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeConstants.java
index 799b98a8..73322c15 100644
--- a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeConstants.java
+++ b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeConstants.java
@@ -22,6 +22,9 @@ public final class ReactNativeConstants {
public static final String KEY_REGISTRATION_CHANNELSHOWBADGE = "channelShowBadge";
public static final String KEY_REGISTRATION_CHANNELENABLELIGHTS = "channelEnableLights";
public static final String KEY_REGISTRATION_CHANNELENABLEVIBRATION = "channelEnableVibration";
+ public static final String KEY_REGISTRATION_TEMPLATENAME = "templateName";
+ public static final String KEY_REGISTRATION_TEMPLATE = "template";
+ public static final String KEY_REGISTRATION_ISTEMPLATE = "isTemplate";
// Shared prefs used in NotificationHubUtil
public static final String SHARED_PREFS_NAME = "com.azure.reactnative.notificationhub.NotificationHubUtil";
@@ -36,6 +39,10 @@ public final class ReactNativeConstants {
public static final String KEY_FOR_PREFS_CHANNELSHOWBADGE = "AzureNotificationHub_channelShowBadge";
public static final String KEY_FOR_PREFS_CHANNELENABLELIGHTS = "AzureNotificationHub_channelEnableLights";
public static final String KEY_FOR_PREFS_CHANNELENABLEVIBRATION = "AzureNotificationHub_channelEnableVibration";
+ public static final String KEY_FOR_PREFS_TEMPLATENAME = "AzureNotificationHub_templateName";
+ public static final String KEY_FOR_PREFS_TEMPLATE = "AzureNotificationHub_template";
+ public static final String KEY_FOR_PREFS_ISTEMPLATE = "AzureNotificationHub_isTemplate";
+ public static final String KEY_FOR_PREFS_UUID = "AzureNotificationHub_UUID";
// Remote notification payload
public static final String KEY_REMOTE_NOTIFICATION_MESSAGE = "message";
@@ -85,6 +92,10 @@ public final class ReactNativeConstants {
public static final String RESOURCE_NAME_NOTIFICATION = "ic_notification";
public static final String RESOURCE_NAME_LAUNCHER = "ic_launcher";
+ // Promise
+ public static final String KEY_PROMISE_RESOLVE_UUID = "uuid";
+ public static final String AZURE_NOTIFICATION_HUB_UNREGISTERED = "Unregistered successfully";
+
// Errors
public static final String ERROR_NO_ACTIVITY_CLASS = "No activity class found for the notification";
public static final String ERROR_NO_MESSAGE = "No message specified for the notification";
@@ -96,6 +107,8 @@ public final class ReactNativeConstants {
public static final String ERROR_INVALID_CONNECTION_STRING = "Connection string cannot be null.";
public static final String ERROR_INVALID_HUBNAME = "Hub name cannot be null.";
public static final String ERROR_INVALID_SENDER_ID = "Sender ID cannot be null.";
+ public static final String ERROR_INVALID_TEMPLATE_NAME = "Template Name cannot be null.";
+ public static final String ERROR_INVALID_TEMPLATE = "Template cannot be null.";
public static final String ERROR_PLAY_SERVICES = "E_PLAY_SERVICES";
public static final String ERROR_PLAY_SERVICES_DISABLED = "User must enable Google Play Services.";
public static final String ERROR_PLAY_SERVICES_UNSUPPORTED = "This device is not supported by Google Play Services.";
@@ -103,6 +116,12 @@ public final class ReactNativeConstants {
public static final String ERROR_NOT_REGISTERED = "E_NOT_REGISTERED";
public static final String ERROR_NOT_REGISTERED_DESC = "No registration to Azure Notification Hub.";
public static final String ERROR_FETCH_IMAGE = "Error while fetching image.";
+ public static final String ERROR_GET_INIT_NOTIFICATION = "E_GET_INIT_NOTIF";
+ public static final String ERROR_ACTIVITY_IS_NULL = "Current activity is null";
+ public static final String ERROR_INTENT_EXTRAS_IS_NULL = "Intent get extras is null";
+ public static final String ERROR_ACTIVITY_INTENT_IS_NULL = "Activity intent is null";
+ public static final String ERROR_GET_UUID = "E_GET_UUID";
+ public static final String ERROR_NO_UUID_SET = "No uuid set";
private ReactNativeConstants() {
}
diff --git a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubModule.java b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubModule.java
index 2f507a96..b4eee759 100644
--- a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubModule.java
+++ b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubModule.java
@@ -7,10 +7,13 @@
import android.content.IntentFilter;
import android.os.Bundle;
+import androidx.core.app.NotificationManagerCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.facebook.react.bridge.ActivityEventListener;
+import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
@@ -61,6 +64,29 @@ public boolean getIsForeground() {
return notificationHubUtil.getAppIsForeground();
}
+ @ReactMethod
+ public void getInitialNotification(Promise promise) {
+ Activity activity = getCurrentActivity();
+ if (activity == null) {
+ promise.reject(ERROR_GET_INIT_NOTIFICATION, ERROR_ACTIVITY_IS_NULL);
+ return;
+ }
+
+ Intent intent = activity.getIntent();
+ if (intent != null && intent.getAction() != null) {
+ if (intent.getExtras() == null) {
+ // In certain cases while app cold launches, i.getExtras() returns null.
+ // Adding the check to make sure app won't crash,
+ // and still successfully launches from notification
+ promise.reject(ERROR_GET_INIT_NOTIFICATION, ERROR_INTENT_EXTRAS_IS_NULL);
+ } else {
+ promise.resolve(ReactNativeUtil.convertBundleToMap(intent.getExtras()));
+ }
+ } else {
+ promise.reject(ERROR_GET_INIT_NOTIFICATION, ERROR_ACTIVITY_INTENT_IS_NULL);
+ }
+ }
+
@ReactMethod
public void register(ReadableMap config, Promise promise) {
ReactNativeNotificationHubUtil notificationHubUtil = ReactNativeNotificationHubUtil.getInstance();
@@ -95,6 +121,114 @@ public void register(ReadableMap config, Promise promise) {
notificationHubUtil.setConnectionString(reactContext, connectionString);
notificationHubUtil.setHubName(reactContext, hubName);
notificationHubUtil.setSenderID(reactContext, senderID);
+ notificationHubUtil.setTemplated(reactContext, false);
+ notificationHubUtil.setTags(reactContext, tags);
+
+ if (config.hasKey(KEY_REGISTRATION_CHANNELNAME)) {
+ String channelName = config.getString(KEY_REGISTRATION_CHANNELNAME);
+ notificationHubUtil.setChannelName(reactContext, channelName);
+ }
+
+ if (config.hasKey(KEY_REGISTRATION_CHANNELIMPORTANCE)) {
+ int channelImportance = config.getInt(KEY_REGISTRATION_CHANNELIMPORTANCE);
+ notificationHubUtil.setChannelImportance(reactContext, channelImportance);
+ }
+
+ if (config.hasKey(KEY_REGISTRATION_CHANNELSHOWBADGE)) {
+ boolean channelShowBadge = config.getBoolean(KEY_REGISTRATION_CHANNELSHOWBADGE);
+ notificationHubUtil.setChannelShowBadge(reactContext, channelShowBadge);
+ }
+
+ if (config.hasKey(KEY_REGISTRATION_CHANNELENABLELIGHTS)) {
+ boolean channelEnableLights = config.getBoolean(KEY_REGISTRATION_CHANNELENABLELIGHTS);
+ notificationHubUtil.setChannelEnableLights(reactContext, channelEnableLights);
+ }
+
+ if (config.hasKey(KEY_REGISTRATION_CHANNELENABLEVIBRATION)) {
+ boolean channelEnableVibration = config.getBoolean(KEY_REGISTRATION_CHANNELENABLEVIBRATION);
+ notificationHubUtil.setChannelEnableVibration(reactContext, channelEnableVibration);
+ }
+
+ String uuid = notificationHubUtil.getUUID(reactContext);
+ if (uuid == null) {
+ uuid = ReactNativeUtil.genUUID();
+ notificationHubUtil.setUUID(reactContext, uuid);
+ }
+
+ GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
+ int resultCode = apiAvailability.isGooglePlayServicesAvailable(reactContext);
+ if (resultCode != ConnectionResult.SUCCESS) {
+ if (apiAvailability.isUserResolvableError(resultCode)) {
+ UiThreadUtil.runOnUiThread(
+ new GoogleApiAvailabilityRunnable(
+ getCurrentActivity(),
+ apiAvailability,
+ resultCode));
+ promise.reject(ERROR_PLAY_SERVICES, ERROR_PLAY_SERVICES_DISABLED);
+ } else {
+ promise.reject(ERROR_PLAY_SERVICES, ERROR_PLAY_SERVICES_UNSUPPORTED);
+ }
+ return;
+ }
+
+ Intent intent = ReactNativeNotificationHubUtil.IntentFactory.createIntent(
+ reactContext, ReactNativeRegistrationIntentService.class);
+ ReactNativeRegistrationIntentService.enqueueWork(reactContext, intent);
+
+ WritableMap res = Arguments.createMap();
+ res.putString(KEY_PROMISE_RESOLVE_UUID, uuid);
+ promise.resolve(res);
+ }
+
+ @ReactMethod
+ public void registerTemplate(ReadableMap config, Promise promise) {
+ ReactNativeNotificationHubUtil notificationHubUtil = ReactNativeNotificationHubUtil.getInstance();
+ String connectionString = config.getString(KEY_REGISTRATION_CONNECTIONSTRING);
+ if (connectionString == null) {
+ promise.reject(ERROR_INVALID_ARGUMENTS, ERROR_INVALID_CONNECTION_STRING);
+ return;
+ }
+
+ String hubName = config.getString(KEY_REGISTRATION_HUBNAME);
+ if (hubName == null) {
+ promise.reject(ERROR_INVALID_ARGUMENTS, ERROR_INVALID_HUBNAME);
+ return;
+ }
+
+ String senderID = config.getString(KEY_REGISTRATION_SENDERID);
+ if (senderID == null) {
+ promise.reject(ERROR_INVALID_ARGUMENTS, ERROR_INVALID_SENDER_ID);
+ return;
+ }
+
+ String templateName = config.getString(KEY_REGISTRATION_TEMPLATENAME);
+ if (templateName == null) {
+ promise.reject(ERROR_INVALID_ARGUMENTS, ERROR_INVALID_TEMPLATE_NAME);
+ return;
+ }
+
+ String template = config.getString(KEY_REGISTRATION_TEMPLATE);
+ if (template == null) {
+ promise.reject(ERROR_INVALID_ARGUMENTS, ERROR_INVALID_TEMPLATE);
+ return;
+ }
+
+ String[] tags = null;
+ if (config.hasKey(KEY_REGISTRATION_TAGS) && !config.isNull(KEY_REGISTRATION_TAGS)) {
+ ReadableArray tagsJson = config.getArray(KEY_REGISTRATION_TAGS);
+ tags = new String[tagsJson.size()];
+ for (int i = 0; i < tagsJson.size(); ++i) {
+ tags[i] = tagsJson.getString(i);
+ }
+ }
+
+ ReactContext reactContext = getReactApplicationContext();
+ notificationHubUtil.setConnectionString(reactContext, connectionString);
+ notificationHubUtil.setHubName(reactContext, hubName);
+ notificationHubUtil.setSenderID(reactContext, senderID);
+ notificationHubUtil.setTemplateName(reactContext, templateName);
+ notificationHubUtil.setTemplate(reactContext, template);
+ notificationHubUtil.setTemplated(reactContext, true);
notificationHubUtil.setTags(reactContext, tags);
if (config.hasKey(KEY_REGISTRATION_CHANNELNAME)) {
@@ -122,6 +256,12 @@ public void register(ReadableMap config, Promise promise) {
notificationHubUtil.setChannelEnableVibration(reactContext, channelEnableVibration);
}
+ String uuid = notificationHubUtil.getUUID(reactContext);
+ if (uuid == null) {
+ uuid = ReactNativeUtil.genUUID();
+ notificationHubUtil.setUUID(reactContext, uuid);
+ }
+
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(reactContext);
if (resultCode != ConnectionResult.SUCCESS) {
@@ -141,6 +281,10 @@ public void register(ReadableMap config, Promise promise) {
Intent intent = ReactNativeNotificationHubUtil.IntentFactory.createIntent(
reactContext, ReactNativeRegistrationIntentService.class);
ReactNativeRegistrationIntentService.enqueueWork(reactContext, intent);
+
+ WritableMap res = Arguments.createMap();
+ res.putString(KEY_PROMISE_RESOLVE_UUID, uuid);
+ promise.resolve(res);
}
@ReactMethod
@@ -161,11 +305,63 @@ public void unregister(Promise promise) {
try {
hub.unregister();
notificationHubUtil.setRegistrationID(reactContext, null);
+ notificationHubUtil.setUUID(reactContext, null);
+ promise.resolve(AZURE_NOTIFICATION_HUB_UNREGISTERED);
} catch (Exception e) {
promise.reject(ERROR_NOTIFICATION_HUB, e);
}
}
+ @ReactMethod
+ public void unregisterTemplate(String templateName, Promise promise) {
+ ReactNativeNotificationHubUtil notificationHubUtil = ReactNativeNotificationHubUtil.getInstance();
+
+ ReactContext reactContext = getReactApplicationContext();
+ String connectionString = notificationHubUtil.getConnectionString(reactContext);
+ String hubName = notificationHubUtil.getHubName(reactContext);
+ String registrationId = notificationHubUtil.getRegistrationID(reactContext);
+
+ if (connectionString == null || hubName == null || registrationId == null) {
+ promise.reject(ERROR_NOT_REGISTERED, ERROR_NOT_REGISTERED_DESC);
+ return;
+ }
+
+ NotificationHub hub = ReactNativeUtil.createNotificationHub(hubName, connectionString, reactContext);
+ try {
+ hub.unregisterTemplate(templateName);
+ notificationHubUtil.setRegistrationID(reactContext, null);
+ notificationHubUtil.setUUID(reactContext, null);
+ promise.resolve(AZURE_NOTIFICATION_HUB_UNREGISTERED);
+ } catch (Exception e) {
+ promise.reject(ERROR_NOTIFICATION_HUB, e);
+ }
+ }
+
+ @ReactMethod
+ public void getUUID(Boolean autoGen, Promise promise) {
+ ReactNativeNotificationHubUtil notificationHubUtil = ReactNativeNotificationHubUtil.getInstance();
+ ReactContext reactContext = getReactApplicationContext();
+ String uuid = notificationHubUtil.getUUID(reactContext);
+
+ if (uuid != null) {
+ promise.resolve(uuid);
+ } else if (autoGen) {
+ uuid = ReactNativeUtil.genUUID();
+ notificationHubUtil.setUUID(reactContext, uuid);
+ promise.resolve(uuid);
+ } else {
+ promise.reject(ERROR_GET_UUID, ERROR_NO_UUID_SET);
+ }
+ }
+
+ @ReactMethod
+ public void isNotificationEnabledOnOSLevel(Promise promise) {
+ ReactContext reactContext = getReactApplicationContext();
+ NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(reactContext);
+ boolean areNotificationsEnabled = notificationManagerCompat.areNotificationsEnabled();
+ promise.resolve(areNotificationsEnabled);
+ }
+
@Override
public void onHostResume() {
setIsForeground(true);
diff --git a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubUtil.java b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubUtil.java
index 1ca6a33e..e7890a1a 100644
--- a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubUtil.java
+++ b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeNotificationHubUtil.java
@@ -165,6 +165,38 @@ public boolean hasChannelEnableVibration(Context context) {
return hasKey(context, KEY_FOR_PREFS_CHANNELENABLEVIBRATION);
}
+ public String getTemplateName(Context context) {
+ return getPref(context, KEY_FOR_PREFS_TEMPLATENAME);
+ }
+
+ public void setTemplateName(Context context, String templateName) {
+ setPref(context, KEY_FOR_PREFS_TEMPLATENAME, templateName);
+ }
+
+ public String getTemplate(Context context) {
+ return getPref(context, KEY_FOR_PREFS_TEMPLATE);
+ }
+
+ public void setTemplate(Context context, String template) {
+ setPref(context, KEY_FOR_PREFS_TEMPLATE, template);
+ }
+
+ public boolean isTemplated(Context context) {
+ return getPrefBoolean(context, KEY_FOR_PREFS_ISTEMPLATE);
+ }
+
+ public void setTemplated(Context context, boolean templated) {
+ setPrefBoolean(context, KEY_FOR_PREFS_ISTEMPLATE, templated);
+ }
+
+ public String getUUID(Context context) {
+ return getPref(context, KEY_FOR_PREFS_UUID);
+ }
+
+ public void setUUID(Context context, String uuid) {
+ setPref(context, KEY_FOR_PREFS_UUID, uuid);
+ }
+
public void setAppIsForeground(boolean isForeground) {
mIsForeground = isForeground;
}
diff --git a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeRegistrationIntentService.java b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeRegistrationIntentService.java
index 3dbcec63..4c94d275 100644
--- a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeRegistrationIntentService.java
+++ b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeRegistrationIntentService.java
@@ -38,6 +38,9 @@ protected void onHandleWork(Intent intent) {
final String hubName = notificationHubUtil.getHubName(this);
final String storedToken = notificationHubUtil.getFCMToken(this);
final String[] tags = notificationHubUtil.getTags(this);
+ final boolean isTemplated = notificationHubUtil.isTemplated(this);
+ final String templateName = notificationHubUtil.getTemplateName(this);
+ final String template = notificationHubUtil.getTemplate(this);
if (connectionString == null || hubName == null) {
// The intent was triggered when no connection string has been set.
@@ -63,7 +66,13 @@ public void onSuccess(InstanceIdResult instanceIdResult) {
ReactNativeRegistrationIntentService.this);
Log.d(TAG, "NH Registration refreshing with token : " + token);
- regID = hub.register(token, tags).getRegistrationId();
+ if (isTemplated) {
+ regID = hub.registerTemplate(
+ token, templateName, template, tags).getRegistrationId();
+ } else {
+ regID = hub.register(token, tags).getRegistrationId();
+ }
+
Log.d(TAG, "New NH Registration Successfully - RegId : " + regID);
notificationHubUtil.setRegistrationID(ReactNativeRegistrationIntentService.this, regID);
diff --git a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeUtil.java b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeUtil.java
index 0def0bf8..06b241af 100644
--- a/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeUtil.java
+++ b/android/src/main/java/com/azure/reactnative/notificationhub/ReactNativeUtil.java
@@ -26,9 +26,9 @@
import java.io.InputStream;
import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
import java.net.URL;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -335,6 +335,10 @@ public static Bitmap fetchImage(String urlString) {
}
}
+ public static String genUUID() {
+ return UUID.randomUUID().toString();
+ }
+
private ReactNativeUtil() {
}
}
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index ed2869f0..11ff3445 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -42,10 +42,6 @@ steps:
displayName: 'Run lint'
workingDirectory: '../sample'
-- script: npm run test
- displayName: 'Run unit tests'
- workingDirectory: '../sample'
-
- task: Gradle@2
displayName: 'Building Android'
inputs:
@@ -78,6 +74,7 @@ steps:
- script: |
pod install
+ pod update
sudo cp -R ../node_modules/react-native-azurenotificationhub/ios Pods/RNAzureNotificationHub
sudo chown -R $(id -u):$(id -g) Pods/RNAzureNotificationHub
pod update
diff --git a/docs/android-installation.md b/docs/android-installation.md
index e7e142a4..0ce0286a 100644
--- a/docs/android-installation.md
+++ b/docs/android-installation.md
@@ -203,6 +203,9 @@ const channelImportance = 3; // The channel's importance (NotificationM
const channelShowBadge = true;
const channelEnableLights = true;
const channelEnableVibration = true;
+const template = '...'; // Notification hub templates:
+ // https://docs.microsoft.com/en-us/azure/notification-hubs/notification-hubs-templates-cross-platform-push-messages
+const templateName = '...'; // The template's name
export default class App extends Component {
constructor(props) {
@@ -213,7 +216,7 @@ export default class App extends Component {
register() {
PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED, this._onAzureNotificationHubRegistered);
PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED_ERROR, this._onAzureNotificationHubRegisteredError);
-
+
NotificationHub.register({
connectionString,
hubName,
@@ -225,12 +228,59 @@ export default class App extends Component {
channelEnableLights,
channelEnableVibration
})
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ registerTemplate() {
+ PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED, this._onAzureNotificationHubRegistered);
+ PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED_ERROR, this._onAzureNotificationHubRegisteredError);
+
+ NotificationHub.registerTemplate({
+ connectionString,
+ hubName,
+ senderID,
+ template,
+ templateName,
+ tags,
+ channelName,
+ channelImportance,
+ channelShowBadge,
+ channelEnableLights,
+ channelEnableVibration
+ })
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ getInitialNotification() {
+ NotificationHub.getInitialNotification()
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ getUUID() {
+ NotificationHub.getUUID(false)
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ isNotificationEnabledOnOSLevel() {
+ NotificationHub.isNotificationEnabledOnOSLevel()
+ .then((res) => console.warn(res))
.catch(reason => console.warn(reason));
}
unregister() {
NotificationHub.unregister()
- .catch(reason => console.warn(reason));
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ unregisterTemplate() {
+ NotificationHub.unregisterTemplate(templateName)
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
}
render() {
@@ -240,28 +290,63 @@ export default class App extends Component {
Register
-
+
+
+
+
+
+
+ Register Template
+
+
+
+
+
+
+ Get initial notification
+
+
+
+
+
+
+ Get UUID
+
+
+
+
+
+
+ Check if notification is enabled
+
Unregister
-
+
+
+
+
+
+
+ Unregister Template
+
);
}
-
+
_onAzureNotificationHubRegistered(registrationID) {
console.warn('RegistrationID: ' + registrationID);
}
-
+
_onAzureNotificationHubRegisteredError(error) {
console.warn('Error: ' + error);
}
-
+
_onRemoteNotification(notification) {
console.warn(notification);
}
diff --git a/docs/ios-installation.md b/docs/ios-installation.md
index 65c0593e..c3cf3996 100644
--- a/docs/ios-installation.md
+++ b/docs/ios-installation.md
@@ -9,7 +9,7 @@ react-native init ReactNativeAzureNotificationHubSample
```
In addition to the standard React Native requirements, you will also need the following:
-* An iOS 9 (or later version)-capable device (simulator doesn't work with push notifications)
+* An iOS 10 (or later version)-capable device (simulator doesn't work with push notifications)
* [Apple Developer Program](https://developer.apple.com/programs/) membership
## Install react-native-azurenotificationhub
@@ -156,34 +156,44 @@ Add the following line to your `ios/Podfile` file and run **pod install**
* And then add the following code in the same file:
```objective-c
-// Required to register for notifications
-- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
- [RCTAzureNotificationHubManager didRegisterUserNotificationSettings:notificationSettings];
+ ...
+
+ // Registering for local notifications
+ [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
+
+ return YES;
}
-// Required for the register event.
+// Invoked when the app successfully registered with Apple Push Notification service (APNs).
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RCTAzureNotificationHubManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
-// Required for the registrationError event.
+// Invoked when APNs cannot successfully complete the registration process.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RCTAzureNotificationHubManager didFailToRegisterForRemoteNotificationsWithError:error];
}
-// Required for the notification event.
-- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
+// Invoked when a remote notification arrived and there is data to be fetched.
+- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
+fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
- [RCTAzureNotificationHubManager didReceiveRemoteNotification:notification];
+ [RCTAzureNotificationHubManager didReceiveRemoteNotification:userInfo
+ fetchCompletionHandler:completionHandler];
}
-// Required for the localNotification event.
-- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
+// Invoked when a notification arrived while the app was running in the foreground.
+- (void)userNotificationCenter:(UNUserNotificationCenter *)center
+ willPresentNotification:(UNNotification *)notification
+ withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
- [RCTAzureNotificationHubManager didReceiveLocalNotification:notification];
+ [RCTAzureNotificationHubManager userNotificationCenter:center
+ willPresentNotification:notification
+ withCompletionHandler:completionHandler];
}
```
@@ -221,9 +231,12 @@ import {
const NotificationHub = require('react-native-azurenotificationhub/index.ios');
-const connectionString = '...'; // The Notification Hub connection string
-const hubName = '...'; // The Notification Hub name
-const tags = [ ... ]; // The set of tags to subscribe to
+const connectionString = '...'; // The Notification Hub connection string
+const hubName = '...'; // The Notification Hub name
+const tags = [ ... ]; // The set of tags to subscribe to
+const template = '...'; // Notification hub templates:
+ // https://docs.microsoft.com/en-us/azure/notification-hubs/notification-hubs-templates-cross-platform-push-messages
+const templateName = '...'; // The template's name
let remoteNotificationsDeviceToken = ''; // The device token registered with APNS
@@ -267,15 +280,33 @@ export default class App extends Component {
// rejects, or if the permissions were previously rejected. The promise
// resolves to the current state of the permission of
// {alert: boolean, badge: boolean,sound: boolean }
- NotificationHub.requestPermissions();
+ NotificationHub.requestPermissions()
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
}
register() {
- NotificationHub.register(remoteNotificationsDeviceToken, {connectionString, hubName, tags});
+ NotificationHub.register(remoteNotificationsDeviceToken, { connectionString, hubName, tags })
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ registerTemplate() {
+ NotificationHub.registerTemplate(remoteNotificationsDeviceToken, { connectionString, hubName, tags, templateName, template })
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
}
unregister() {
- NotificationHub.unregister();
+ NotificationHub.unregister()
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ unregisterTemplate() {
+ NotificationHub.unregisterTemplate(templateName)
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
}
render() {
@@ -295,6 +326,13 @@ export default class App extends Component {
+
+
+
+ Register Template
+
+
+
@@ -302,6 +340,13 @@ export default class App extends Component {
+
+
+
+ Unregister Template
+
+
+
);
}
diff --git a/ios/AzureNotificationHubIOS.js b/ios/AzureNotificationHubIOS.js
index 4a729795..952010e4 100644
--- a/ios/AzureNotificationHubIOS.js
+++ b/ios/AzureNotificationHubIOS.js
@@ -357,12 +357,20 @@ class AzureNotificationHubIOS {
RCTAzureNotificationHubManager.checkPermissions(callback);
}
- static register(deviceToken, config) {
- RCTAzureNotificationHubManager.register(deviceToken, config);
+ static register(deviceToken, config): Promise {
+ return RCTAzureNotificationHubManager.register(deviceToken, config);
}
- static unregister() {
- RCTAzureNotificationHubManager.unregister();
+ static registerTemplate(deviceToken, config): Promise {
+ return RCTAzureNotificationHubManager.registerTemplate(deviceToken, config);
+ }
+
+ static unregister(): Promise {
+ return RCTAzureNotificationHubManager.unregister();
+ }
+
+ static unregisterTemplate(templateName): Promise {
+ return RCTAzureNotificationHubManager.unregisterTemplate(templateName);
}
/**
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.h b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.h
index 34d4c476..2614c39d 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.h
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.h
@@ -35,9 +35,6 @@
// Handle registration error for Azure Notification Hub
- (void)azureNotificationHubRegisteredError:(nonnull NSNotification *)notification;
-// Handle successful registration for UIUserNotificationSettings
-- (void)userNotificationSettingsRegistered:(nonnull NSNotification *)notification;
-
@end
#endif /* RCTAzureNotificationHandler_h */
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.m b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.m
index 81222d54..cb595091 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.m
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHandler.m
@@ -10,8 +10,6 @@
#import "RCTAzureNotificationHub.h"
#import "RCTAzureNotificationHandler.h"
-extern RCTPromiseResolveBlock requestPermissionsResolveBlock;
-
@implementation RCTAzureNotificationHandler
{
@private
@@ -92,24 +90,4 @@ - (void)azureNotificationHubRegisteredError:(nonnull NSNotification *)notificati
body:errorDetails];
}
-// Handle successful registration for UIUserNotificationSettings
-- (void)userNotificationSettingsRegistered:(nonnull NSNotification *)notification
-{
- RCTPromiseResolveBlock resolve = notification.userInfo[RCTUserInfoResolveBlock];
- if (resolve == nil)
- {
- return;
- }
-
- UIUserNotificationSettings *notificationSettings = notification.userInfo[RCTUserInfoNotificationSettings];
- NSDictionary *notificationTypes = @{
- RCTNotificationTypeAlert: @((notificationSettings.types & UIUserNotificationTypeAlert) > 0),
- RCTNotificationTypeSound: @((notificationSettings.types & UIUserNotificationTypeSound) > 0),
- RCTNotificationTypeBadge: @((notificationSettings.types & UIUserNotificationTypeBadge) > 0),
- };
-
- resolve(notificationTypes);
- requestPermissionsResolveBlock = nil;
-}
-
@end
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.h b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.h
index 005a602b..2f997ac4 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.h
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.h
@@ -10,6 +10,8 @@
#ifndef RCTAzureNotificationHub_h
#define RCTAzureNotificationHub_h
+@import UserNotifications;
+
// Notification Hub events
extern NSString *const RCTLocalNotificationReceived;
extern NSString *const RCTRemoteNotificationReceived;
@@ -23,9 +25,10 @@ extern NSString *const RCTUserNotificationSettingsRegistered;
extern NSString *const RCTConnectionStringKey;
extern NSString *const RCTHubNameKey;
extern NSString *const RCTTagsKey;
+extern NSString *const RCTTemplateNameKey;
+extern NSString *const RCTTemplateKey;
// User info
-extern NSString *const RCTUserInfoNotificationSettings;
extern NSString *const RCTUserInfoDeviceToken;
extern NSString *const RCTUserInfoRemote;
extern NSString *const RCTUserInfoResolveBlock;
@@ -38,15 +41,25 @@ extern NSString *const RCTNotificationTypeBadge;
extern NSString *const RCTNotificationTypeSound;
extern NSString *const RCTNotificationTypeAlert;
+// Messages
+extern NSString *const RCTPromiseResolveUnregiseredSuccessfully;
+
// Errors
extern NSString *const RCTErrorUnableToRequestPermissions;
-extern NSString *const RCTErrorUnableToRequestPermissionsDetails;
+extern NSString *const RCTErrorUnableToRequestPermissionsAppExt;
extern NSString *const RCTErrorUnableToRequestPermissionsTwice;
+extern NSString *const RCTErrorUnableToRequestPermissionsUserReject;
extern NSString *const RCTErrorInvalidArguments;
extern NSString *const RCTErrorMissingConnectionString;
extern NSString *const RCTErrorMissingHubName;
+extern NSString *const RCTErrorMissingTemplateName;
+extern NSString *const RCTErrorMissingTemplate;
+extern NSString *const RCTErrorUnableToUnregister;
+extern NSString *const RCTErrorUnableToUnregisterNoRegistration;
-// Completion type used in Azure Notification Hub's native methods
+// Completion types
typedef void (^RCTNativeCompletion)(NSError *error);
+typedef void (^RCTNotificationCompletion)(BOOL granted, NSError * _Nullable error);
+typedef void (^RCTNotificationSettingsCompletion)(UNNotificationSettings * _Nonnull settings);
#endif /* RCTAzureNotificationHub_h */
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.m b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.m
index c1834d3e..d682014c 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.m
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHub.m
@@ -20,9 +20,10 @@
NSString *const RCTConnectionStringKey = @"connectionString";
NSString *const RCTHubNameKey = @"hubName";
NSString *const RCTTagsKey = @"tags";
+NSString *const RCTTemplateNameKey = @"templateName";
+NSString *const RCTTemplateKey = @"template";
// User info
-NSString *const RCTUserInfoNotificationSettings = @"notificationSettings";
NSString *const RCTUserInfoDeviceToken = @"deviceToken";
NSString *const RCTUserInfoRemote = @"remote";
NSString *const RCTUserInfoResolveBlock = @"resolveBlock";
@@ -35,10 +36,18 @@
NSString *const RCTNotificationTypeSound = @"sound";
NSString *const RCTNotificationTypeAlert = @"alert";
+// Messages
+NSString *const RCTPromiseResolveUnregiseredSuccessfully = @"Unregisted successfully";
+
// Errors
NSString *const RCTErrorUnableToRequestPermissions = @"Unabled to request permissions";
-NSString *const RCTErrorUnableToRequestPermissionsDetails = @"Requesting push notifications is currently unavailable in an app extension";
+NSString *const RCTErrorUnableToRequestPermissionsAppExt = @"Requesting push notifications is currently unavailable in an app extension.";
NSString *const RCTErrorUnableToRequestPermissionsTwice = @"Cannot call requestPermissions twice before the first has returned.";
+NSString *const RCTErrorUnableToRequestPermissionsUserReject = @"User didn't allow permissions.";
NSString *const RCTErrorInvalidArguments = @"Invalid arguments";
NSString *const RCTErrorMissingConnectionString = @"Connection string cannot be null.";
NSString *const RCTErrorMissingHubName = @"Hub name cannot be null.";
+NSString *const RCTErrorMissingTemplateName = @"Template name cannot be null.";
+NSString *const RCTErrorMissingTemplate = @"Template cannot be null.";
+NSString *const RCTErrorUnableToUnregister = @"Unabled to unregister";
+NSString *const RCTErrorUnableToUnregisterNoRegistration = @"There is no registration.";
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.h b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.h
index bfd707e6..6d09f99f 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.h
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.h
@@ -9,22 +9,26 @@
#import "React/RCTEventEmitter.h"
-@interface RCTAzureNotificationHubManager : RCTEventEmitter
+#import "RCTAzureNotificationHandler.h"
+
+@import UserNotifications;
-// Required to register for notifications, invoked from AppDelegate
-+ (void)didRegisterUserNotificationSettings:(nonnull UIUserNotificationSettings *)notificationSettings;
+@interface RCTAzureNotificationHubManager : RCTEventEmitter
-// Required for the register event, invoked from AppDelegate
+// Invoked from AppDelegate when the app successfully registered with Apple Push Notification service (APNs).
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(nonnull NSData *)deviceToken;
-// Required for the notification event, invoked from AppDelegate
-+ (void)didReceiveRemoteNotification:(nonnull NSDictionary *)notification;
+// Invoked from AppDelegate when APNs cannot successfully complete the registration process.
++ (void)didFailToRegisterForRemoteNotificationsWithError:(nonnull NSError *)error;
-// Required for the localNotification event, invoked from AppDelegate
-+ (void)didReceiveLocalNotification:(nonnull UILocalNotification *)notification;
+// Invoked from AppDelegate when a remote notification arrived and there is data to be fetched.
++ (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
+ fetchCompletionHandler:(void (__unused ^_Nonnull)(UIBackgroundFetchResult result))completionHandler;
-// Required for the registrationError event, invoked from AppDelegate
-+ (void)didFailToRegisterForRemoteNotificationsWithError:(nonnull NSError *)error;
+// Invoked from AppDelegate when a notification arrived while the app was running in the foreground.
++ (void)userNotificationCenter:(nonnull __unused UNUserNotificationCenter *)center
+ willPresentNotification:(nonnull UNNotification *)notification
+ withCompletionHandler:(void (__unused ^_Nonnull)(UNNotificationPresentationOptions options))completionHandler;
// Set application icon badge number
- (void)setApplicationIconBadgeNumber:(NSInteger)number;
@@ -65,11 +69,25 @@
// Register with Azure Notification Hub
- (void)register:(nonnull NSString *)deviceToken
config:(nonnull NSDictionary *)config
- resolver:(nonnull RCTPromiseResolveBlock)resolve
+ resolver:(nonnull __unused RCTPromiseResolveBlock)resolve
rejecter:(nonnull RCTPromiseRejectBlock)reject;
+// Register template
+- (void)registerTemplate:(nonnull NSString *)deviceToken
+ config:(nonnull NSDictionary *)config
+ resolver:(nonnull __unused RCTPromiseResolveBlock)resolve
+ rejecter:(nonnull RCTPromiseRejectBlock)reject;
+
// Unregister with Azure Notification Hub
- (void)unregister:(nonnull RCTPromiseResolveBlock)resolve
rejecter:(nonnull RCTPromiseRejectBlock)reject;
+// Unregister template
+- (void)unregisterTemplate:(nonnull NSString *)templateName
+ resolver:(nonnull RCTPromiseResolveBlock)resolve
+ rejecter:(nonnull RCTPromiseRejectBlock)reject;
+
+// Set notification handler
+- (void)setNotificationHandler:(nonnull RCTAzureNotificationHandler *)handler;
+
@end
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.m b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.m
index deba2f41..534da9d8 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.m
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubManager.m
@@ -15,7 +15,6 @@
#import "React/RCTUtils.h"
#import "RCTAzureNotificationHub.h"
-#import "RCTAzureNotificationHandler.h"
#import "RCTAzureNotificationHubManager.h"
#import "RCTAzureNotificationHubUtil.h"
@@ -23,20 +22,30 @@
RCT_EXTERN NSString *const RCTErrorUnspecified;
static RCTAzureNotificationHandler *notificationHandler;
-RCTPromiseResolveBlock requestPermissionsResolveBlock;
-RCTPromiseRejectBlock requestPermissionsRejectBlock;
@implementation RCTAzureNotificationHubManager
{
@private
// The Notification Hub connection string
NSString *_connectionString;
-
+
// The Notification Hub name
NSString *_hubName;
-
+
// The Notification Hub tags
NSSet *_tags;
+
+ // The template name
+ NSString *_templateName;
+
+ // The template JSON blob
+ NSString *_template;
+
+ // The Promise resolve block
+ RCTPromiseResolveBlock _requestPermissionsResolveBlock;
+
+ // The Promise reject block
+ RCTPromiseRejectBlock _requestPermissionsRejectBlock;
}
RCT_EXPORT_MODULE()
@@ -90,11 +99,6 @@ - (void)startObserving
selector:@selector(azureNotificationHubRegisteredError:)
name:RCTAzureNotificationHubRegisteredError
object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:notificationHandler
- selector:@selector(userNotificationSettingsRegistered:)
- name:RCTUserNotificationSettingsRegistered
- object:nil];
}
- (void)stopObserving
@@ -102,35 +106,10 @@ - (void)stopObserving
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-- (bool)assertArguments:(RCTPromiseRejectBlock)reject
+// Set notification handler
+- (void)setNotificationHandler:(nonnull RCTAzureNotificationHandler *)handler
{
- if (_connectionString == nil)
- {
- reject(RCTErrorInvalidArguments, RCTErrorMissingConnectionString, nil);
- return false;
- }
-
- if (_hubName == nil)
- {
- reject(RCTErrorInvalidArguments, RCTErrorMissingHubName, nil);
- return false;
- }
-
- return true;
-}
-
-+ (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
-{
- if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)])
- {
- [[UIApplication sharedApplication] registerForRemoteNotifications];
- [[NSNotificationCenter defaultCenter] postNotificationName:RCTUserNotificationSettingsRegistered
- object:notificationHandler
- userInfo:@{
- RCTUserInfoNotificationSettings: notificationSettings,
- RCTUserInfoResolveBlock: requestPermissionsResolveBlock
- }];
- }
+ notificationHandler = handler;
}
+ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
@@ -148,18 +127,21 @@ + (void)didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
userInfo:@{RCTUserInfoError: error}];
}
-+ (void)didReceiveRemoteNotification:(NSDictionary *)notification
++ (void)didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
+ fetchCompletionHandler:(void (__unused ^_Nonnull)(UIBackgroundFetchResult result))completionHandler
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
object:notificationHandler
- userInfo:notification];
+ userInfo:userInfo];
}
-+ (void)didReceiveLocalNotification:(UILocalNotification *)notification
++ (void)userNotificationCenter:(nonnull __unused UNUserNotificationCenter *)center
+ willPresentNotification:(nonnull UNNotification *)notification
+ withCompletionHandler:(void (__unused ^_Nonnull)(UNNotificationPresentationOptions options))completionHandler
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTLocalNotificationReceived
object:notificationHandler
- userInfo:[RCTAzureNotificationHubUtil formatLocalNotification:notification]];
+ userInfo:[RCTAzureNotificationHubUtil formatUNNotification:notification]];
}
// Update the application icon badge number on the home screen
@@ -180,31 +162,49 @@ + (void)didReceiveLocalNotification:(UILocalNotification *)notification
{
if (RCTRunningInAppExtension())
{
- reject(RCTErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(RCTErrorUnableToRequestPermissionsDetails));
+ reject(RCTErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(RCTErrorUnableToRequestPermissionsAppExt));
return;
}
-
- if (requestPermissionsResolveBlock != nil)
+
+ if (_requestPermissionsResolveBlock != nil)
{
RCTLogError(@"%@", RCTErrorUnableToRequestPermissionsTwice);
return;
}
-
- requestPermissionsResolveBlock = resolve;
- requestPermissionsRejectBlock = reject;
-
- UIUserNotificationType types = [RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions];
- UIApplication *app = RCTSharedApplication();
- if ([app respondsToSelector:@selector(registerUserNotificationSettings:)])
- {
- UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:(NSUInteger)types
- categories:nil];
- [app registerUserNotificationSettings:notificationSettings];
- }
- else
- {
- [app registerForRemoteNotificationTypes:(NSUInteger)types];
- }
+
+ _requestPermissionsResolveBlock = resolve;
+ _requestPermissionsRejectBlock = reject;
+
+ UNAuthorizationOptions options = [RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions];
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+ [center requestAuthorizationWithOptions:options
+ completionHandler:^(BOOL granted, NSError * _Nullable error) {
+ if (error != nil)
+ {
+ reject(RCTErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(error.localizedDescription));
+ }
+ else if (!granted)
+ {
+ reject(RCTErrorUnableToRequestPermissions, nil, RCTErrorWithMessage(RCTErrorUnableToRequestPermissionsUserReject));
+ }
+ else
+ {
+ [RCTAzureNotificationHubUtil runOnMainThread:^{
+ [[UIApplication sharedApplication] registerForRemoteNotifications];
+ }];
+
+ NSDictionary *notificationTypes = @{
+ RCTNotificationTypeAlert: @((options & UNAuthorizationOptionAlert) > 0),
+ RCTNotificationTypeSound: @((options & UNAuthorizationOptionSound) > 0),
+ RCTNotificationTypeBadge: @((options & UNAuthorizationOptionBadge) > 0),
+ };
+
+ resolve(notificationTypes);
+ }
+
+ _requestPermissionsResolveBlock = nil;
+ _requestPermissionsRejectBlock = nil;
+ }];
}
RCT_EXPORT_METHOD(abandonPermissions)
@@ -219,13 +219,18 @@ + (void)didReceiveLocalNotification:(UILocalNotification *)notification
callback(@[@{RCTNotificationTypeAlert: @NO, RCTNotificationTypeBadge: @NO, RCTNotificationTypeSound: @NO}]);
return;
}
-
- NSUInteger types = [RCTSharedApplication() currentUserNotificationSettings].types;
- callback(@[@{
- RCTNotificationTypeAlert: @((types & UIUserNotificationTypeAlert) > 0),
- RCTNotificationTypeBadge: @((types & UIUserNotificationTypeBadge) > 0),
- RCTNotificationTypeSound: @((types & UIUserNotificationTypeSound) > 0),
- }]);
+
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+
+ [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
+ callback(@[@{
+ RCTNotificationTypeAlert: @(settings.notificationCenterSetting == UNNotificationSettingEnabled
+ || settings.lockScreenSetting == UNNotificationSettingEnabled
+ || settings.alertSetting == UNNotificationSettingEnabled),
+ RCTNotificationTypeBadge: @(settings.badgeSetting == UNNotificationSettingEnabled),
+ RCTNotificationTypeSound: @(settings.soundSetting == UNNotificationSettingEnabled)
+ }]);
+ }];
}
RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification)
@@ -307,8 +312,8 @@ + (void)didReceiveLocalNotification:(UILocalNotification *)notification
RCT_EXPORT_METHOD(register:(nonnull NSString *)deviceToken
config:(nonnull NSDictionary *)config
- resolver:(RCTPromiseResolveBlock)resolve
- rejecter:(RCTPromiseRejectBlock)reject)
+ resolver:(nonnull __unused RCTPromiseResolveBlock)resolve
+ rejecter:(nonnull RCTPromiseRejectBlock)reject)
{
// Store the connection string, hub name and tags
_connectionString = [config objectForKey:RCTConnectionStringKey];
@@ -316,15 +321,22 @@ + (void)didReceiveLocalNotification:(UILocalNotification *)notification
_tags = [config objectForKey:RCTTagsKey];
// Check arguments
- if (![self assertArguments:reject])
+ if (_connectionString == nil)
{
+ reject(RCTErrorInvalidArguments, RCTErrorMissingConnectionString, nil);
return;
}
-
+
+ if (_hubName == nil)
+ {
+ reject(RCTErrorInvalidArguments, RCTErrorMissingHubName, nil);
+ return;
+ }
+
// Initialize hub
SBNotificationHub *hub = [RCTAzureNotificationHubUtil createAzureNotificationHub:_connectionString
hubName:_hubName];
-
+
// Register for native notifications
[RCTAzureNotificationHubUtil runOnMainThread:^
{
@@ -348,19 +360,87 @@ + (void)didReceiveLocalNotification:(UILocalNotification *)notification
}];
}
-RCT_EXPORT_METHOD(unregister:(RCTPromiseResolveBlock)resolve
- rejecter:(RCTPromiseRejectBlock)reject)
+RCT_EXPORT_METHOD(registerTemplate:(nonnull NSString *)deviceToken
+ config:(nonnull NSDictionary *)config
+ resolver:(nonnull __unused RCTPromiseResolveBlock)resolve
+ rejecter:(nonnull RCTPromiseRejectBlock)reject)
{
+ // Store the connection string, hub name, tags, template name and template
+ _connectionString = [config objectForKey:RCTConnectionStringKey];
+ _hubName = [config objectForKey:RCTHubNameKey];
+ _tags = [config objectForKey:RCTTagsKey];
+ _templateName = [config objectForKey:RCTTemplateNameKey];
+ _template = [config objectForKey:RCTTemplateKey];
+
// Check arguments
- if (![self assertArguments:reject])
+ if (_connectionString == nil)
{
+ reject(RCTErrorInvalidArguments, RCTErrorMissingConnectionString, nil);
return;
}
-
+
+ if (_hubName == nil)
+ {
+ reject(RCTErrorInvalidArguments, RCTErrorMissingHubName, nil);
+ return;
+ }
+
+ if (_templateName == nil)
+ {
+ reject(RCTErrorInvalidArguments, RCTErrorMissingTemplateName, nil);
+ return;
+ }
+
+ if (_template == nil)
+ {
+ reject(RCTErrorInvalidArguments, RCTErrorMissingTemplate, nil);
+ return;
+ }
+
// Initialize hub
SBNotificationHub *hub = [RCTAzureNotificationHubUtil createAzureNotificationHub:_connectionString
hubName:_hubName];
-
+
+ // Register for native notifications
+ [RCTAzureNotificationHubUtil runOnMainThread:^
+ {
+ [hub registerTemplateWithDeviceToken:deviceToken
+ name:_templateName
+ jsonBodyTemplate:_template
+ expiryTemplate:nil
+ tags:_tags
+ completion:^(NSError* error)
+ {
+ if (error != nil)
+ {
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTAzureNotificationHubRegisteredError
+ object:notificationHandler
+ userInfo:@{RCTUserInfoError: error}];
+ }
+ else
+ {
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTAzureNotificationHubRegistered
+ object:notificationHandler
+ userInfo:@{RCTUserInfoSuccess: @YES}];
+ }
+ }];
+ }];
+}
+
+RCT_EXPORT_METHOD(unregister:(nonnull RCTPromiseResolveBlock)resolve
+ rejecter:(nonnull RCTPromiseRejectBlock)reject)
+{
+ // Check arguments
+ if (_connectionString == nil || _hubName == nil)
+ {
+ reject(RCTErrorUnableToUnregister, RCTErrorUnableToUnregisterNoRegistration, nil);
+ return;
+ }
+
+ // Initialize hub
+ SBNotificationHub *hub = [RCTAzureNotificationHubUtil createAzureNotificationHub:_connectionString
+ hubName:_hubName];
+
// Unregister for native notifications
[RCTAzureNotificationHubUtil runOnMainThread:^
{
@@ -371,6 +451,49 @@ + (void)didReceiveLocalNotification:(UILocalNotification *)notification
[[NSNotificationCenter defaultCenter] postNotificationName:RCTErrorUnspecified
object:notificationHandler
userInfo:@{RCTUserInfoError: error}];
+
+ reject(RCTErrorUnableToUnregister, [error localizedDescription], nil);
+ }
+ else
+ {
+ _connectionString = nil;
+ resolve(RCTPromiseResolveUnregiseredSuccessfully);
+ }
+ }];
+ }];
+}
+
+RCT_EXPORT_METHOD(unregisterTemplate:(nonnull NSString *)templateName
+ resolver:(nonnull RCTPromiseResolveBlock)resolve
+ rejecter:(nonnull RCTPromiseRejectBlock)reject)
+{
+ // Check arguments
+ if (_connectionString == nil || _hubName == nil || _template == nil)
+ {
+ reject(RCTErrorUnableToUnregister, RCTErrorUnableToUnregisterNoRegistration, nil);
+ return;
+ }
+
+ // Initialize hub
+ SBNotificationHub *hub = [RCTAzureNotificationHubUtil createAzureNotificationHub:_connectionString
+ hubName:_hubName];
+
+ // Unregister for native notifications
+ [RCTAzureNotificationHubUtil runOnMainThread:^
+ {
+ [hub unregisterTemplateWithName:templateName completion:^(NSError *error)
+ {
+ if (error != nil)
+ {
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTErrorUnspecified
+ object:notificationHandler
+ userInfo:@{RCTUserInfoError: error}];
+
+ reject(RCTErrorUnableToUnregister, [error localizedDescription], nil);
+ }
+ else
+ {
+ resolve(RCTPromiseResolveUnregiseredSuccessfully);
}
}];
}];
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.h b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.h
index f319b226..23c0316e 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.h
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.h
@@ -12,8 +12,13 @@
#import
+@import UserNotifications;
+
@interface RCTAzureNotificationHubUtil : NSObject
+// Format UNNotification
++ (nonnull NSDictionary *)formatUNNotification:(nonnull UNNotification *)notification;
+
// Format local notification
+ (nonnull NSDictionary *)formatLocalNotification:(nonnull UILocalNotification *)notification;
@@ -25,10 +30,10 @@
+ (nonnull NSString *)convertDeviceTokenToString:(nonnull NSData *)deviceToken;
// Get notification types with permissions
-+ (UIUserNotificationType)getNotificationTypesWithPermissions:(nullable NSDictionary *)permissions;
++ (UNAuthorizationOptions)getNotificationTypesWithPermissions:(nullable NSDictionary *)permissions;
// Run block on the main thread
-+ (void)runOnMainThread:(dispatch_block_t)block;
++ (void)runOnMainThread:(nonnull dispatch_block_t)block;
@end
diff --git a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.m b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.m
index 49bed9a4..8e850e08 100644
--- a/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.m
+++ b/ios/RCTAzureNotificationHubManager/RCTAzureNotificationHubUtil.m
@@ -15,6 +15,33 @@
@implementation RCTAzureNotificationHubUtil
+// Format UNNotification
++ (nonnull NSDictionary *)formatUNNotification:(nonnull UNNotification *)notification
+{
+ NSMutableDictionary *formattedNotification = [NSMutableDictionary dictionary];
+ UNNotificationContent *content = notification.request.content;
+
+ formattedNotification[@"identifier"] = notification.request.identifier;
+
+ if (notification.date)
+ {
+ NSDateFormatter *formatter = [NSDateFormatter new];
+ [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
+ NSString *dateString = [formatter stringFromDate:notification.date];
+ formattedNotification[@"date"] = dateString;
+ }
+
+ formattedNotification[@"title"] = RCTNullIfNil(content.title);
+ formattedNotification[@"thread-id"] = RCTNullIfNil(content.threadIdentifier);
+ formattedNotification[@"alertBody"] = RCTNullIfNil(content.body);
+ formattedNotification[@"applicationIconBadgeNumber"] = RCTNullIfNil(content.badge);
+ formattedNotification[@"category"] = RCTNullIfNil(content.categoryIdentifier);
+ formattedNotification[@"soundName"] = RCTNullIfNil(content.sound);
+ formattedNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(content.userInfo));
+
+ return formattedNotification;
+}
+
// Format local notification
+ (nonnull NSDictionary *)formatLocalNotification:(nonnull UILocalNotification *)notification
{
@@ -26,7 +53,7 @@ + (nonnull NSDictionary *)formatLocalNotification:(nonnull UILocalNotification *
NSString *fireDateString = [formatter stringFromDate:notification.fireDate];
formattedLocalNotification[@"fireDate"] = fireDateString;
}
-
+
formattedLocalNotification[@"alertAction"] = RCTNullIfNil(notification.alertAction);
formattedLocalNotification[@"alertBody"] = RCTNullIfNil(notification.alertBody);
formattedLocalNotification[@"applicationIconBadgeNumber"] = @(notification.applicationIconBadgeNumber);
@@ -62,36 +89,36 @@ + (nonnull NSString *)convertDeviceTokenToString:(nonnull NSData *)deviceToken
}
// Get notification types with permissions
-+ (UIUserNotificationType)getNotificationTypesWithPermissions:(nullable NSDictionary *)permissions
++ (UNAuthorizationOptions)getNotificationTypesWithPermissions:(nullable NSDictionary *)permissions
{
- UIUserNotificationType types = UIUserNotificationTypeNone;
+ UNAuthorizationOptions types = 0;
if (permissions)
{
if ([RCTConvert BOOL:permissions[RCTNotificationTypeAlert]])
{
- types |= UIUserNotificationTypeAlert;
+ types |= UNAuthorizationOptionAlert;
}
if ([RCTConvert BOOL:permissions[RCTNotificationTypeBadge]])
{
- types |= UIUserNotificationTypeBadge;
+ types |= UNAuthorizationOptionBadge;
}
if ([RCTConvert BOOL:permissions[RCTNotificationTypeSound]])
{
- types |= UIUserNotificationTypeSound;
+ types |= UNAuthorizationOptionSound;
}
}
else
{
- types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
+ types = UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound;
}
return types;
}
// Run block on the main thread
-+ (void)runOnMainThread:(dispatch_block_t)block
++ (void)runOnMainThread:(nonnull dispatch_block_t)block
{
dispatch_async(dispatch_get_main_queue(), block);
}
diff --git a/package.json b/package.json
index 98285bc3..c748fff3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-azurenotificationhub",
- "version": "0.9.4-Patched.1",
+ "version": "0.9.5",
"description": "React Native module to support Azure Notification Hub push notifications on Android, iOS, and Windows.",
"main": "index.js",
"repository": {
diff --git a/sample/App.js b/sample/App.js
index bb775809..9a0dc485 100644
--- a/sample/App.js
+++ b/sample/App.js
@@ -6,109 +6,194 @@
* @flow
*/
-import React from 'react';
+import React, { Component } from 'react';
+import { NativeEventEmitter } from 'react-native';
import {
- SafeAreaView,
StyleSheet,
- ScrollView,
- View,
Text,
- StatusBar,
+ View,
+ TouchableOpacity,
} from 'react-native';
-import {
- Header,
- LearnMoreLinks,
- Colors,
- DebugInstructions,
- ReloadInstructions,
-} from 'react-native/Libraries/NewAppScreen';
-
-const App: () => React$Node = () => {
- return (
- <>
-
-
-
-
- {global.HermesInternal == null ? null : (
-
- Engine: Hermes
-
- )}
-
-
- Step One
-
- Edit App.js to change this
- screen and then come back to see your edits.
-
-
-
- See Your Changes
-
-
-
-
-
- Debug
-
-
-
-
-
- Learn More
-
- Read the docs to discover what to do next:
-
-
-
-
-
-
- >
- );
-};
+const NotificationHub = require('react-native-azurenotificationhub');
+const PushNotificationEmitter = new NativeEventEmitter(NotificationHub);
+
+const EVENT_AZURE_NOTIFICATION_HUB_REGISTERED = 'azureNotificationHubRegistered';
+const EVENT_AZURE_NOTIFICATION_HUB_REGISTERED_ERROR = 'azureNotificationHubRegisteredError';
+const EVENT_REMOTE_NOTIFICATION_RECEIVED = 'remoteNotificationReceived';
+
+const connectionString = 'Endpoint=sb://rn-anh.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=12345';
+const hubName = 'azurenotificationhub';
+const senderID = '12345';
+const tags = [];
+const channelName = 'Channel Name';
+const channelImportance = 3;
+const channelShowBadge = true;
+const channelEnableLights = true;
+const channelEnableVibration = true;
+const template = '{\"data\":{\"message\":\"$(message)\"}}';
+const templateName = 'Template Name';
+
+export default class App extends Component {
+ constructor(props) {
+ super(props);
+ PushNotificationEmitter.addListener(EVENT_REMOTE_NOTIFICATION_RECEIVED, this._onRemoteNotification);
+ }
+
+ register() {
+ PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED, this._onAzureNotificationHubRegistered);
+ PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED_ERROR, this._onAzureNotificationHubRegisteredError);
+
+ NotificationHub.register({
+ connectionString,
+ hubName,
+ senderID,
+ tags,
+ channelName,
+ channelImportance,
+ channelShowBadge,
+ channelEnableLights,
+ channelEnableVibration
+ })
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ registerTemplate() {
+ PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED, this._onAzureNotificationHubRegistered);
+ PushNotificationEmitter.addListener(EVENT_AZURE_NOTIFICATION_HUB_REGISTERED_ERROR, this._onAzureNotificationHubRegisteredError);
+
+ NotificationHub.registerTemplate({
+ connectionString,
+ hubName,
+ senderID,
+ template,
+ templateName,
+ tags,
+ channelName,
+ channelImportance,
+ channelShowBadge,
+ channelEnableLights,
+ channelEnableVibration
+ })
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ getInitialNotification() {
+ NotificationHub.getInitialNotification()
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ getUUID() {
+ NotificationHub.getUUID(false)
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ isNotificationEnabledOnOSLevel() {
+ NotificationHub.isNotificationEnabledOnOSLevel()
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ unregister() {
+ NotificationHub.unregister()
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ unregisterTemplate() {
+ NotificationHub.unregisterTemplate(templateName)
+ .then((res) => console.warn(res))
+ .catch(reason => console.warn(reason));
+ }
+
+ render() {
+ return (
+
+
+
+
+ Register
+
+
+
+
+
+
+ Register Template
+
+
+
+
+
+
+ Get initial notification
+
+
+
+
+
+
+ Get UUID
+
+
+
+
+
+
+ Check if notification is enabled
+
+
+
+
+
+
+ Unregister
+
+
+
+
+
+
+ Unregister Template
+
+
+
+
+ );
+ }
+
+ _onAzureNotificationHubRegistered(registrationID) {
+ console.warn('RegistrationID: ' + registrationID);
+ }
+
+ _onAzureNotificationHubRegisteredError(error) {
+ console.warn('Error: ' + error);
+ }
+
+ _onRemoteNotification(notification) {
+ console.warn(notification);
+ }
+}
const styles = StyleSheet.create({
- scrollView: {
- backgroundColor: Colors.lighter,
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#F5FCFF',
},
- engine: {
- position: 'absolute',
- right: 0,
+ welcome: {
+ fontSize: 20,
+ textAlign: 'center',
+ margin: 10,
},
- body: {
- backgroundColor: Colors.white,
- },
- sectionContainer: {
- marginTop: 32,
- paddingHorizontal: 24,
- },
- sectionTitle: {
- fontSize: 24,
- fontWeight: '600',
- color: Colors.black,
- },
- sectionDescription: {
- marginTop: 8,
- fontSize: 18,
- fontWeight: '400',
- color: Colors.dark,
- },
- highlight: {
- fontWeight: '700',
- },
- footer: {
- color: Colors.dark,
- fontSize: 12,
- fontWeight: '600',
- padding: 4,
- paddingRight: 12,
- textAlign: 'right',
+ instructions: {
+ textAlign: 'center',
+ color: '#333333',
+ marginBottom: 5,
},
});
-
-export default App;
diff --git a/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubModuleTest.java b/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubModuleTest.java
index f5201576..7bed952c 100644
--- a/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubModuleTest.java
+++ b/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubModuleTest.java
@@ -6,6 +6,8 @@
import android.content.IntentFilter;
import android.os.Bundle;
+import androidx.annotation.RequiresPermission;
+import androidx.core.app.NotificationManagerCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.junit.Assert;
@@ -14,6 +16,7 @@
import static com.azure.reactnative.notificationhub.ReactNativeConstants.*;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -35,11 +38,13 @@
import com.azure.reactnative.notificationhub.ReactNativeNotificationsHandler;
import com.azure.reactnative.notificationhub.ReactNativeRegistrationIntentService;
import com.azure.reactnative.notificationhub.ReactNativeUtil;
+import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.microsoft.windowsazure.messaging.NotificationHub;
@@ -54,7 +59,9 @@
ReactNativeUtil.class,
ReactNativeNotificationsHandler.class,
ReactNativeRegistrationIntentService.class,
- GoogleApiAvailability.class
+ GoogleApiAvailability.class,
+ Arguments.class,
+ NotificationManagerCompat.class
})
public class ReactNativeNotificationHubModuleTest {
@Mock
@@ -81,6 +88,9 @@ public class ReactNativeNotificationHubModuleTest {
@Mock
NotificationHub mNotificationHub;
+ @Mock
+ WritableMap mRes;
+
ReactNativeNotificationHubModule mHubModule;
@Before
@@ -102,6 +112,9 @@ public void setUp() {
PowerMockito.mockStatic(ReactNativeRegistrationIntentService.class);
PowerMockito.mockStatic(GoogleApiAvailability.class);
when(GoogleApiAvailability.getInstance()).thenReturn(mGoogleApiAvailability);
+ PowerMockito.mockStatic(Arguments.class);
+ when(Arguments.createMap()).thenReturn(mRes);
+ PowerMockito.mockStatic(NotificationManagerCompat.class);
mHubModule = new ReactNativeNotificationHubModule(mReactApplicationContext);
}
@@ -252,6 +265,39 @@ public void testRegisterHasChannelEnableVibration() {
any(ReactContext.class), eq(channelEnableVibration));
}
+ @Test
+ public void testRegisterGenUUID() {
+ when(mConfig.getString(KEY_REGISTRATION_CONNECTIONSTRING)).thenReturn(KEY_REGISTRATION_CONNECTIONSTRING);
+ when(mConfig.getString(KEY_REGISTRATION_HUBNAME)).thenReturn(KEY_REGISTRATION_HUBNAME);
+ when(mConfig.getString(KEY_REGISTRATION_SENDERID)).thenReturn(KEY_REGISTRATION_SENDERID);
+ when(ReactNativeUtil.genUUID()).thenReturn(PowerMockito.mock(String.class));
+
+ mHubModule.register(mConfig, mPromise);
+
+ verify(mNotificationHubUtil, times(1)).getUUID(any(ReactContext.class));
+ verify(mNotificationHubUtil, times(1)).setUUID(
+ any(ReactContext.class), anyString());
+ PowerMockito.verifyStatic((ReactNativeUtil.class));
+ ReactNativeUtil.genUUID();
+ }
+
+ @Test
+ public void testRegisterExistingUUID() {
+ when(mConfig.getString(KEY_REGISTRATION_CONNECTIONSTRING)).thenReturn(KEY_REGISTRATION_CONNECTIONSTRING);
+ when(mConfig.getString(KEY_REGISTRATION_HUBNAME)).thenReturn(KEY_REGISTRATION_HUBNAME);
+ when(mConfig.getString(KEY_REGISTRATION_SENDERID)).thenReturn(KEY_REGISTRATION_SENDERID);
+ when(mNotificationHubUtil.getUUID(any(ReactContext.class))).thenReturn(
+ PowerMockito.mock(String.class));
+
+ mHubModule.register(mConfig, mPromise);
+
+ verify(mNotificationHubUtil, times(1)).getUUID(any(ReactContext.class));
+ verify(mNotificationHubUtil, times(0)).setUUID(
+ any(ReactContext.class), anyString());
+ PowerMockito.verifyStatic((ReactNativeUtil.class), times(0));
+ ReactNativeUtil.genUUID();
+ }
+
@Test
public void testRegisterSuccessfully() {
final String connectionString = "Connection String";
@@ -278,8 +324,12 @@ public void testRegisterSuccessfully() {
any(ReactContext.class), eq(hubName));
verify(mNotificationHubUtil, times(1)).setSenderID(
any(ReactContext.class), eq(senderID));
+ verify(mNotificationHubUtil, times(1)).setTemplated(
+ any(ReactContext.class), eq(false));
verify(mNotificationHubUtil, times(1)).setTags(
any(ReactContext.class), eq(tags));
+ verify(mRes, times(1)).putString(eq(KEY_PROMISE_RESOLVE_UUID), any());
+ verify(mPromise, times(1)).resolve(mRes);
verify(mPromise, times(0)).reject(anyString(), anyString());
PowerMockito.verifyStatic(ReactNativeRegistrationIntentService.class);
@@ -319,14 +369,17 @@ public void testUnregisterSuccessfully() throws Exception {
mHubModule.unregister(mPromise);
- verify(mPromise, times(0)).reject(anyString(), anyString());
verify(mNotificationHub, times(1)).unregister();
verify(mNotificationHubUtil, times(1)).setRegistrationID(
any(ReactContext.class), eq(null));
+ verify(mNotificationHubUtil, times(1)).setUUID(
+ any(ReactContext.class), eq(null));
+ verify(mPromise, times(0)).reject(anyString(), anyString());
+ verify(mPromise, times(1)).resolve(AZURE_NOTIFICATION_HUB_UNREGISTERED);
}
@Test
- public void testUnregisterNoRegistration() throws Exception {
+ public void testUnregisterNoRegistration() {
when(mNotificationHubUtil.getConnectionString(any(ReactContext.class))).thenReturn("Connection String");
when(mNotificationHubUtil.getHubName(any(ReactContext.class))).thenReturn("Hub Name");
when(mNotificationHubUtil.getRegistrationID(any(ReactContext.class))).thenReturn(null);
@@ -358,6 +411,282 @@ public void testUnregisterThrowException() throws Exception {
unhandledException);
}
+ @Test
+ public void testRegisterTemplateMissingTemplateName() {
+ when(mConfig.getString(KEY_REGISTRATION_CONNECTIONSTRING)).thenReturn("Connection String");
+ when(mConfig.getString(KEY_REGISTRATION_HUBNAME)).thenReturn("Hub Name");
+ when(mConfig.getString(KEY_REGISTRATION_SENDERID)).thenReturn("Connection String");
+
+ mHubModule.registerTemplate(mConfig, mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_INVALID_ARGUMENTS,
+ ERROR_INVALID_TEMPLATE_NAME);
+ }
+
+ @Test
+ public void testRegisterTemplateMissingTemplate() {
+ when(mConfig.getString(KEY_REGISTRATION_CONNECTIONSTRING)).thenReturn("Connection String");
+ when(mConfig.getString(KEY_REGISTRATION_HUBNAME)).thenReturn("Hub Name");
+ when(mConfig.getString(KEY_REGISTRATION_SENDERID)).thenReturn("Connection String");
+ when(mConfig.getString(KEY_REGISTRATION_TEMPLATENAME)).thenReturn("Template Name");
+
+ mHubModule.registerTemplate(mConfig, mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_INVALID_ARGUMENTS,
+ ERROR_INVALID_TEMPLATE);
+ }
+
+ @Test
+ public void testRegisterTemplateSuccessfully() {
+ final String connectionString = "Connection String";
+ final String hubName = "Hub Name";
+ final String senderID = "Sender ID";
+ final String templateName = "Template Name";
+ final String template = "Template";
+ final String[] tags = { "Tag" };
+
+ when(mConfig.getString(KEY_REGISTRATION_CONNECTIONSTRING)).thenReturn(connectionString);
+ when(mConfig.getString(KEY_REGISTRATION_HUBNAME)).thenReturn(hubName);
+ when(mConfig.getString(KEY_REGISTRATION_SENDERID)).thenReturn(senderID);
+ when(mConfig.getString(KEY_REGISTRATION_TEMPLATENAME)).thenReturn(templateName);
+ when(mConfig.getString(KEY_REGISTRATION_TEMPLATE)).thenReturn(template);
+ when(mConfig.hasKey(KEY_REGISTRATION_TAGS)).thenReturn(true);
+ when(mConfig.isNull(KEY_REGISTRATION_TAGS)).thenReturn(false);
+ when(mConfig.getArray(KEY_REGISTRATION_TAGS)).thenReturn(mTags);
+ when(mTags.size()).thenReturn(1);
+ when(mTags.getString(0)).thenReturn(tags[0]);
+ when(mGoogleApiAvailability.isGooglePlayServicesAvailable(any())).thenReturn(
+ ConnectionResult.SUCCESS);
+
+ mHubModule.registerTemplate(mConfig, mPromise);
+
+ verify(mNotificationHubUtil, times(1)).setConnectionString(
+ any(ReactContext.class), eq(connectionString));
+ verify(mNotificationHubUtil, times(1)).setHubName(
+ any(ReactContext.class), eq(hubName));
+ verify(mNotificationHubUtil, times(1)).setSenderID(
+ any(ReactContext.class), eq(senderID));
+ verify(mNotificationHubUtil, times(1)).setTemplateName(
+ any(ReactContext.class), eq(templateName));
+ verify(mNotificationHubUtil, times(1)).setTemplate(
+ any(ReactContext.class), eq(template));
+ verify(mNotificationHubUtil, times(1)).setTemplated(
+ any(ReactContext.class), eq(true));
+ verify(mNotificationHubUtil, times(1)).setTags(
+ any(ReactContext.class), eq(tags));
+ verify(mRes, times(1)).putString(eq(KEY_PROMISE_RESOLVE_UUID), any());
+ verify(mPromise, times(1)).resolve(mRes);
+ verify(mPromise, times(0)).reject(anyString(), anyString());
+
+ PowerMockito.verifyStatic(ReactNativeRegistrationIntentService.class);
+ ReactNativeRegistrationIntentService.enqueueWork(eq(mReactApplicationContext), any(Intent.class));
+ }
+
+ @Test
+ public void testRegisterTemplateFailed() {
+ final String[] tags = { "Tag" };
+
+ when(mConfig.getString(KEY_REGISTRATION_CONNECTIONSTRING)).thenReturn("Connection String");
+ when(mConfig.getString(KEY_REGISTRATION_HUBNAME)).thenReturn("Hub Name");
+ when(mConfig.getString(KEY_REGISTRATION_SENDERID)).thenReturn("Sender ID");
+ when(mConfig.getString(KEY_REGISTRATION_TEMPLATENAME)).thenReturn("Template Name");
+ when(mConfig.getString(KEY_REGISTRATION_TEMPLATE)).thenReturn("Template");
+ when(mConfig.hasKey(KEY_REGISTRATION_TAGS)).thenReturn(true);
+ when(mConfig.isNull(KEY_REGISTRATION_TAGS)).thenReturn(false);
+ when(mConfig.getArray(KEY_REGISTRATION_TAGS)).thenReturn(mTags);
+ when(mTags.size()).thenReturn(1);
+ when(mTags.getString(0)).thenReturn(tags[0]);
+ when(mGoogleApiAvailability.isGooglePlayServicesAvailable(any())).thenReturn(
+ ConnectionResult.INTERNAL_ERROR);
+ when(mGoogleApiAvailability.isUserResolvableError(anyInt())).thenReturn(false);
+
+ mHubModule.registerTemplate(mConfig, mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_PLAY_SERVICES,
+ ERROR_PLAY_SERVICES_UNSUPPORTED);
+ }
+
+ @Test
+ public void testUnregisterTemplateSuccessfully() throws Exception {
+ final String templateName = "Template Name";
+
+ when(mNotificationHubUtil.getConnectionString(any(ReactContext.class))).thenReturn("Connection String");
+ when(mNotificationHubUtil.getHubName(any(ReactContext.class))).thenReturn("Hub Name");
+ when(mNotificationHubUtil.getRegistrationID(any(ReactContext.class))).thenReturn("registrationId");
+ when(ReactNativeUtil.createNotificationHub(
+ anyString(), anyString(), any(ReactContext.class))).thenReturn(mNotificationHub);
+
+ mHubModule.unregisterTemplate(templateName, mPromise);
+
+ verify(mNotificationHub, times(1)).unregisterTemplate(templateName);
+ verify(mNotificationHubUtil, times(1)).setRegistrationID(
+ any(ReactContext.class), eq(null));
+ verify(mNotificationHubUtil, times(1)).setUUID(
+ any(ReactContext.class), eq(null));
+ verify(mPromise, times(0)).reject(anyString(), anyString());
+ verify(mPromise, times(1)).resolve(AZURE_NOTIFICATION_HUB_UNREGISTERED);
+ }
+
+ @Test
+ public void testUnregisterTemplateNoRegistration() {
+ when(mNotificationHubUtil.getConnectionString(any(ReactContext.class))).thenReturn("Connection String");
+ when(mNotificationHubUtil.getHubName(any(ReactContext.class))).thenReturn("Hub Name");
+ when(mNotificationHubUtil.getRegistrationID(any(ReactContext.class))).thenReturn(null);
+ when(ReactNativeUtil.createNotificationHub(
+ anyString(), anyString(), any(ReactContext.class))).thenReturn(mNotificationHub);
+
+ mHubModule.unregisterTemplate("Template Name", mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_NOT_REGISTERED,
+ ERROR_NOT_REGISTERED_DESC);
+ }
+
+ @Test
+ public void testUnregisterTemplateThrowException() throws Exception {
+ final String templateName = "Template Name";
+ final Exception unhandledException = new Exception("Unhandled exception");
+
+ when(mNotificationHubUtil.getConnectionString(any(ReactContext.class))).thenReturn("Connection String");
+ when(mNotificationHubUtil.getHubName(any(ReactContext.class))).thenReturn("Hub Name");
+ when(mNotificationHubUtil.getRegistrationID(any(ReactContext.class))).thenReturn("registrationId");
+ when(ReactNativeUtil.createNotificationHub(
+ anyString(), anyString(), any(ReactContext.class))).thenReturn(mNotificationHub);
+ doThrow(unhandledException).when(mNotificationHub).unregisterTemplate(templateName);
+
+ mHubModule.unregisterTemplate(templateName, mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_NOTIFICATION_HUB,
+ unhandledException);
+ }
+
+ @Test
+ public void testGetInitialNotificationNullActivity() {
+ when(mReactApplicationContext.getCurrentActivity()).thenReturn(null);
+
+ mHubModule.getInitialNotification(mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_GET_INIT_NOTIFICATION,
+ ERROR_ACTIVITY_IS_NULL);
+ }
+
+ @Test
+ public void testGetInitialNotificationNullIntent() {
+ Activity activity = PowerMockito.mock(Activity.class);
+ when(mReactApplicationContext.getCurrentActivity()).thenReturn(activity);
+ when(activity.getIntent()).thenReturn(null);
+
+ mHubModule.getInitialNotification(mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_GET_INIT_NOTIFICATION,
+ ERROR_ACTIVITY_INTENT_IS_NULL);
+ }
+
+ @Test
+ public void testGetInitialNotificationNullIntentAction() {
+ Activity activity = PowerMockito.mock(Activity.class);
+ when(mReactApplicationContext.getCurrentActivity()).thenReturn(activity);
+ Intent intent = PowerMockito.mock(Intent.class);
+ when(activity.getIntent()).thenReturn(intent);
+ when(intent.getAction()).thenReturn(null);
+
+ mHubModule.getInitialNotification(mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_GET_INIT_NOTIFICATION,
+ ERROR_ACTIVITY_INTENT_IS_NULL);
+ }
+
+ @Test
+ public void testGetInitialNotificationNullIntentExtras() {
+ Activity activity = PowerMockito.mock(Activity.class);
+ when(mReactApplicationContext.getCurrentActivity()).thenReturn(activity);
+ Intent intent = PowerMockito.mock(Intent.class);
+ when(activity.getIntent()).thenReturn(intent);
+ when(intent.getAction()).thenReturn(PowerMockito.mock(String.class));
+ when(intent.getExtras()).thenReturn(null);
+
+ mHubModule.getInitialNotification(mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_GET_INIT_NOTIFICATION,
+ ERROR_INTENT_EXTRAS_IS_NULL);
+ }
+
+ @Test
+ public void testGetInitialNotification() {
+ Activity activity = PowerMockito.mock(Activity.class);
+ when(mReactApplicationContext.getCurrentActivity()).thenReturn(activity);
+ Intent intent = PowerMockito.mock(Intent.class);
+ when(activity.getIntent()).thenReturn(intent);
+ when(intent.getAction()).thenReturn(PowerMockito.mock(String.class));
+ when(intent.getExtras()).thenReturn(PowerMockito.mock(Bundle.class));
+ WritableMap map = PowerMockito.mock(WritableMap.class);
+ when(ReactNativeUtil.convertBundleToMap(any())).thenReturn(map);
+
+ mHubModule.getInitialNotification(mPromise);
+
+ verify(mPromise, times(1)).resolve(map);
+ }
+
+ @Test
+ public void testGetUUIDNoUUIDNoAutoGen() {
+ when(mNotificationHubUtil.getUUID(mReactApplicationContext)).thenReturn(null);
+
+ mHubModule.getUUID(false, mPromise);
+
+ verify(mPromise, times(1)).reject(
+ ERROR_GET_UUID,
+ ERROR_NO_UUID_SET);
+ }
+
+ @Test
+ public void testGetUUIDNoUUIDAutoGen() {
+ final String uuid = "uuid";
+
+ when(mNotificationHubUtil.getUUID(mReactApplicationContext)).thenReturn(null);
+ when(ReactNativeUtil.genUUID()).thenReturn(uuid);
+
+ mHubModule.getUUID(true, mPromise);
+
+ verify(mNotificationHubUtil, times(1)).setUUID(
+ mReactApplicationContext, uuid);
+ verify(mPromise, times(1)).resolve(uuid);
+ }
+
+ @Test
+ public void testGetUUID() {
+ final String uuid = "uuid";
+
+ when(mNotificationHubUtil.getUUID(mReactApplicationContext)).thenReturn(uuid);
+
+ mHubModule.getUUID(true, mPromise);
+
+ PowerMockito.verifyStatic(ReactNativeUtil.class, times(0));
+ ReactNativeUtil.genUUID();
+ verify(mPromise, times(1)).resolve(uuid);
+ }
+
+ @Test
+ public void testIsNotificationEnabledOnOSLevel() {
+ final boolean areNotificationsEnabled = true;
+
+ NotificationManagerCompat manager = PowerMockito.mock(NotificationManagerCompat.class);
+ when(NotificationManagerCompat.from(mReactApplicationContext)).thenReturn(manager);
+ when(manager.areNotificationsEnabled()).thenReturn(areNotificationsEnabled);
+
+ mHubModule.isNotificationEnabledOnOSLevel(mPromise);
+
+ verify(manager, times(1)).areNotificationsEnabled();
+ verify(mPromise, times(1)).resolve(areNotificationsEnabled);
+ }
+
@Test
public void testOnHostResumeNoNotification() {
Activity activity = PowerMockito.mock(Activity.class);
diff --git a/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubUtilTest.java b/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubUtilTest.java
index 041df647..d807fd7e 100644
--- a/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubUtilTest.java
+++ b/sample/android/app/src/test/java/com/reactnativeazurenotificationhubsample/ReactNativeNotificationHubUtilTest.java
@@ -323,4 +323,80 @@ public void testHasChannelEnableLights() {
verify(mSharedPreferences, times(1)).contains(KEY_FOR_PREFS_CHANNELENABLELIGHTS);
}
+
+ @Test
+ public void testGetTemplateName() {
+ mHubUtil.getTemplateName(mReactApplicationContext);
+
+ verify(mSharedPreferences, times(1)).getString(
+ KEY_FOR_PREFS_TEMPLATENAME, null);
+ }
+
+ @Test
+ public void testSetTemplateName() {
+ final String templateName = "Template Name";
+
+ mHubUtil.setTemplateName(mReactApplicationContext, templateName);
+
+ verify(mEditor, times(1)).putString(
+ KEY_FOR_PREFS_TEMPLATENAME, templateName);
+ verify(mEditor, times(1)).apply();
+ }
+
+ @Test
+ public void testGetTemplate() {
+ mHubUtil.getTemplate(mReactApplicationContext);
+
+ verify(mSharedPreferences, times(1)).getString(
+ KEY_FOR_PREFS_TEMPLATE, null);
+ }
+
+ @Test
+ public void testSetTemplate() {
+ final String template = "Template";
+
+ mHubUtil.setTemplate(mReactApplicationContext, template);
+
+ verify(mEditor, times(1)).putString(
+ KEY_FOR_PREFS_TEMPLATE, template);
+ verify(mEditor, times(1)).apply();
+ }
+
+ @Test
+ public void testIsTemplated() {
+ mHubUtil.isTemplated(mReactApplicationContext);
+
+ verify(mSharedPreferences, times(1)).getBoolean(
+ KEY_FOR_PREFS_ISTEMPLATE, false);
+ }
+
+ @Test
+ public void testSetTemplated() {
+ final boolean isTemplated = true;
+
+ mHubUtil.setTemplated(mReactApplicationContext, isTemplated);
+
+ verify(mEditor, times(1)).putBoolean(
+ KEY_FOR_PREFS_ISTEMPLATE, isTemplated);
+ verify(mEditor, times(1)).apply();
+ }
+
+ @Test
+ public void testGetUUID() {
+ mHubUtil.getUUID(mReactApplicationContext);
+
+ verify(mSharedPreferences, times(1)).getString(
+ KEY_FOR_PREFS_UUID, null);
+ }
+
+ @Test
+ public void testSetUUID() {
+ final String uuid = "uuid";
+
+ mHubUtil.setUUID(mReactApplicationContext, uuid);
+
+ verify(mEditor, times(1)).putString(
+ KEY_FOR_PREFS_UUID, uuid);
+ verify(mEditor, times(1)).apply();
+ }
}
diff --git a/sample/ios/ReactNativeAzureNotificationHubSample.xcodeproj/project.pbxproj b/sample/ios/ReactNativeAzureNotificationHubSample.xcodeproj/project.pbxproj
index dce4d5c0..d620dba3 100644
--- a/sample/ios/ReactNativeAzureNotificationHubSample.xcodeproj/project.pbxproj
+++ b/sample/ios/ReactNativeAzureNotificationHubSample.xcodeproj/project.pbxproj
@@ -55,6 +55,7 @@
2D02E4901E0B4A5D006451C7 /* ReactNativeAzureNotificationHubSample-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ReactNativeAzureNotificationHubSample-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
3AAB39D4BDBE7F53EC74C4C4 /* libPods-ReactNativeAzureNotificationHubSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeAzureNotificationHubSample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B18387DF86E68D789995173 /* Pods-ReactNativeAzureNotificationHubSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeAzureNotificationHubSample.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeAzureNotificationHubSample/Pods-ReactNativeAzureNotificationHubSample.release.xcconfig"; sourceTree = ""; };
+ 45454162242451A2003F4618 /* ReactNativeAzureNotificationHubSample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = ReactNativeAzureNotificationHubSample.entitlements; path = ReactNativeAzureNotificationHubSample/ReactNativeAzureNotificationHubSample.entitlements; sourceTree = ""; };
45E30B45240821F000A339F1 /* RCTAzureNotificationHubManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAzureNotificationHubManagerTests.m; sourceTree = ""; tabWidth = 4; };
45E30B46240821F000A339F1 /* RCTAzureNotificationHubUtilTests.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAzureNotificationHubUtilTests.m; sourceTree = ""; tabWidth = 4; };
45E30B47240821F100A339F1 /* RCTAzureNotificationHandlerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAzureNotificationHandlerTests.m; sourceTree = ""; tabWidth = 4; };
@@ -120,6 +121,7 @@
13B07FAE1A68108700A75B9A /* ReactNativeAzureNotificationHubSample */ = {
isa = PBXGroup;
children = (
+ 45454162242451A2003F4618 /* ReactNativeAzureNotificationHubSample.entitlements */,
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
@@ -589,6 +591,7 @@
baseConfigurationReference = 2351567499705FB80A85A312 /* Pods-ReactNativeAzureNotificationHubSample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_ENTITLEMENTS = ReactNativeAzureNotificationHubSample/ReactNativeAzureNotificationHubSample.entitlements;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
INFOPLIST_FILE = ReactNativeAzureNotificationHubSample/Info.plist;
@@ -609,6 +612,7 @@
baseConfigurationReference = 3B18387DF86E68D789995173 /* Pods-ReactNativeAzureNotificationHubSample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_ENTITLEMENTS = ReactNativeAzureNotificationHubSample/ReactNativeAzureNotificationHubSample.entitlements;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = ReactNativeAzureNotificationHubSample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
diff --git a/sample/ios/ReactNativeAzureNotificationHubSample/AppDelegate.m b/sample/ios/ReactNativeAzureNotificationHubSample/AppDelegate.m
index e6d60560..781aa107 100644
--- a/sample/ios/ReactNativeAzureNotificationHubSample/AppDelegate.m
+++ b/sample/ios/ReactNativeAzureNotificationHubSample/AppDelegate.m
@@ -28,6 +28,10 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
+
+ // Registering for local notifications
+ [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
+
return YES;
}
@@ -40,34 +44,34 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
#endif
}
-// Required to register for notifications
-- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
-{
- [RCTAzureNotificationHubManager didRegisterUserNotificationSettings:notificationSettings];
-}
-
-// Required for the register event.
+// Invoked when the app successfully registered with Apple Push Notification service (APNs).
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RCTAzureNotificationHubManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
-// Required for the registrationError event.
+// Invoked when APNs cannot successfully complete the registration process.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RCTAzureNotificationHubManager didFailToRegisterForRemoteNotificationsWithError:error];
}
-// Required for the notification event.
-- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
+// Invoked when a remote notification arrived and there is data to be fetched.
+- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
+ fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
- [RCTAzureNotificationHubManager didReceiveRemoteNotification:notification];
+ [RCTAzureNotificationHubManager didReceiveRemoteNotification:userInfo
+ fetchCompletionHandler:completionHandler];
}
-// Required for the localNotification event.
-- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
+// Invoked when a notification arrived while the app was running in the foreground.
+- (void)userNotificationCenter:(UNUserNotificationCenter *)center
+ willPresentNotification:(UNNotification *)notification
+ withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
- [RCTAzureNotificationHubManager didReceiveLocalNotification:notification];
+ [RCTAzureNotificationHubManager userNotificationCenter:center
+ willPresentNotification:notification
+ withCompletionHandler:completionHandler];
}
@end
diff --git a/sample/ios/ReactNativeAzureNotificationHubSample/ReactNativeAzureNotificationHubSample.entitlements b/sample/ios/ReactNativeAzureNotificationHubSample/ReactNativeAzureNotificationHubSample.entitlements
new file mode 100644
index 00000000..903def2a
--- /dev/null
+++ b/sample/ios/ReactNativeAzureNotificationHubSample/ReactNativeAzureNotificationHubSample.entitlements
@@ -0,0 +1,8 @@
+
+
+
+
+ aps-environment
+ development
+
+
diff --git a/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHandlerTests.m b/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHandlerTests.m
index a3273415..a5482799 100644
--- a/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHandlerTests.m
+++ b/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHandlerTests.m
@@ -93,31 +93,39 @@ - (void)testRemoteNotificationRegisteredError
body:expectedErrorDetails]);
}
-- (void)testUserNotificationSettingsRegistered
+- (void)testAzureNotificationHubRegistered
{
- __block NSDictionary *notificationTypes = nil;
- RCTPromiseResolveBlock resolver = ^(NSDictionary *callbackNotificationTypes)
- {
- notificationTypes = callbackNotificationTypes;
- };
+ NSNotification* notification = [NSNotification notificationWithName:@"Notification" object:_userInfo userInfo:_userInfo];
+
+ [_notificationHandler azureNotificationHubRegistered:notification];
- UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge;
- UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(NSUInteger)types
- categories:nil];
+ OCMVerify([_eventEmitter sendEventWithName:RCTAzureNotificationHubRegistered
+ body:_userInfo]);
+}
+
+- (void)testAzureNotificationHubRegisteredError
+{
+ NSDictionary *errorUserInfo = [[NSDictionary alloc]
+ initWithObjectsAndKeys:NSLocalizedDescriptionKey, NSLocalizedDescriptionKey, nil];
+
+ NSError* error = [NSError errorWithDomain:@"Error domain"
+ code:100
+ userInfo:errorUserInfo];
- NSArray *keys = [NSArray arrayWithObjects:RCTUserInfoNotificationSettings, RCTUserInfoResolveBlock, nil];
- NSArray *objects = [NSArray arrayWithObjects:settings, resolver, nil];
+ NSArray *keys = [NSArray arrayWithObjects:RCTUserInfoError, nil];
+ NSArray *objects = [NSArray arrayWithObjects:error, nil];
NSDictionary *userInfo = [[NSMutableDictionary alloc] initWithObjects:objects forKeys:keys];
NSNotification* notification = [NSNotification notificationWithName:@"Notification" object:userInfo userInfo:userInfo];
- NSDictionary *expectedNotificationTypes = @{
- RCTNotificationTypeAlert: @YES,
- RCTNotificationTypeSound: @NO,
- RCTNotificationTypeBadge: @YES
+ NSDictionary *expectedErrorDetails = @{
+ @"message": NSLocalizedDescriptionKey,
+ @"code": [NSNumber numberWithInt:100],
+ @"details": errorUserInfo
};
-
- [_notificationHandler userNotificationSettingsRegistered:notification];
- XCTAssertEqualObjects(notificationTypes, expectedNotificationTypes);
+ [_notificationHandler azureNotificationHubRegisteredError:notification];
+
+ OCMVerify([_eventEmitter sendEventWithName:RCTAzureNotificationHubRegisteredError
+ body:expectedErrorDetails]);
}
@end
diff --git a/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubManagerTests.m b/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubManagerTests.m
index 429afe78..d3f54fb0 100644
--- a/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubManagerTests.m
+++ b/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubManagerTests.m
@@ -22,6 +22,10 @@ @interface RCTAzureNotificationHubManagerTests : XCTestCase
static NSString *const RCTTestDeviceToken = @"Device Token";
static NSString *const RCTTestConnectionString = @"Connection String";
static NSString *const RCTTestHubName = @"Hub Name";
+static NSString *const RCTTestTemplate = @"Template";
+static NSString *const RCTTestTemplateName = @"Template Name";
+
+id sharedApplicationMock;
@implementation RCTAzureNotificationHubManagerTests
{
@@ -31,38 +35,55 @@ @implementation RCTAzureNotificationHubManagerTests
RCTPromiseResolveBlock _resolver;
RCTPromiseRejectBlock _rejecter;
NSSet *_tags;
- UILocalNotification *_notification;
+ UILocalNotification *_localNotification;
+ id _notificationMock;
id _hubMock;
id _hubUtilMock;
+ id _notificationHandlerMock;
+}
+
++ (void)setUp
+{
+ sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
}
- (void)setUp
{
[super setUp];
-
+
_hubManager = [[RCTAzureNotificationHubManager alloc] init];
_config = [[NSMutableDictionary alloc] init];
_resolver = ^(id result) {};
_rejecter = ^(NSString *code, NSString *message, NSError *error) {};
_tags = [[NSSet alloc] initWithArray:@[ @"Tag" ]];
- _notification = [[UILocalNotification alloc] init];
+ _localNotification = [[UILocalNotification alloc] init];
NSArray *keys = [NSArray arrayWithObjects:@"Title", @"Message", nil];
NSArray *objects = [NSArray arrayWithObjects:@"Title", @"Message", nil];
NSDictionary *info = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
- [_notification setUserInfo:info];
+ [_localNotification setUserInfo:info];
+
+ _notificationMock = OCMClassMock([UNNotification class]);
+ UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
+ id notificationRequestMock = OCMClassMock([UNNotificationRequest class]);
+ OCMStub([notificationRequestMock content]).andReturn(content);
+ OCMStub([notificationRequestMock identifier]).andReturn( @"identifier");
+ OCMStub([_notificationMock request]).andReturn(notificationRequestMock);
+ content.userInfo = info;
_hubMock = OCMClassMock([SBNotificationHub class]);
_hubUtilMock = OCMClassMock([RCTAzureNotificationHubUtil class]);
OCMStub([_hubUtilMock createAzureNotificationHub:OCMOCK_ANY
hubName:OCMOCK_ANY]).andReturn(_hubMock);
-
+ _notificationHandlerMock = OCMClassMock([RCTAzureNotificationHandler class]);
+ [_hubManager setNotificationHandler:_notificationHandlerMock];
+
void (^runOnMainThread)(NSInvocation *) = ^(NSInvocation *invocation)
{
__unsafe_unretained dispatch_block_t block = nil;
[invocation getArgument:&block atIndex:2]; // First argument starts at 2
- [block invoke];
+ block();
};
-
+
OCMStub([_hubUtilMock runOnMainThread:OCMOCK_ANY]).andDo(runOnMainThread);
}
@@ -73,12 +94,12 @@ - (void)testRegisterNoConnectionString
{
errorMsg = message;
};
-
+
[_hubManager register:RCTTestDeviceToken
config:_config
resolver:_resolver
rejecter:_rejecter];
-
+
XCTAssertEqualObjects(errorMsg, RCTErrorMissingConnectionString);
}
@@ -89,13 +110,13 @@ - (void)testRegisterNoHubName
{
errorMsg = message;
};
-
+
[_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
[_hubManager register:RCTTestDeviceToken
config:_config
resolver:_resolver
rejecter:_rejecter];
-
+
XCTAssertEqualObjects(errorMsg, RCTErrorMissingHubName);
}
@@ -104,7 +125,7 @@ - (void)testRegisterNativeError
[_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
[_config setObject:RCTTestHubName forKey:RCTHubNameKey];
[_config setObject:_tags forKey:RCTTagsKey];
-
+
NSError *error = [NSError errorWithDomain:@"Mock Error" code:0 userInfo:nil];
void (^registerNativeWithDeviceToken)(NSInvocation *) = ^(NSInvocation *invocation)
{
@@ -112,25 +133,27 @@ - (void)testRegisterNativeError
[invocation getArgument:&completion atIndex:4]; // First argument starts at 2
completion(error);
};
-
+
OCMStub([_hubMock registerNativeWithDeviceToken:OCMOCK_ANY
tags:OCMOCK_ANY
completion:OCMOCK_ANY]).andDo(registerNativeWithDeviceToken);
-
+
id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
[_hubManager register:RCTTestDeviceToken
config:_config
resolver:_resolver
rejecter:_rejecter];
-
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
+
OCMVerify([_hubUtilMock createAzureNotificationHub:RCTTestConnectionString
hubName:RCTTestHubName]);
-
+
OCMVerify([_hubMock registerNativeWithDeviceToken:RCTTestDeviceToken
tags:_tags
completion:OCMOCK_ANY]);
-
+
OCMVerify([defaultCenterMock postNotificationName:RCTAzureNotificationHubRegisteredError
object:OCMOCK_ANY
userInfo:@{RCTUserInfoError: error}]);
@@ -141,32 +164,197 @@ - (void)testRegisterNativeSuccessfully
[_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
[_config setObject:RCTTestHubName forKey:RCTHubNameKey];
[_config setObject:_tags forKey:RCTTagsKey];
-
+
void (^registerNativeWithDeviceToken)(NSInvocation *) = ^(NSInvocation *invocation)
{
__unsafe_unretained RCTNativeCompletion completion = nil;
[invocation getArgument:&completion atIndex:4]; // First argument starts at 2
completion(nil);
};
-
+
OCMStub([_hubMock registerNativeWithDeviceToken:OCMOCK_ANY
tags:OCMOCK_ANY
completion:OCMOCK_ANY]).andDo(registerNativeWithDeviceToken);
-
+
id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
[_hubManager register:RCTTestDeviceToken
config:_config
resolver:_resolver
rejecter:_rejecter];
-
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
+
OCMVerify([_hubUtilMock createAzureNotificationHub:RCTTestConnectionString
hubName:RCTTestHubName]);
-
+
OCMVerify([_hubMock registerNativeWithDeviceToken:RCTTestDeviceToken
tags:_tags
completion:OCMOCK_ANY]);
-
+
+ OCMVerify([defaultCenterMock postNotificationName:RCTAzureNotificationHubRegistered
+ object:OCMOCK_ANY
+ userInfo:@{RCTUserInfoSuccess: @YES}]);
+}
+
+- (void)testRegisterTemplateNoConnectionString
+{
+ __block NSString *errorMsg;
+ _rejecter = ^(NSString *code, NSString *message, NSError *error)
+ {
+ errorMsg = message;
+ };
+
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ XCTAssertEqualObjects(errorMsg, RCTErrorMissingConnectionString);
+}
+
+- (void)testRegisterTemplateNoHubName
+{
+ __block NSString *errorMsg;
+ _rejecter = ^(NSString *code, NSString *message, NSError *error)
+ {
+ errorMsg = message;
+ };
+
+ [_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ XCTAssertEqualObjects(errorMsg, RCTErrorMissingHubName);
+}
+
+- (void)testRegisterTemplateNoTemplateName
+{
+ __block NSString *errorMsg;
+ _rejecter = ^(NSString *code, NSString *message, NSError *error)
+ {
+ errorMsg = message;
+ };
+
+ [_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
+ [_config setObject:RCTTestHubName forKey:RCTHubNameKey];
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ XCTAssertEqualObjects(errorMsg, RCTErrorMissingTemplateName);
+}
+
+- (void)testRegisterTemplateNoTemplate
+{
+ __block NSString *errorMsg;
+ _rejecter = ^(NSString *code, NSString *message, NSError *error)
+ {
+ errorMsg = message;
+ };
+
+ [_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
+ [_config setObject:RCTTestHubName forKey:RCTHubNameKey];
+ [_config setObject:RCTTestTemplateName forKey:RCTTemplateNameKey];
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ XCTAssertEqualObjects(errorMsg, RCTErrorMissingTemplate);
+}
+
+- (void)testRegisterTemplateNativeError
+{
+ [_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
+ [_config setObject:RCTTestHubName forKey:RCTHubNameKey];
+ [_config setObject:_tags forKey:RCTTagsKey];
+ [_config setObject:RCTTestTemplateName forKey:RCTTemplateNameKey];
+ [_config setObject:RCTTestTemplate forKey:RCTTemplateKey];
+
+ NSError *error = [NSError errorWithDomain:@"Mock Error" code:0 userInfo:nil];
+ void (^registerTemplateNativeWithDeviceToken)(NSInvocation *) = ^(NSInvocation *invocation)
+ {
+ __unsafe_unretained RCTNativeCompletion completion = nil;
+ [invocation getArgument:&completion atIndex:7]; // First argument starts at 2
+ completion(error);
+ };
+
+ OCMStub([_hubMock registerTemplateWithDeviceToken:RCTTestDeviceToken
+ name:RCTTestTemplateName
+ jsonBodyTemplate:RCTTestTemplate
+ expiryTemplate:nil
+ tags:_tags
+ completion:OCMOCK_ANY]).andDo(registerTemplateNativeWithDeviceToken);
+
+ id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
+
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
+
+ OCMVerify([_hubUtilMock createAzureNotificationHub:RCTTestConnectionString
+ hubName:RCTTestHubName]);
+
+ OCMVerify([_hubMock registerTemplateWithDeviceToken:RCTTestDeviceToken
+ name:RCTTestTemplateName
+ jsonBodyTemplate:RCTTestTemplate
+ expiryTemplate:nil
+ tags:_tags
+ completion:OCMOCK_ANY]);
+
+ OCMVerify([defaultCenterMock postNotificationName:RCTAzureNotificationHubRegisteredError
+ object:OCMOCK_ANY
+ userInfo:@{RCTUserInfoError: error}]);
+}
+
+- (void)testRegisterTemplateNativeSuccessfully
+{
+ [_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
+ [_config setObject:RCTTestHubName forKey:RCTHubNameKey];
+ [_config setObject:_tags forKey:RCTTagsKey];
+ [_config setObject:RCTTestTemplateName forKey:RCTTemplateNameKey];
+ [_config setObject:RCTTestTemplate forKey:RCTTemplateKey];
+
+ void (^registerTemplateNativeWithDeviceToken)(NSInvocation *) = ^(NSInvocation *invocation)
+ {
+ __unsafe_unretained RCTNativeCompletion completion = nil;
+ [invocation getArgument:&completion atIndex:7]; // First argument starts at 2
+ completion(nil);
+ };
+
+ OCMStub([_hubMock registerTemplateWithDeviceToken:RCTTestDeviceToken
+ name:RCTTestTemplateName
+ jsonBodyTemplate:RCTTestTemplate
+ expiryTemplate:nil
+ tags:_tags
+ completion:OCMOCK_ANY]).andDo(registerTemplateNativeWithDeviceToken);
+
+ id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
+
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
+
+ OCMVerify([_hubUtilMock createAzureNotificationHub:RCTTestConnectionString
+ hubName:RCTTestHubName]);
+
+ OCMVerify([_hubMock registerTemplateWithDeviceToken:RCTTestDeviceToken
+ name:RCTTestTemplateName
+ jsonBodyTemplate:RCTTestTemplate
+ expiryTemplate:nil
+ tags:_tags
+ completion:OCMOCK_ANY]);
+
OCMVerify([defaultCenterMock postNotificationName:RCTAzureNotificationHubRegistered
object:OCMOCK_ANY
userInfo:@{RCTUserInfoSuccess: @YES}]);
@@ -179,10 +367,10 @@ - (void)testUnregisterNoRegistration
{
errorMsg = message;
};
-
+
[_hubManager unregister:_resolver rejecter:_rejecter];
-
- XCTAssertEqualObjects(errorMsg, RCTErrorMissingConnectionString);
+
+ XCTAssertEqualObjects(errorMsg, RCTErrorUnableToUnregisterNoRegistration);
}
- (void)testUnregisterNativeError
@@ -190,7 +378,7 @@ - (void)testUnregisterNativeError
[_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
[_config setObject:RCTTestHubName forKey:RCTHubNameKey];
[_config setObject:_tags forKey:RCTTagsKey];
-
+
NSError *error = [NSError errorWithDomain:@"Mock Error" code:0 userInfo:nil];
void (^unregisterNativeWithCompletion)(NSInvocation *) = ^(NSInvocation *invocation)
{
@@ -198,17 +386,18 @@ - (void)testUnregisterNativeError
[invocation getArgument:&completion atIndex:2]; // First argument starts at 2
completion(error);
};
-
+
OCMStub([_hubMock unregisterNativeWithCompletion:OCMOCK_ANY]).andDo(unregisterNativeWithCompletion);
id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
-
+
[_hubManager register:RCTTestDeviceToken
config:_config
resolver:_resolver
rejecter:_rejecter];
-
+
[_hubManager unregister:_resolver rejecter:_rejecter];
-
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
OCMVerify([_hubMock unregisterNativeWithCompletion:OCMOCK_ANY]);
OCMVerify([defaultCenterMock postNotificationName:RCTErrorUnspecified
object:OCMOCK_ANY
@@ -220,14 +409,14 @@ - (void)testUnregisterNativeSuccessfully
[_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
[_config setObject:RCTTestHubName forKey:RCTHubNameKey];
[_config setObject:_tags forKey:RCTTagsKey];
-
+
void (^unregisterNativeWithCompletion)(NSInvocation *) = ^(NSInvocation *invocation)
{
__unsafe_unretained RCTNativeCompletion completion = nil;
[invocation getArgument:&completion atIndex:2]; // First argument starts at 2
completion(nil);
};
-
+
OCMStub([_hubMock unregisterNativeWithCompletion:OCMOCK_ANY]).andDo(unregisterNativeWithCompletion);
id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
OCMReject([defaultCenterMock postNotificationName:OCMOCK_ANY object:OCMOCK_ANY userInfo:OCMOCK_ANY]);
@@ -236,19 +425,116 @@ - (void)testUnregisterNativeSuccessfully
config:_config
resolver:_resolver
rejecter:_rejecter];
-
+
[_hubManager unregister:_resolver rejecter:_rejecter];
-
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
OCMVerify([_hubMock unregisterNativeWithCompletion:OCMOCK_ANY]);
+ OCMReject([defaultCenterMock postNotificationName:RCTErrorUnspecified
+ object:OCMOCK_ANY
+ userInfo:OCMOCK_ANY]);
+}
+
+- (void)testUnregisterTemplateNoRegistration
+{
+ __block NSString *errorMsg;
+ _rejecter = ^(NSString *code, NSString *message, NSError *error)
+ {
+ errorMsg = message;
+ };
+
+ [_hubManager unregisterTemplate:RCTTestTemplateName
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ XCTAssertEqualObjects(errorMsg, RCTErrorUnableToUnregisterNoRegistration);
+}
+
+- (void)testUnregisterTemplateNativeError
+{
+ [_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
+ [_config setObject:RCTTestHubName forKey:RCTHubNameKey];
+ [_config setObject:_tags forKey:RCTTagsKey];
+ [_config setObject:RCTTestTemplateName forKey:RCTTemplateNameKey];
+ [_config setObject:RCTTestTemplate forKey:RCTTemplateKey];
+
+ NSError *error = [NSError errorWithDomain:@"Mock Error" code:0 userInfo:nil];
+ void (^unregisterTemplateNativeWithCompletion)(NSInvocation *) = ^(NSInvocation *invocation)
+ {
+ __unsafe_unretained RCTNativeCompletion completion = nil;
+ [invocation getArgument:&completion atIndex:3]; // First argument starts at 2
+ completion(error);
+ };
+
+ OCMStub([_hubMock unregisterTemplateWithName:RCTTestTemplateName
+ completion:OCMOCK_ANY]).andDo(unregisterTemplateNativeWithCompletion);
+
+ id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
+
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ [_hubManager unregisterTemplate:RCTTestTemplateName
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
+
+ OCMVerify([_hubMock unregisterTemplateWithName:RCTTestTemplateName
+ completion:OCMOCK_ANY]);
+
+ OCMVerify([defaultCenterMock postNotificationName:RCTErrorUnspecified
+ object:OCMOCK_ANY
+ userInfo:@{RCTUserInfoError: error}]);
+}
+
+- (void)testUnregisterTemplateNativeSuccessfully
+{
+ [_config setObject:RCTTestConnectionString forKey:RCTConnectionStringKey];
+ [_config setObject:RCTTestHubName forKey:RCTHubNameKey];
+ [_config setObject:_tags forKey:RCTTagsKey];
+ [_config setObject:RCTTestTemplateName forKey:RCTTemplateNameKey];
+ [_config setObject:RCTTestTemplate forKey:RCTTemplateKey];
+
+ void (^unregisterTemplateNativeWithCompletion)(NSInvocation *) = ^(NSInvocation *invocation)
+ {
+ __unsafe_unretained RCTNativeCompletion completion = nil;
+ [invocation getArgument:&completion atIndex:3]; // First argument starts at 2
+ completion(nil);
+ };
+
+ OCMStub([_hubMock unregisterTemplateWithName:RCTTestTemplateName
+ completion:OCMOCK_ANY]).andDo(unregisterTemplateNativeWithCompletion);
+
+ id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
+
+ [_hubManager registerTemplate:RCTTestDeviceToken
+ config:_config
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ [_hubManager unregisterTemplate:RCTTestTemplateName
+ resolver:_resolver
+ rejecter:_rejecter];
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
+
+ OCMVerify([_hubMock unregisterTemplateWithName:RCTTestTemplateName
+ completion:OCMOCK_ANY]);
+
+ OCMReject([defaultCenterMock postNotificationName:RCTErrorUnspecified
+ object:OCMOCK_ANY
+ userInfo:OCMOCK_ANY]);
}
- (void)testSetApplicationIconBadgeNumber
{
NSInteger badgeNumber = 1;
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
-
+
[_hubManager setApplicationIconBadgeNumber:badgeNumber];
-
+
OCMVerify([sharedApplicationMock setApplicationIconBadgeNumber:badgeNumber]);
}
@@ -259,45 +545,43 @@ - (void)testGetApplicationIconBadgeNumber
{
XCTAssertEqual([response[0] longValue], badgeNumber);
};
-
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
+
OCMStub([sharedApplicationMock applicationIconBadgeNumber]).andReturn(badgeNumber);
-
+
[_hubManager setApplicationIconBadgeNumber:badgeNumber];
[_hubManager getApplicationIconBadgeNumber:block];
}
- (void)testRequestPermissions
{
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
NSArray *keys = [NSArray arrayWithObjects:RCTNotificationTypeAlert, RCTNotificationTypeBadge, RCTNotificationTypeSound, nil];
NSArray *objects = [NSArray arrayWithObjects:@YES, @YES, @YES, nil];
NSDictionary *permissions = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
- UIUserNotificationType types = [RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions];
- UIUserNotificationSettings *expectedSettings = [UIUserNotificationSettings settingsForTypes:(NSUInteger)types
- categories:nil];
-
- [_hubManager requestPermissions:permissions resolver:_resolver rejecter:_rejecter];
-
- OCMVerify([sharedApplicationMock registerUserNotificationSettings:expectedSettings]);
-}
+ UNAuthorizationOptions expectedOptions = [RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions];
+ id center = OCMPartialMock([UNUserNotificationCenter currentNotificationCenter]);
+ void (^requestAuthorizationCompletionHandler)(NSInvocation *) = ^(NSInvocation *invocation)
+ {
+ __unsafe_unretained RCTNotificationCompletion completion = nil;
+ [invocation getArgument:&completion atIndex:3]; // First argument starts at 2
+ completion(true, nil);
+ };
+
+ OCMStub([center requestAuthorizationWithOptions:expectedOptions
+ completionHandler:OCMOCK_ANY]).andDo(requestAuthorizationCompletionHandler);
-- (void)testRequestPermissionsTwice
-{
- NSDictionary *permissions = [[NSDictionary alloc] init];
- [_hubManager requestPermissions:permissions resolver:_resolver rejecter:_rejecter];
-
- OCMReject([_hubUtilMock getNotificationTypesWithPermissions:permissions]);
-
[_hubManager requestPermissions:permissions resolver:_resolver rejecter:_rejecter];
+
+ OCMVerify([center requestAuthorizationWithOptions:expectedOptions
+ completionHandler:OCMOCK_ANY]);
+
+ OCMVerify([_hubUtilMock runOnMainThread:OCMOCK_ANY]);
+ OCMVerify([sharedApplicationMock registerForRemoteNotifications]);
}
- (void)testAbandonPermissions
{
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
-
[_hubManager abandonPermissions];
-
+
OCMVerify([sharedApplicationMock unregisterForRemoteNotifications]);
}
@@ -306,75 +590,80 @@ - (void)testCheckPermissions
NSArray *keys = [NSArray arrayWithObjects:RCTNotificationTypeAlert, RCTNotificationTypeBadge, RCTNotificationTypeSound, nil];
NSArray *objects = [NSArray arrayWithObjects:@YES, @NO, @YES, nil];
NSDictionary *permissions = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
- UIUserNotificationType types = [RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions];
- id settingsMock = OCMClassMock([UIUserNotificationSettings class]);
- OCMStub([settingsMock types]).andReturn(types);
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
- OCMStub([sharedApplicationMock currentUserNotificationSettings]).andReturn(settingsMock);
-
+ id center = OCMPartialMock([UNUserNotificationCenter currentNotificationCenter]);
+ UNNotificationSettings *settings = [UNNotificationSettings alloc];
+ [settings setValue:@(UNNotificationSettingEnabled) forKey:@"notificationCenterSetting"];
+ [settings setValue:@(UNNotificationSettingDisabled) forKey:@"badgeSetting"];
+ [settings setValue:@(UNNotificationSettingEnabled) forKey:@"soundSetting"];
+ void (^getNotificationSettingsWithCompletionHandler)(NSInvocation *) = ^(NSInvocation *invocation)
+ {
+ __unsafe_unretained RCTNotificationSettingsCompletion completion = nil;
+ [invocation getArgument:&completion atIndex:2]; // First argument starts at 2
+ completion(settings);
+ };
+
+ OCMStub([center getNotificationSettingsWithCompletionHandler:OCMOCK_ANY]).andDo(getNotificationSettingsWithCompletionHandler);
+
NSArray *expectedResponse = @[@{
RCTNotificationTypeAlert: @YES,
RCTNotificationTypeBadge: @NO,
RCTNotificationTypeSound: @YES,
}];
-
+
RCTResponseSenderBlock callback = ^(NSArray *response)
{
XCTAssertEqualObjects(response, expectedResponse);
};
-
+
[_hubManager checkPermissions:callback];
}
- (void)testPresentLocalNotification
{
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
id notificationMock = OCMClassMock([UILocalNotification class]);
-
+
[_hubManager presentLocalNotification:notificationMock];
-
+
OCMVerify([sharedApplicationMock presentLocalNotificationNow:notificationMock]);
}
- (void)testScheduleLocalNotification
{
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
id notificationMock = OCMClassMock([UILocalNotification class]);
-
+
[_hubManager scheduleLocalNotification:notificationMock];
-
+
OCMVerify([sharedApplicationMock scheduleLocalNotification:notificationMock]);
}
- (void)testCancelAllLocalNotifications
{
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
-
[_hubManager cancelAllLocalNotifications];
-
+
OCMVerify([sharedApplicationMock cancelAllLocalNotifications]);
}
- (void)testCancelLocalNotificationsMatched
{
NSMutableArray *notifications = [[NSMutableArray alloc] init];
- [notifications addObject:_notification];
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
+ [notifications addObject:_localNotification];
OCMStub([sharedApplicationMock scheduledLocalNotifications]).andReturn(notifications);
-
- [_hubManager cancelLocalNotifications:[_notification userInfo]];
-
- OCMVerify([sharedApplicationMock cancelLocalNotification:_notification]);
+ UNNotificationRequest *request = [_notificationMock request];
+ UNMutableNotificationContent *content = [request content];
+ NSDictionary *userInfo = content.userInfo;
+
+ [_hubManager cancelLocalNotifications:userInfo];
+
+ OCMVerify([sharedApplicationMock cancelLocalNotification:_localNotification]);
}
- (void)testCancelLocalNotificationsNotMatched
{
NSMutableArray *notifications = [[NSMutableArray alloc] init];
- [notifications addObject:_notification];
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
+ [notifications addObject:_localNotification];
OCMStub([sharedApplicationMock scheduledLocalNotifications]).andReturn(notifications);
OCMReject([sharedApplicationMock cancelLocalNotification:OCMOCK_ANY]);
-
+
NSArray *keys = [NSArray arrayWithObjects:@"Different Title", @"Different Message", nil];
NSArray *objects = [NSArray arrayWithObjects:@"Title", @"Message", nil];
NSDictionary *info = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
@@ -389,10 +678,10 @@ - (void)testGetInitialNotificationRemoteNotification
NSArray *launchOptionsObjects = [NSArray arrayWithObjects:[[NSMutableDictionary alloc]
initWithObjects:@[ remoteNotificationObject ]
forKeys:@[ remoteNotificationKey ]], nil];
-
+
NSDictionary *launchOptionsMock = [[NSDictionary alloc] initWithObjects:launchOptionsObjects
forKeys:launchOptionsKeys];
-
+
id bridgeMock = OCMClassMock([RCTBridge class]);
OCMStub([bridgeMock launchOptions]).andReturn(launchOptionsMock);
_hubManager.bridge = bridgeMock;
@@ -403,9 +692,9 @@ - (void)testGetInitialNotificationRemoteNotification
userInfoRemote = initialNotification[RCTUserInfoRemote];
notification = initialNotification[remoteNotificationKey];
};
-
+
[_hubManager getInitialNotification:_resolver reject:_rejecter];
-
+
XCTAssertEqual(userInfoRemote, true);
XCTAssertEqualObjects(notification, remoteNotificationObject);
}
@@ -413,10 +702,10 @@ - (void)testGetInitialNotificationRemoteNotification
- (void)testGetInitialNotificationLocalNotification
{
NSArray *launchOptionsKeys = [NSArray arrayWithObjects:UIApplicationLaunchOptionsLocalNotificationKey, nil];
- NSArray *launchOptionsObjects = [NSArray arrayWithObjects: _notification, nil];
+ NSArray *launchOptionsObjects = [NSArray arrayWithObjects: _localNotification, nil];
NSDictionary *launchOptionsMock = [[NSDictionary alloc] initWithObjects:launchOptionsObjects
forKeys:launchOptionsKeys];
-
+
id bridgeMock = OCMClassMock([RCTBridge class]);
OCMStub([bridgeMock launchOptions]).andReturn(launchOptionsMock);
_hubManager.bridge = bridgeMock;
@@ -425,10 +714,10 @@ - (void)testGetInitialNotificationLocalNotification
{
notification = initialLocalNotification;
};
-
+
[_hubManager getInitialNotification:_resolver reject:_rejecter];
-
- XCTAssertEqualObjects(notification, [RCTAzureNotificationHubUtil formatLocalNotification:_notification]);
+
+ XCTAssertEqualObjects(notification, [RCTAzureNotificationHubUtil formatLocalNotification:_localNotification]);
}
- (void)testGetInitialNotificationNoNotification
@@ -441,27 +730,26 @@ - (void)testGetInitialNotificationNoNotification
{
notification = result;
};
-
+
[_hubManager getInitialNotification:_resolver reject:_rejecter];
-
+
XCTAssertEqualObjects(notification, (id)kCFNull);
}
- (void)testGetScheduledLocalNotifications
{
NSMutableArray *notifications = [[NSMutableArray alloc] init];
- [notifications addObject:_notification];
- id sharedApplicationMock = OCMPartialMock([UIApplication sharedApplication]);
+ [notifications addObject:_localNotification];
OCMStub([sharedApplicationMock scheduledLocalNotifications]).andReturn(notifications);
__block NSMutableArray *scheduledNotifications = nil;
RCTResponseSenderBlock callback = ^(NSArray *result)
{
scheduledNotifications = result;
};
-
+
[_hubManager getScheduledLocalNotifications:callback];
- XCTAssertEqualObjects(scheduledNotifications[0][0], [RCTAzureNotificationHubUtil formatLocalNotification:_notification]);
+ XCTAssertEqualObjects(scheduledNotifications[0][0], [RCTAzureNotificationHubUtil formatLocalNotification:_localNotification]);
}
- (void)testStartObserving
@@ -499,11 +787,6 @@ - (void)testStartObserving
selector:[OCMArg anySelector]
name:RCTAzureNotificationHubRegisteredError
object:nil]);
-
- OCMVerify([defaultCenterMock addObserver:OCMOCK_ANY
- selector:[OCMArg anySelector]
- name:RCTUserNotificationSettingsRegistered
- object:nil]);
}
- (void)testStopObserving
@@ -557,27 +840,29 @@ - (void)testDidFailToRegisterForRemoteNotificationsWithError
- (void)testDidReceiveRemoteNotification
{
id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
- NSDictionary *notification = [[NSDictionary alloc] initWithObjectsAndKeys:@"key", @"value", nil];
+ NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:@"key", @"value", nil];
- [RCTAzureNotificationHubManager didReceiveRemoteNotification:notification];
+ [RCTAzureNotificationHubManager didReceiveRemoteNotification:userInfo
+ fetchCompletionHandler:nil];
OCMVerify([defaultCenterMock postNotificationName:RCTRemoteNotificationReceived
object:OCMOCK_ANY
- userInfo:notification]);
+ userInfo:userInfo]);
}
-- (void)testDidReceiveLocalNotification
+- (void)testUserNotificationCenter
{
id defaultCenterMock = OCMPartialMock([NSNotificationCenter defaultCenter]);
- UILocalNotification *notification = [[UILocalNotification alloc] init];
- NSDictionary *info = [[NSDictionary alloc] initWithObjectsAndKeys:@"Key", @"Value", nil];
- [notification setUserInfo:info];
+ id notificationMock = OCMClassMock([UNNotification class]);
- [RCTAzureNotificationHubManager didReceiveLocalNotification:notification];
+ [RCTAzureNotificationHubManager userNotificationCenter:nil
+ willPresentNotification:notificationMock
+ withCompletionHandler:nil];
+ OCMVerify([RCTAzureNotificationHubUtil formatUNNotification:notificationMock]);
OCMVerify([defaultCenterMock postNotificationName:RCTLocalNotificationReceived
object:OCMOCK_ANY
- userInfo:[RCTAzureNotificationHubUtil formatLocalNotification:notification]]);
+ userInfo:OCMOCK_ANY]);
}
@end
diff --git a/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubUtilTests.m b/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubUtilTests.m
index bc2fdd59..8ab23a84 100644
--- a/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubUtilTests.m
+++ b/sample/ios/ReactNativeAzureNotificationHubSampleTests/RCTAzureNotificationHubUtilTests.m
@@ -11,11 +11,49 @@
#import
#import
+@import OCMock;
+@import UserNotifications;
+
@interface RCTAzureNotificationHubUtilTests : XCTestCase
@end
@implementation RCTAzureNotificationHubUtilTests
+- (void)testFormatUNNotification
+{
+ UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
+ id notificationRequestMock = OCMClassMock([UNNotificationRequest class]);
+ OCMStub([notificationRequestMock content]).andReturn(content);
+ OCMStub([notificationRequestMock identifier]).andReturn( @"identifier");
+ id notificationMock = OCMClassMock([UNNotification class]);
+ OCMStub([notificationMock request]).andReturn(notificationRequestMock);
+
+ NSArray *keys = [NSArray arrayWithObjects:@"userInfoKey", nil];
+ NSArray *objects = [NSArray arrayWithObjects:@"userInfoObject", nil];
+ NSDictionary *info = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
+ content.title = @"title";
+ content.threadIdentifier = @"threadIdentifier";
+ content.body = @"body";
+ content.badge = @(1);
+ content.categoryIdentifier = @"category";
+ content.sound = @"sound";
+ content.userInfo = info;
+ NSDictionary *expectedNotification = @{
+ @"identifier": @"identifier",
+ @"title": @"title",
+ @"thread-id": @"threadIdentifier",
+ @"userInfo": @{ @"userInfoKey": @"userInfoObject" },
+ @"alertBody": @"body",
+ @"applicationIconBadgeNumber": [NSNumber numberWithInt:1],
+ @"category": @"category",
+ @"soundName": @"sound"
+ };
+
+ NSDictionary *formattedNotification = [RCTAzureNotificationHubUtil formatUNNotification:notificationMock];
+
+ XCTAssertEqualObjects(formattedNotification, expectedNotification);
+}
+
- (void)testFormatLocalNotification
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
@@ -37,9 +75,9 @@ - (void)testFormatLocalNotification
@"soundName": @"soundName",
@"remote": @NO
};
-
+
NSDictionary *formattedNotification = [RCTAzureNotificationHubUtil formatLocalNotification:notification];
-
+
XCTAssertEqualObjects(formattedNotification, expectedNotification);
}
@@ -57,20 +95,19 @@ - (void)testConvertDeviceTokenToString
- (void)testGetNotificationTypesWithPermissions
{
NSMutableDictionary *permissions = [[NSMutableDictionary alloc] init];
- XCTAssertEqual([RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions],
- UIUserNotificationTypeNone);
+ XCTAssertEqual([RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions], 0);
[permissions setValue:@YES forKey:RCTNotificationTypeAlert];
XCTAssertEqual([RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions],
- UIUserNotificationTypeAlert);
+ UNAuthorizationOptionAlert);
[permissions setValue:@YES forKey:RCTNotificationTypeBadge];
XCTAssertEqual([RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions],
- UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
+ UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
[permissions setValue:@YES forKey:RCTNotificationTypeSound];
XCTAssertEqual([RCTAzureNotificationHubUtil getNotificationTypesWithPermissions:permissions],
- UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound);
+ UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound);
}
@end