diff --git a/README.md b/README.md index 7ae31e318..e29c80349 100644 --- a/README.md +++ b/README.md @@ -360,7 +360,23 @@ In the location notification json specify the full file name: ## Channel Management (Android) -This library doesn't include a full Channel Management at the moment. Channels are generated on the fly when you pass options to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`. +To use custom channels, create them at startup and pass the matching `channelId` through to `PushNotification.localNotification` + +```javascript + PushNotification.createChannel( + { + channelId: "custom-channel-id", // (required) + channelName: "Custom channel", // (required) + channelDesc: "A custom channel to categorise your custom notifications", // (optional) default: undefined. + soundName: "default", // (optional) See `soundName` parameter of `localNotification` function + importance: 4, // (optional) default: 4. Int value of the Android notification importance + vibrate: true, // (optional) default: true. Creates the default vibration patten if true. + }, + (created: any) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed. + ); +``` + +Channels with ids that do not exist are generated on the fly when you pass options to `PushNotification.localNotification` or `PushNotification.localNotificationSchedule`. The pattern of `channel_id` is: diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java index c268cd452..e64835ad4 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotification.java @@ -297,6 +297,18 @@ public void channelExists(String channel_id, Callback callback) { } } + @ReactMethod + /** + * Creates a channel if it does not already exist. Returns whether the channel was created. + */ + public void createChannel(ReadableMap channelInfo, Callback callback) { + boolean created = mRNPushNotificationHelper.createChannel(channelInfo); + + if(callback != null) { + callback.invoke(created); + } + } + @ReactMethod /** * Check if channel is blocked with a given id diff --git a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java index ecd61b03e..43dade5dd 100644 --- a/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java +++ b/android/src/main/java/com/dieam/reactnativepushnotification/modules/RNPushNotificationHelper.java @@ -428,31 +428,13 @@ public void sendToNotificationCentreWithPicture(Bundle bundle, Bitmap largeIconB Uri soundUri = null; if (!bundle.containsKey("playSound") || bundle.getBoolean("playSound")) { - soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - String soundName = bundle.getString("soundName"); - - if (soundName != null) { - if (!"default".equalsIgnoreCase(soundName)) { - - // sound name can be full filename, or just the resource name. - // So the strings 'my_sound.mp3' AND 'my_sound' are accepted - // The reason is to make the iOS and android javascript interfaces compatible - - int resId; - if (context.getResources().getIdentifier(soundName, "raw", context.getPackageName()) != 0) { - resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); - } else { - soundName = soundName.substring(0, soundName.lastIndexOf('.')); - resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); - } - - soundUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + resId); - } - } else { + if (soundName == null) { soundName = "default"; } + soundUri = getSoundUri(soundName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // API 26 and higher channel_id = channel_id + "-" + soundName; } @@ -676,6 +658,27 @@ private void scheduleNextNotificationIfRepeating(Bundle bundle) { } } + private Uri getSoundUri(String soundName) { + if (soundName == null || "default".equalsIgnoreCase(soundName)) { + return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + } else { + + // sound name can be full filename, or just the resource name. + // So the strings 'my_sound.mp3' AND 'my_sound' are accepted + // The reason is to make the iOS and android javascript interfaces compatible + + int resId; + if (context.getResources().getIdentifier(soundName, "raw", context.getPackageName()) != 0) { + resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); + } else { + soundName = soundName.substring(0, soundName.lastIndexOf('.')); + resId = context.getResources().getIdentifier(soundName, "raw", context.getPackageName()); + } + + return Uri.parse("android.resource://" + context.getPackageName() + "/" + resId); + } + } + public void clearNotifications() { Log.i(LOG_TAG, "Clearing alerts from the notification centre"); @@ -899,11 +902,11 @@ public void deleteChannel(String channel_id) { manager.deleteNotificationChannel(channel_id); } - private void checkOrCreateChannel(NotificationManager manager, String channel_id, String channel_name, String channel_description, Uri soundUri, int importance, long[] vibratePattern) { + private boolean checkOrCreateChannel(NotificationManager manager, String channel_id, String channel_name, String channel_description, Uri soundUri, int importance, long[] vibratePattern) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) - return; + return false; if (manager == null) - return; + return false; NotificationChannel channel = manager.getNotificationChannel(channel_id); @@ -920,7 +923,7 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id channel.setDescription(channel_description); channel.enableLights(true); - channel.enableVibration(true); + channel.enableVibration(vibratePattern != null); channel.setVibrationPattern(vibratePattern); if (soundUri != null) { @@ -935,7 +938,28 @@ private void checkOrCreateChannel(NotificationManager manager, String channel_id } manager.createNotificationChannel(channel); + return true; } + return false; + } + + public boolean createChannel(ReadableMap channelInfo) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) + return false; + + String channelId = channelInfo.getString("channelId"); + String channelName = channelInfo.getString("channelName"); + String channelDesc = channelInfo.hasKey("channelDesc") ? channelInfo.getString("channelDesc") : null; + String soundName = channelInfo.hasKey("soundName") ? channelInfo.getString("soundName") : "default"; + int importance = channelInfo.hasKey("importance") ? channelInfo.getInt("importance") : 4; + boolean vibrate = channelInfo.hasKey("vibrate") && channelInfo.getBoolean("vibrate"); + long[] vibratePattern = vibrate ? new long[] { DEFAULT_VIBRATION } : null; + + NotificationManager manager = notificationManager(); + + Uri soundUri = getSoundUri(soundName); + + return checkOrCreateChannel(manager, channelId, channelName, channelDesc, soundUri, importance, vibratePattern); } public boolean isApplicationInForeground(Context context) { diff --git a/component/index.android.js b/component/index.android.js index b67d44cf4..819acab9b 100644 --- a/component/index.android.js +++ b/component/index.android.js @@ -154,6 +154,10 @@ NotificationsComponent.prototype.channelExists = function(channel_id, callback) RNPushNotification.channelExists(channel_id, callback); } +NotificationsComponent.prototype.createChannel = function(channelInfo, callback) { + RNPushNotification.createChannel(channelInfo, callback); +} + NotificationsComponent.prototype.channelBlocked = function(channel_id, callback) { RNPushNotification.channelBlocked(channel_id, callback); } diff --git a/index.js b/index.js index e71db401f..b1186f02e 100644 --- a/index.js +++ b/index.js @@ -513,6 +513,10 @@ Notifications.channelExists = function() { return this.callNative('channelExists', arguments); }; +Notifications.createChannel = function() { + return this.callNative('createChannel', arguments); +}; + Notifications.channelBlocked = function() { return this.callNative('channelBlocked', arguments); };