[notifications] Android channel and channel group support
This commit is contained in:
parent
7acace4ce6
commit
b9df258402
|
@ -1,49 +0,0 @@
|
|||
package io.invertase.firebase.messaging;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Application;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
import android.content.SharedPreferences;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
public class RNFirebaseLocalMessagingHelper {
|
||||
private static final long DEFAULT_VIBRATION = 300L;
|
||||
private static final String TAG = RNFirebaseLocalMessagingHelper.class.getSimpleName();
|
||||
private final static String PREFERENCES_KEY = "ReactNativeSystemNotification";
|
||||
private static boolean mIsForeground = false; //this is a hack
|
||||
|
||||
private Context mContext;
|
||||
private SharedPreferences sharedPreferences = null;
|
||||
|
||||
public RNFirebaseLocalMessagingHelper(Application context) {
|
||||
mContext = context;
|
||||
sharedPreferences = mContext.getSharedPreferences(PREFERENCES_KEY, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public void setApplicationForeground(boolean foreground){
|
||||
mIsForeground = foreground;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +1,12 @@
|
|||
package io.invertase.firebase.messaging;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.ActivityEventListener;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
|
@ -18,32 +14,20 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
import com.google.firebase.messaging.RemoteMessage.Notification;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class RNFirebaseMessaging extends ReactContextBaseJavaModule implements ActivityEventListener {
|
||||
private static final String BADGE_FILE = "BadgeCountFile";
|
||||
private static final String BADGE_KEY = "BadgeCount";
|
||||
|
||||
public class RNFirebaseMessaging extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "RNFirebaseMessaging";
|
||||
|
||||
private SharedPreferences sharedPreferences = null;
|
||||
|
||||
public RNFirebaseMessaging(ReactApplicationContext context) {
|
||||
super(context);
|
||||
context.addActivityEventListener(this);
|
||||
|
||||
sharedPreferences = context.getSharedPreferences(BADGE_FILE, Context.MODE_PRIVATE);
|
||||
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
|
||||
|
||||
// Subscribe to message events
|
||||
|
@ -73,24 +57,6 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule implements A
|
|||
}
|
||||
|
||||
// Non Web SDK methods
|
||||
|
||||
@ReactMethod
|
||||
public void getBadge(Promise promise) {
|
||||
int badge = sharedPreferences.getInt(BADGE_KEY, 0);
|
||||
Log.d(TAG, "Got badge count: " + badge);
|
||||
promise.resolve(badge);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getInitialMessage(Promise promise) {
|
||||
if (getCurrentActivity() == null) {
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
WritableMap messageMap = parseIntentForMessage(getCurrentActivity().getIntent());
|
||||
promise.resolve(messageMap);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void hasPermission(Promise promise) {
|
||||
promise.resolve(true);
|
||||
|
@ -132,19 +98,6 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule implements A
|
|||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setBadge(int badge) {
|
||||
// Store the badge count for later retrieval
|
||||
sharedPreferences.edit().putInt(BADGE_KEY, badge).apply();
|
||||
if (badge == 0) {
|
||||
Log.d(TAG, "Remove badge count");
|
||||
ShortcutBadger.removeCount(this.getReactApplicationContext());
|
||||
} else {
|
||||
Log.d(TAG, "Apply badge count: " + badge);
|
||||
ShortcutBadger.applyCount(this.getReactApplicationContext(), badge);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void subscribeToTopic(String topic) {
|
||||
FirebaseMessaging.getInstance().subscribeToTopic(topic);
|
||||
|
@ -155,60 +108,6 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule implements A
|
|||
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Start ActivityEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@Override
|
||||
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
||||
// FCM functionality does not need this function
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
WritableMap messageMap = parseIntentForMessage(intent);
|
||||
if (messageMap != null) {
|
||||
Log.d(TAG, "onNewIntent called with new FCM message");
|
||||
Utils.sendEvent(getReactApplicationContext(), "messaging_message_received", messageMap);
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// End ActivityEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
private WritableMap parseIntentForMessage(Intent intent) {
|
||||
// Check if FCM data exists
|
||||
if (intent.getExtras() == null || !intent.hasExtra("google.message_id")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bundle extras = intent.getExtras();
|
||||
|
||||
WritableMap messageMap = Arguments.createMap();
|
||||
WritableMap dataMap = Arguments.createMap();
|
||||
|
||||
for (String key : extras.keySet()) {
|
||||
if (key.equals("collapse_key")) {
|
||||
messageMap.putString("collapseKey", extras.getString("collapse_key"));
|
||||
} else if (key.equals("from")) {
|
||||
messageMap.putString("from", extras.getString("from"));
|
||||
} else if (key.equals("google.message_id")) {
|
||||
messageMap.putString("messageId", extras.getString("google.message_id"));
|
||||
} else if (key.equals("google.sent_time")) {
|
||||
messageMap.putDouble("sentTime", extras.getLong("google.sent_time"));
|
||||
} else if (key.equals("google.ttl")) {
|
||||
messageMap.putDouble("ttl", extras.getDouble("google.ttl"));
|
||||
} else if (key.equals("_fbSourceApplicationHasBeenSet")) {
|
||||
// ignore known unneeded fields
|
||||
} else {
|
||||
dataMap.putString(key, extras.getString(key));
|
||||
}
|
||||
}
|
||||
messageMap.putMap("data", dataMap);
|
||||
messageMap.putBoolean("openedFromTray", true);
|
||||
|
||||
return messageMap;
|
||||
}
|
||||
|
||||
private class MessageReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
@ -246,67 +145,10 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule implements A
|
|||
if (message.getMessageType() != null) {
|
||||
messageMap.putString("messageType", message.getMessageType());
|
||||
}
|
||||
|
||||
if (message.getNotification() != null) {
|
||||
Notification notification = message.getNotification();
|
||||
|
||||
WritableMap notificationMap = Arguments.createMap();
|
||||
|
||||
if (notification.getBody() != null) {
|
||||
notificationMap.putString("body", notification.getBody());
|
||||
}
|
||||
if (notification.getBodyLocalizationArgs() != null) {
|
||||
WritableArray bodyArgs = Arguments.createArray();
|
||||
for (String arg : notification.getBodyLocalizationArgs()) {
|
||||
bodyArgs.pushString(arg);
|
||||
}
|
||||
notificationMap.putArray("bodyLocalizationArgs", bodyArgs);
|
||||
}
|
||||
if (notification.getBodyLocalizationKey() != null) {
|
||||
notificationMap.putString("bodyLocalizationKey", notification.getBodyLocalizationKey());
|
||||
}
|
||||
if (notification.getClickAction() != null) {
|
||||
notificationMap.putString("clickAction", notification.getClickAction());
|
||||
}
|
||||
if (notification.getColor() != null) {
|
||||
notificationMap.putString("color", notification.getColor());
|
||||
}
|
||||
if (notification.getIcon() != null) {
|
||||
notificationMap.putString("icon", notification.getIcon());
|
||||
}
|
||||
if (notification.getLink() != null) {
|
||||
notificationMap.putString("link", notification.getLink().toString());
|
||||
}
|
||||
if (notification.getSound() != null) {
|
||||
notificationMap.putString("sound", notification.getSound());
|
||||
}
|
||||
if (notification.getTag() != null) {
|
||||
notificationMap.putString("tag", notification.getTag());
|
||||
}
|
||||
if (notification.getTitle() != null) {
|
||||
notificationMap.putString("title", notification.getTitle());
|
||||
}
|
||||
if (notification.getTitleLocalizationArgs() != null) {
|
||||
WritableArray titleArgs = Arguments.createArray();
|
||||
for (String arg : notification.getTitleLocalizationArgs()) {
|
||||
titleArgs.pushString(arg);
|
||||
}
|
||||
notificationMap.putArray("titleLocalizationArgs", titleArgs);
|
||||
}
|
||||
if (notification.getTitleLocalizationKey() != null) {
|
||||
notificationMap.putString("titleLocalizationKey", notification.getTitleLocalizationKey());
|
||||
}
|
||||
|
||||
messageMap.putMap("notification", notificationMap);
|
||||
}
|
||||
|
||||
messageMap.putBoolean("openedFromTray", false);
|
||||
messageMap.putDouble("sentTime", message.getSentTime());
|
||||
|
||||
if (message.getTo() != null) {
|
||||
messageMap.putString("to", message.getTo());
|
||||
}
|
||||
|
||||
messageMap.putDouble("ttl", message.getTtl());
|
||||
|
||||
return messageMap;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.invertase.firebase.messaging;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.JavaScriptModule;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
|
|
|
@ -10,16 +10,25 @@ import com.google.firebase.messaging.RemoteMessage;
|
|||
public class RNFirebaseMessagingService extends FirebaseMessagingService {
|
||||
private static final String TAG = "RNFMessagingService";
|
||||
public static final String MESSAGE_EVENT = "messaging-message";
|
||||
public static final String REMOTE_NOTIFICATION_EVENT = "notifications-remote-notification";
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(RemoteMessage message) {
|
||||
Log.d(TAG, "onMessageReceived event received");
|
||||
|
||||
// Build an Intent to pass the token to the RN Application
|
||||
Intent messageEvent = new Intent(MESSAGE_EVENT);
|
||||
messageEvent.putExtra("message", message);
|
||||
Intent event;
|
||||
|
||||
if (message.getNotification() != null) {
|
||||
// It's a notification, pass to the notification module
|
||||
event = new Intent(REMOTE_NOTIFICATION_EVENT);
|
||||
event.putExtra("notification", message);
|
||||
} else {
|
||||
// It's a data message, pass to the messaging module
|
||||
event = new Intent(MESSAGE_EVENT);
|
||||
event.putExtra("message", message);
|
||||
}
|
||||
|
||||
// Broadcast it so it is only available to the RN Application
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(messageEvent);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(event);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package io.invertase.firebase.notifications;
|
|||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
|
@ -21,6 +23,7 @@ import android.util.Log;
|
|||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
@ -30,6 +33,7 @@ import java.io.IOException;
|
|||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.messaging.BundleJSONConverter;
|
||||
|
@ -71,6 +75,42 @@ public class RNFirebaseNotificationManager {
|
|||
preferences.edit().remove(notificationId).apply();
|
||||
}
|
||||
|
||||
public void createChannel(ReadableMap channelMap) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = parseChannelMap(channelMap);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
public void createChannelGroup(ReadableMap channelGroupMap) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannelGroup channelGroup = parseChannelGroupMap(channelGroupMap);
|
||||
notificationManager.createNotificationChannelGroup(channelGroup);
|
||||
}
|
||||
}
|
||||
|
||||
public void createChannelGroups(ReadableArray channelGroupsArray) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
List<NotificationChannelGroup> channelGroups = new ArrayList<>();
|
||||
for (int i = 0; i < channelGroupsArray.size(); i++) {
|
||||
NotificationChannelGroup channelGroup = parseChannelGroupMap(channelGroupsArray.getMap(i));
|
||||
channelGroups.add(channelGroup);
|
||||
}
|
||||
notificationManager.createNotificationChannelGroups(channelGroups);
|
||||
}
|
||||
}
|
||||
|
||||
public void createChannels(ReadableArray channelsArray) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
List<NotificationChannel> channels = new ArrayList<>();
|
||||
for (int i = 0; i < channelsArray.size(); i++) {
|
||||
NotificationChannel channel = parseChannelMap(channelsArray.getMap(i));
|
||||
channels.add(channel);
|
||||
}
|
||||
notificationManager.createNotificationChannels(channels);
|
||||
}
|
||||
}
|
||||
|
||||
public void displayNotification(ReadableMap notification, Promise promise) {
|
||||
Bundle notificationBundle = Arguments.toBundle(notification);
|
||||
displayNotification(notificationBundle, promise);
|
||||
|
@ -155,12 +195,14 @@ public class RNFirebaseNotificationManager {
|
|||
return;
|
||||
}
|
||||
|
||||
String channelId = notification.getString("channelId");
|
||||
Bundle android = notification.getBundle("android");
|
||||
|
||||
String channelId = android.getString("channelId");
|
||||
String notificationId = notification.getString("notificationId");
|
||||
|
||||
NotificationCompat.Builder nb;
|
||||
// TODO: Change 27 to 'Build.VERSION_CODES.O_MR1' when using appsupport v27
|
||||
if (Build.VERSION.SDK_INT >= 27) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
nb = new NotificationCompat.Builder(context, channelId);
|
||||
} else {
|
||||
nb = new NotificationCompat.Builder(context);
|
||||
|
@ -173,16 +215,8 @@ public class RNFirebaseNotificationManager {
|
|||
nb = nb.setExtras(notification.getBundle("data"));
|
||||
}
|
||||
if (notification.containsKey("sound")) {
|
||||
String sound = notification.getString("sound");
|
||||
if (sound.equalsIgnoreCase("default")) {
|
||||
nb = nb.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
|
||||
} else {
|
||||
int soundResourceId = getResourceId("raw", sound);
|
||||
if (soundResourceId == 0) {
|
||||
soundResourceId = getResourceId("raw", sound.substring(0, sound.lastIndexOf('.')));
|
||||
}
|
||||
nb = nb.setSound(Uri.parse("android.resource://" + context.getPackageName() + "/" + soundResourceId));
|
||||
}
|
||||
Uri sound = getSound(notification.getString("sound"));
|
||||
nb = nb.setSound(sound);
|
||||
}
|
||||
if (notification.containsKey("subtitle")) {
|
||||
nb = nb.setSubText(notification.getString("subtitle"));
|
||||
|
@ -191,125 +225,138 @@ public class RNFirebaseNotificationManager {
|
|||
nb = nb.setContentTitle(notification.getString("title"));
|
||||
}
|
||||
|
||||
if (notification.containsKey("autoCancel")) {
|
||||
nb = nb.setAutoCancel(notification.getBoolean("autoCancel"));
|
||||
if (android.containsKey("autoCancel")) {
|
||||
nb = nb.setAutoCancel(android.getBoolean("autoCancel"));
|
||||
}
|
||||
if (notification.containsKey("badgeIconType")) {
|
||||
nb = nb.setBadgeIconType(notification.getInt("badgeIconType"));
|
||||
if (android.containsKey("badgeIconType")) {
|
||||
Double badgeIconType = android.getDouble("badgeIconType");
|
||||
nb = nb.setBadgeIconType(badgeIconType.intValue());
|
||||
}
|
||||
if (notification.containsKey("category")) {
|
||||
nb = nb.setCategory(notification.getString("category"));
|
||||
if (android.containsKey("category")) {
|
||||
nb = nb.setCategory(android.getString("category"));
|
||||
}
|
||||
if (notification.containsKey("color")) {
|
||||
String color = notification.getString("color");
|
||||
if (android.containsKey("color")) {
|
||||
String color = android.getString("color");
|
||||
nb = nb.setColor(Color.parseColor(color));
|
||||
}
|
||||
if (notification.containsKey("colorized")) {
|
||||
nb = nb.setColorized(notification.getBoolean("colorized"));
|
||||
if (android.containsKey("colorized")) {
|
||||
nb = nb.setColorized(android.getBoolean("colorized"));
|
||||
}
|
||||
if (notification.containsKey("contentInfo")) {
|
||||
nb = nb.setContentInfo(notification.getString("contentInfo"));
|
||||
if (android.containsKey("contentInfo")) {
|
||||
nb = nb.setContentInfo(android.getString("contentInfo"));
|
||||
}
|
||||
if (notification.containsKey("defaults")) {
|
||||
int[] defaultsArray = notification.getIntArray("defaults");
|
||||
double[] defaultsArray = android.getDoubleArray("defaults");
|
||||
int defaults = 0;
|
||||
for (int d : defaultsArray) {
|
||||
defaults |= d;
|
||||
for (Double d : defaultsArray) {
|
||||
defaults |= d.intValue();
|
||||
}
|
||||
nb = nb.setDefaults(defaults);
|
||||
}
|
||||
if (notification.containsKey("group")) {
|
||||
nb = nb.setGroup(notification.getString("group"));
|
||||
if (android.containsKey("group")) {
|
||||
nb = nb.setGroup(android.getString("group"));
|
||||
}
|
||||
if (notification.containsKey("groupAlertBehaviour")) {
|
||||
nb = nb.setGroupAlertBehavior(notification.getInt("groupAlertBehaviour"));
|
||||
if (android.containsKey("groupAlertBehaviour")) {
|
||||
Double groupAlertBehaviour = android.getDouble("groupAlertBehaviour");
|
||||
nb = nb.setGroupAlertBehavior(groupAlertBehaviour.intValue());
|
||||
}
|
||||
if (notification.containsKey("groupSummary")) {
|
||||
nb = nb.setGroupSummary(notification.getBoolean("groupSummary"));
|
||||
if (android.containsKey("groupSummary")) {
|
||||
nb = nb.setGroupSummary(android.getBoolean("groupSummary"));
|
||||
}
|
||||
if (notification.containsKey("largeIcon")) {
|
||||
Bitmap largeIcon = getBitmap(notification.getString("largeIcon"));
|
||||
if (android.containsKey("largeIcon")) {
|
||||
Bitmap largeIcon = getBitmap(android.getString("largeIcon"));
|
||||
if (largeIcon != null) {
|
||||
nb = nb.setLargeIcon(largeIcon);
|
||||
}
|
||||
}
|
||||
if (notification.containsKey("lights")) {
|
||||
Bundle lights = notification.getBundle("lights");
|
||||
nb = nb.setLights(lights.getInt("argb"), lights.getInt("onMs"), lights.getInt("offMs"));
|
||||
if (android.containsKey("lights")) {
|
||||
Bundle lights = android.getBundle("lights");
|
||||
Double argb = lights.getDouble("argb");
|
||||
Double onMs = lights.getDouble("onMs");
|
||||
Double offMs = lights.getDouble("offMs");
|
||||
nb = nb.setLights(argb.intValue(), onMs.intValue(), offMs.intValue());
|
||||
}
|
||||
if (notification.containsKey("localOnly")) {
|
||||
nb = nb.setLocalOnly(notification.getBoolean("localOnly"));
|
||||
if (android.containsKey("localOnly")) {
|
||||
nb = nb.setLocalOnly(android.getBoolean("localOnly"));
|
||||
}
|
||||
|
||||
if (notification.containsKey("number")) {
|
||||
nb = nb.setNumber(notification.getInt("number"));
|
||||
if (android.containsKey("number")) {
|
||||
Double number = android.getDouble("number");
|
||||
nb = nb.setNumber(number.intValue());
|
||||
}
|
||||
if (notification.containsKey("ongoing")) {
|
||||
nb = nb.setOngoing(notification.getBoolean("ongoing"));
|
||||
if (android.containsKey("ongoing")) {
|
||||
nb = nb.setOngoing(android.getBoolean("ongoing"));
|
||||
}
|
||||
if (notification.containsKey("onlyAlertOnce")) {
|
||||
nb = nb.setOngoing(notification.getBoolean("onlyAlertOnce"));
|
||||
if (android.containsKey("onlyAlertOnce")) {
|
||||
nb = nb.setOngoing(android.getBoolean("onlyAlertOnce"));
|
||||
}
|
||||
if (notification.containsKey("people")) {
|
||||
String[] people = notification.getStringArray("people");
|
||||
for (String person : people) {
|
||||
nb = nb.addPerson(person);
|
||||
if (android.containsKey("people")) {
|
||||
String[] people = android.getStringArray("people");
|
||||
if (people != null) {
|
||||
for (String person : people) {
|
||||
nb = nb.addPerson(person);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (notification.containsKey("priority")) {
|
||||
nb = nb.setPriority(notification.getInt("priority"));
|
||||
if (android.containsKey("priority")) {
|
||||
Double priority = android.getDouble("priority");
|
||||
nb = nb.setPriority(priority.intValue());
|
||||
}
|
||||
if (notification.containsKey("progress")) {
|
||||
Bundle progress = notification.getBundle("lights");
|
||||
nb = nb.setProgress(progress.getInt("max"), progress.getInt("progress"), progress.getBoolean("indeterminate"));
|
||||
if (android.containsKey("progress")) {
|
||||
Bundle progress = android.getBundle("lights");
|
||||
Double max = progress.getDouble("max");
|
||||
Double progressI = progress.getDouble("progress");
|
||||
nb = nb.setProgress(max.intValue(), progressI.intValue(), progress.getBoolean("indeterminate"));
|
||||
}
|
||||
// TODO: Public version of notification
|
||||
/* if (notification.containsKey("publicVersion")) {
|
||||
/* if (android.containsKey("publicVersion")) {
|
||||
nb = nb.setPublicVersion();
|
||||
} */
|
||||
if (notification.containsKey("remoteInputHistory")) {
|
||||
nb = nb.setRemoteInputHistory(notification.getStringArray("remoteInputHistory"));
|
||||
if (android.containsKey("remoteInputHistory")) {
|
||||
nb = nb.setRemoteInputHistory(android.getStringArray("remoteInputHistory"));
|
||||
}
|
||||
if (notification.containsKey("shortcutId")) {
|
||||
nb = nb.setShortcutId(notification.getString("shortcutId"));
|
||||
if (android.containsKey("shortcutId")) {
|
||||
nb = nb.setShortcutId(android.getString("shortcutId"));
|
||||
}
|
||||
if (notification.containsKey("showWhen")) {
|
||||
nb = nb.setShowWhen(notification.getBoolean("showWhen"));
|
||||
if (android.containsKey("showWhen")) {
|
||||
nb = nb.setShowWhen(android.getBoolean("showWhen"));
|
||||
}
|
||||
if (notification.containsKey("smallIcon")) {
|
||||
Bundle smallIcon = notification.getBundle("smallIcon");
|
||||
if (android.containsKey("smallIcon")) {
|
||||
Bundle smallIcon = android.getBundle("smallIcon");
|
||||
int smallIconResourceId = getResourceId("mipmap", smallIcon.getString("icon"));
|
||||
if (smallIconResourceId == 0) {
|
||||
smallIconResourceId = getResourceId("drawable", smallIcon.getString("icon"));
|
||||
}
|
||||
if (smallIconResourceId != 0) {
|
||||
if (smallIcon.containsKey("level")) {
|
||||
nb = nb.setSmallIcon(smallIconResourceId, smallIcon.getInt("level"));
|
||||
Double level = smallIcon.getDouble("level");
|
||||
nb = nb.setSmallIcon(smallIconResourceId, level.intValue());
|
||||
} else {
|
||||
nb = nb.setSmallIcon(smallIconResourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (notification.containsKey("sortKey")) {
|
||||
nb = nb.setSortKey(notification.getString("sortKey"));
|
||||
if (android.containsKey("sortKey")) {
|
||||
nb = nb.setSortKey(android.getString("sortKey"));
|
||||
}
|
||||
if (notification.containsKey("ticker")) {
|
||||
nb = nb.setTicker(notification.getString("ticker"));
|
||||
if (android.containsKey("ticker")) {
|
||||
nb = nb.setTicker(android.getString("ticker"));
|
||||
}
|
||||
if (notification.containsKey("timeoutAfter")) {
|
||||
nb = nb.setTimeoutAfter(notification.getLong("timeoutAfter"));
|
||||
if (android.containsKey("timeoutAfter")) {
|
||||
nb = nb.setTimeoutAfter(android.getLong("timeoutAfter"));
|
||||
}
|
||||
if (notification.containsKey("usesChronometer")) {
|
||||
nb = nb.setUsesChronometer(notification.getBoolean("usesChronometer"));
|
||||
if (android.containsKey("usesChronometer")) {
|
||||
nb = nb.setUsesChronometer(android.getBoolean("usesChronometer"));
|
||||
}
|
||||
if (notification.containsKey("vibrate")) {
|
||||
nb = nb.setVibrate(notification.getLongArray("vibrate"));
|
||||
if (android.containsKey("vibrate")) {
|
||||
nb = nb.setVibrate(android.getLongArray("vibrate"));
|
||||
}
|
||||
if (notification.containsKey("visibility")) {
|
||||
nb = nb.setVisibility(notification.getInt("visibility"));
|
||||
if (android.containsKey("visibility")) {
|
||||
Double visibility = android.getDouble("visibility");
|
||||
nb = nb.setVisibility(visibility.intValue());
|
||||
}
|
||||
if (notification.containsKey("when")) {
|
||||
nb = nb.setWhen(notification.getLong("when"));
|
||||
if (android.containsKey("when")) {
|
||||
nb = nb.setWhen(android.getLong("when"));
|
||||
}
|
||||
|
||||
// TODO: Big text / Big picture
|
||||
|
@ -335,8 +382,8 @@ public class RNFirebaseNotificationManager {
|
|||
Intent intent = new Intent(context, intentClass);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
intent.putExtras(notification);
|
||||
if (notification.containsKey("clickAction")) {
|
||||
intent.setAction(notification.getString("clickAction"));
|
||||
if (android.containsKey("clickAction")) {
|
||||
intent.setAction(android.getString("clickAction"));
|
||||
}
|
||||
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(context, notificationId.hashCode(), intent,
|
||||
|
@ -391,6 +438,71 @@ public class RNFirebaseNotificationManager {
|
|||
return context.getResources().getIdentifier(image, type, context.getPackageName());
|
||||
}
|
||||
|
||||
private Uri getSound(String sound) {
|
||||
if (sound.equalsIgnoreCase("default")) {
|
||||
return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
||||
} else {
|
||||
int soundResourceId = getResourceId("raw", sound);
|
||||
if (soundResourceId == 0) {
|
||||
soundResourceId = getResourceId("raw", sound.substring(0, sound.lastIndexOf('.')));
|
||||
}
|
||||
return Uri.parse("android.resource://" + context.getPackageName() + "/" + soundResourceId);
|
||||
}
|
||||
}
|
||||
|
||||
private NotificationChannelGroup parseChannelGroupMap(ReadableMap channelGroupMap) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
String groupId = channelGroupMap.getString("groupId");
|
||||
String name = channelGroupMap.getString("name");
|
||||
|
||||
return new NotificationChannelGroup(groupId, name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private NotificationChannel parseChannelMap(ReadableMap channelMap) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
String channelId = channelMap.getString("channelId");
|
||||
String name = channelMap.getString("name");
|
||||
int importance = channelMap.getInt("importance");
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(channelId, name, importance);
|
||||
if (channelMap.hasKey("bypassDnd")) {
|
||||
channel.setBypassDnd(channelMap.getBoolean("bypassDnd"));
|
||||
}
|
||||
if (channelMap.hasKey("description")) {
|
||||
channel.setDescription(channelMap.getString("description"));
|
||||
}
|
||||
if (channelMap.hasKey("group")) {
|
||||
channel.setGroup(channelMap.getString("group"));
|
||||
}
|
||||
if (channelMap.hasKey("lightColor")) {
|
||||
String lightColor = channelMap.getString("lightColor");
|
||||
channel.setLightColor(Color.parseColor(lightColor));
|
||||
}
|
||||
if (channelMap.hasKey("lockScreenVisibility")) {
|
||||
channel.setLockscreenVisibility(channelMap.getInt("lockScreenVisibility"));
|
||||
}
|
||||
if (channelMap.hasKey("showBadge")) {
|
||||
channel.setShowBadge(channelMap.getBoolean("showBadge"));
|
||||
}
|
||||
if (channelMap.hasKey("sound")) {
|
||||
Uri sound = getSound(channelMap.getString("sound"));
|
||||
channel.setSound(sound, null);
|
||||
}
|
||||
if (channelMap.hasKey("vibrationPattern")) {
|
||||
ReadableArray vibrationArray = channelMap.getArray("vibrationPattern");
|
||||
long[] vibration = new long[]{};
|
||||
for (int i = 0; i < vibrationArray.size(); i++) {
|
||||
vibration[i] = (long) vibrationArray.getDouble(i);
|
||||
}
|
||||
channel.setVibrationPattern(vibration);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void scheduleNotification(Bundle notification, Promise promise) {
|
||||
if (!notification.containsKey("notificationId")) {
|
||||
if (promise == null) {
|
||||
|
|
|
@ -1,38 +1,57 @@
|
|||
package io.invertase.firebase.notifications;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.ActivityEventListener;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
import io.invertase.firebase.messaging.RNFirebaseMessagingService;
|
||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
|
||||
public class RNFirebaseNotifications extends ReactContextBaseJavaModule implements LifecycleEventListener {
|
||||
public class RNFirebaseNotifications extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
|
||||
private static final String BADGE_FILE = "BadgeCountFile";
|
||||
private static final String BADGE_KEY = "BadgeCount";
|
||||
private static final String TAG = "RNFirebaseNotifications";
|
||||
|
||||
private SharedPreferences sharedPreferences = null;
|
||||
|
||||
private RNFirebaseNotificationManager notificationManager;
|
||||
public RNFirebaseNotifications(ReactApplicationContext context) {
|
||||
super(context);
|
||||
notificationManager = new RNFirebaseNotificationManager(context.getApplicationContext());
|
||||
context.addActivityEventListener(this);
|
||||
context.addLifecycleEventListener(this);
|
||||
|
||||
notificationManager = new RNFirebaseNotificationManager(context.getApplicationContext());
|
||||
sharedPreferences = context.getSharedPreferences(BADGE_FILE, Context.MODE_PRIVATE);
|
||||
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
|
||||
|
||||
// Subscribe to remote notification events
|
||||
localBroadcastManager.registerReceiver(new RemoteNotificationReceiver(),
|
||||
new IntentFilter(RNFirebaseMessagingService.REMOTE_NOTIFICATION_EVENT));
|
||||
|
||||
// Subscribe to scheduled notification events
|
||||
localBroadcastManager.registerReceiver(new ScheduledNotificationReceiver(),
|
||||
new IntentFilter(RNFirebaseNotificationManager.SCHEDULED_NOTIFICATION_EVENT));
|
||||
|
@ -58,9 +77,22 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
|
|||
notificationManager.displayNotification(notification, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getBadge(Promise promise) {
|
||||
int badge = sharedPreferences.getInt(BADGE_KEY, 0);
|
||||
Log.d(TAG, "Got badge count: " + badge);
|
||||
promise.resolve(badge);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getInitialNotification(Promise promise) {
|
||||
// TODO
|
||||
if (getCurrentActivity() == null) {
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
WritableMap notificationOpenedMap = parseIntentForRemoteNotification(getCurrentActivity().getIntent());
|
||||
promise.resolve(notificationOpenedMap);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
|
@ -83,11 +115,74 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
|
|||
notificationManager.removeDeliveredNotification(notificationId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setBadge(int badge) {
|
||||
// Store the badge count for later retrieval
|
||||
sharedPreferences.edit().putInt(BADGE_KEY, badge).apply();
|
||||
if (badge == 0) {
|
||||
Log.d(TAG, "Remove badge count");
|
||||
ShortcutBadger.removeCount(this.getReactApplicationContext());
|
||||
} else {
|
||||
Log.d(TAG, "Apply badge count: " + badge);
|
||||
ShortcutBadger.applyCount(this.getReactApplicationContext(), badge);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void scheduleNotification(ReadableMap notification, Promise promise) {
|
||||
notificationManager.scheduleNotification(notification, promise);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Start Android specific methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ReactMethod
|
||||
public void createChannel(ReadableMap channelMap, Promise promise) {
|
||||
notificationManager.createChannel(channelMap);
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createChannelGroup(ReadableMap channelGroupMap, Promise promise) {
|
||||
notificationManager.createChannelGroup(channelGroupMap);
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createChannelGroup(ReadableArray channelGroupsArray, Promise promise) {
|
||||
notificationManager.createChannelGroups(channelGroupsArray);
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createChannels(ReadableArray channelsArray, Promise promise) {
|
||||
notificationManager.createChannels(channelsArray);
|
||||
promise.resolve(null);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// End Android specific methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Start ActivityEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@Override
|
||||
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
||||
// FCM functionality does not need this function
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
WritableMap notificationOpenedMap = parseIntentForRemoteNotification(intent);
|
||||
if (notificationOpenedMap != null) {
|
||||
Log.d(TAG, "onNewIntent called with new remote notification");
|
||||
Utils.sendEvent(getReactApplicationContext(), "notifications_notification_opened", notificationOpenedMap);
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// End ActivityEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Start LifecycleEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -109,10 +204,102 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
|
|||
// End LifecycleEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
private WritableMap parseIntentForRemoteNotification(Intent intent) {
|
||||
// Check if FCM data exists
|
||||
if (intent.getExtras() == null || !intent.hasExtra("google.message_id")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bundle extras = intent.getExtras();
|
||||
|
||||
WritableMap notificationMap = Arguments.createMap();
|
||||
WritableMap dataMap = Arguments.createMap();
|
||||
|
||||
for (String key : extras.keySet()) {
|
||||
if (key.equals("google.message_id")) {
|
||||
notificationMap.putString("notificationId", extras.getString(key));
|
||||
} else if (key.equals("collapse_key")
|
||||
|| key.equals("from")
|
||||
|| key.equals("google.sent_time")
|
||||
|| key.equals("google.ttl")
|
||||
|| key.equals("_fbSourceApplicationHasBeenSet")) {
|
||||
// ignore known unneeded fields
|
||||
} else {
|
||||
dataMap.putString(key, extras.getString(key));
|
||||
}
|
||||
}
|
||||
notificationMap.putMap("data", dataMap);
|
||||
|
||||
WritableMap notificationOpenedMap = Arguments.createMap();
|
||||
notificationOpenedMap.putString("action", intent.getAction());
|
||||
notificationOpenedMap.putMap("notification", notificationMap);
|
||||
|
||||
return notificationOpenedMap;
|
||||
}
|
||||
|
||||
private WritableMap parseNotificationBundle(Bundle notification) {
|
||||
return Arguments.makeNativeMap(notification);
|
||||
}
|
||||
|
||||
private WritableMap parseRemoteMessage(RemoteMessage message) {
|
||||
RemoteMessage.Notification notification = message.getNotification();
|
||||
|
||||
WritableMap notificationMap = Arguments.createMap();
|
||||
WritableMap dataMap = Arguments.createMap();
|
||||
|
||||
// Cross platform notification properties
|
||||
notificationMap.putString("body", notification.getBody());
|
||||
if (message.getData() != null) {
|
||||
for (Map.Entry<String, String> e : message.getData().entrySet()) {
|
||||
dataMap.putString(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
notificationMap.putMap("data", dataMap);
|
||||
if (message.getMessageId() != null) {
|
||||
notificationMap.putString("notificationId", message.getMessageId());
|
||||
}
|
||||
if (notification.getSound() != null) {
|
||||
notificationMap.putString("sound", notification.getSound());
|
||||
}
|
||||
if (notification.getTitle() != null) {
|
||||
notificationMap.putString("title", notification.getTitle());
|
||||
}
|
||||
|
||||
// Android specific notification properties
|
||||
WritableMap androidMap = Arguments.createMap();
|
||||
if (notification.getClickAction() != null) {
|
||||
androidMap.putString("clickAction", notification.getClickAction());
|
||||
}
|
||||
if (notification.getColor() != null) {
|
||||
androidMap.putString("color", notification.getColor());
|
||||
}
|
||||
if (notification.getIcon() != null) {
|
||||
WritableMap iconMap = Arguments.createMap();
|
||||
iconMap.putString("icon", notification.getIcon());
|
||||
androidMap.putMap("smallIcon", iconMap);
|
||||
}
|
||||
if (notification.getTag() != null) {
|
||||
androidMap.putString("group", notification.getTag());
|
||||
}
|
||||
|
||||
return notificationMap;
|
||||
}
|
||||
|
||||
private class RemoteNotificationReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (getReactApplicationContext().hasActiveCatalystInstance()) {
|
||||
Log.d(TAG, "Received new remote notification");
|
||||
|
||||
RemoteMessage message = intent.getParcelableExtra("notification");
|
||||
WritableMap messageMap = parseRemoteMessage(message);
|
||||
|
||||
Utils.sendEvent(getReactApplicationContext(), "notifications_notification_received", messageMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ScheduledNotificationReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
|
|
@ -25,6 +25,7 @@ export default class RemoteMessage {
|
|||
this._data = inboundMessage.data;
|
||||
this._from = inboundMessage.from;
|
||||
this._messageId = inboundMessage.messageId;
|
||||
this._messageType = inboundMessage.messageType;
|
||||
this._sentTime = inboundMessage.sentTime;
|
||||
}
|
||||
// defaults
|
||||
|
@ -50,6 +51,10 @@ export default class RemoteMessage {
|
|||
return this._messageId;
|
||||
}
|
||||
|
||||
get messageType(): ?string {
|
||||
return this._messageType;
|
||||
}
|
||||
|
||||
get sentTime(): ?number {
|
||||
return this._sentTime;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ export type NativeInboundRemoteMessage = {
|
|||
data: { [string]: string },
|
||||
from?: string,
|
||||
messageId: string,
|
||||
messageType?: string,
|
||||
sentTime?: number,
|
||||
to?: string,
|
||||
ttl?: number,
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
/**
|
||||
* @flow
|
||||
* AndroidChannel representation wrapper
|
||||
*/
|
||||
import type { ImportanceType, VisibilityType } from './types';
|
||||
|
||||
type NativeAndroidChannel = {|
|
||||
bypassDnd?: boolean,
|
||||
channelId: string,
|
||||
description?: string,
|
||||
group?: string,
|
||||
importance: ImportanceType,
|
||||
lightColor?: string,
|
||||
lockScreenVisibility?: VisibilityType,
|
||||
name: string,
|
||||
showBadge?: boolean,
|
||||
sound?: string,
|
||||
vibrationPattern?: number[],
|
||||
|};
|
||||
|
||||
export default class AndroidChannel {
|
||||
_bypassDnd: boolean | void;
|
||||
_channelId: string;
|
||||
_description: string | void;
|
||||
_group: string | void;
|
||||
_importance: ImportanceType;
|
||||
_lightColor: string | void;
|
||||
_lockScreenVisibility: VisibilityType;
|
||||
_name: string;
|
||||
_showBadge: boolean | void;
|
||||
_sound: string | void;
|
||||
_vibrationPattern: number[] | void;
|
||||
|
||||
get bypassDnd(): ?boolean {
|
||||
return this._bypassDnd;
|
||||
}
|
||||
|
||||
get channelId(): string {
|
||||
return this._channelId;
|
||||
}
|
||||
|
||||
get description(): ?string {
|
||||
return this._description;
|
||||
}
|
||||
|
||||
get group(): ?string {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
get importance(): ImportanceType {
|
||||
return this._importance;
|
||||
}
|
||||
|
||||
get lightColor(): ?string {
|
||||
return this._lightColor;
|
||||
}
|
||||
|
||||
get lockScreenVisibility(): ?VisibilityType {
|
||||
return this._lockScreenVisibility;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get showBadge(): ?boolean {
|
||||
return this._showBadge;
|
||||
}
|
||||
|
||||
get sound(): ?string {
|
||||
return this._sound;
|
||||
}
|
||||
|
||||
get vibrationPattern(): ?(number[]) {
|
||||
return this._vibrationPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bypassDnd
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setBypassDnd(bypassDnd: boolean): AndroidChannel {
|
||||
this._bypassDnd = bypassDnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param channelId
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setChannelId(channelId: string): AndroidChannel {
|
||||
this._channelId = channelId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param description
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setDescription(description: string): AndroidChannel {
|
||||
this._description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param group
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setGroup(groupId: string): AndroidChannel {
|
||||
this._group = groupId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param importance
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setImportance(importance: ImportanceType): AndroidChannel {
|
||||
this._importance = importance;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param lightColor
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setLightColor(lightColor: string): AndroidChannel {
|
||||
this._lightColor = lightColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param lockScreenVisibility
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setLockScreenVisibility(
|
||||
lockScreenVisibility: VisibilityType
|
||||
): AndroidChannel {
|
||||
this._lockScreenVisibility = lockScreenVisibility;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setName(name: string): AndroidChannel {
|
||||
this._name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param showBadge
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setShowBadge(showBadge: boolean): AndroidChannel {
|
||||
this._showBadge = showBadge;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sound
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setSound(sound: string): AndroidChannel {
|
||||
this._sound = sound;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param vibrationPattern
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setVibrationPattern(vibrationPattern: number[]): AndroidChannel {
|
||||
this._vibrationPattern = vibrationPattern;
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): NativeAndroidChannel {
|
||||
if (!this._channelId) {
|
||||
throw new Error('AndroidChannel: Missing required `channelId` property');
|
||||
} else if (!this._importance) {
|
||||
throw new Error('AndroidChannel: Missing required `importance` property');
|
||||
} else if (!this._name) {
|
||||
throw new Error('AndroidChannel: Missing required `name` property');
|
||||
}
|
||||
|
||||
return {
|
||||
bypassDnd: this._bypassDnd,
|
||||
channelId: this._channelId,
|
||||
description: this._description,
|
||||
group: this._group,
|
||||
importance: this._importance,
|
||||
lightColor: this._lightColor,
|
||||
lockScreenVisibility: this._lockScreenVisibility,
|
||||
name: this._name,
|
||||
showBadge: this._showBadge,
|
||||
sound: this._sound,
|
||||
vibrationPattern: this._vibrationPattern,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* @flow
|
||||
* AndroidChannelGroup representation wrapper
|
||||
*/
|
||||
|
||||
type NativeAndroidChannelGroup = {|
|
||||
groupId: string,
|
||||
name: string,
|
||||
|};
|
||||
|
||||
export default class AndroidChannel {
|
||||
_groupId: string;
|
||||
_name: string;
|
||||
|
||||
get groupId(): string {
|
||||
return this._groupId;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param groupId
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setGroupId(groupId: string): AndroidChannel {
|
||||
this._groupId = groupId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @returns {AndroidChannel}
|
||||
*/
|
||||
setName(name: string): AndroidChannel {
|
||||
this._name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): NativeAndroidChannelGroup {
|
||||
if (!this._groupId) {
|
||||
throw new Error(
|
||||
'AndroidChannelGroup: Missing required `groupId` property'
|
||||
);
|
||||
} else if (!this._name) {
|
||||
throw new Error('AndroidChannelGroup: Missing required `name` property');
|
||||
}
|
||||
|
||||
return {
|
||||
groupId: this._groupId,
|
||||
name: this._name,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* @flow
|
||||
* AndroidNotifications representation wrapper
|
||||
*/
|
||||
import { Platform } from 'react-native';
|
||||
import AndroidChannel from './AndroidChannel';
|
||||
import AndroidChannelGroup from './AndroidChannelGroup';
|
||||
import { getNativeModule } from '../../utils/native';
|
||||
|
||||
import type Notifications from './';
|
||||
|
||||
export default class AndroidNotifications {
|
||||
_notifications: Notifications;
|
||||
|
||||
constructor(notifications: Notifications) {
|
||||
this._notifications = notifications;
|
||||
}
|
||||
|
||||
createChannel(channel: AndroidChannel): Promise<void> {
|
||||
if (Platform.OS === 'android') {
|
||||
if (!(channel instanceof AndroidChannel)) {
|
||||
throw new Error(
|
||||
`AndroidNotifications:createChannel expects an 'AndroidChannel' but got type ${typeof channel}`
|
||||
);
|
||||
}
|
||||
return getNativeModule(this._notifications).createChannel(
|
||||
channel.build()
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
createChannelGroup(channelGroup: AndroidChannelGroup): Promise<void> {
|
||||
if (Platform.OS === 'android') {
|
||||
if (!(channelGroup instanceof AndroidChannelGroup)) {
|
||||
throw new Error(
|
||||
`AndroidNotifications:createChannelGroup expects an 'AndroidChannelGroup' but got type ${typeof channelGroup}`
|
||||
);
|
||||
}
|
||||
return getNativeModule(this._notifications).createChannelGroup(
|
||||
channelGroup.build()
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
createChannelGroups(channelGroups: AndroidChannelGroup[]): Promise<void> {
|
||||
if (Platform.OS === 'android') {
|
||||
if (!Array.isArray(channelGroups)) {
|
||||
throw new Error(
|
||||
`AndroidNotifications:createChannelGroups expects an 'Array' but got type ${typeof channelGroups}`
|
||||
);
|
||||
}
|
||||
const nativeChannelGroups = [];
|
||||
for (let i = 0; i < channelGroups.length; i++) {
|
||||
const channelGroup = channelGroups[i];
|
||||
if (!(channelGroup instanceof AndroidChannelGroup)) {
|
||||
throw new Error(
|
||||
`AndroidNotifications:createChannelGroups expects array items of type 'AndroidChannelGroup' but got type ${typeof channelGroup}`
|
||||
);
|
||||
}
|
||||
nativeChannelGroups.push(channelGroup.build());
|
||||
}
|
||||
return getNativeModule(this._notifications).createChannelGroups(
|
||||
nativeChannelGroups
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
createChannels(channels: AndroidChannel[]): Promise<void> {
|
||||
if (Platform.OS === 'android') {
|
||||
if (!Array.isArray(channels)) {
|
||||
throw new Error(
|
||||
`AndroidNotifications:createChannels expects an 'Array' but got type ${typeof channels}`
|
||||
);
|
||||
}
|
||||
const nativeChannels = [];
|
||||
for (let i = 0; i < channels.length; i++) {
|
||||
const channel = channels[i];
|
||||
if (!(channel instanceof AndroidChannel)) {
|
||||
throw new Error(
|
||||
`AndroidNotifications:createChannels expects array items of type 'AndroidChannel' but got type ${typeof channel}`
|
||||
);
|
||||
}
|
||||
nativeChannels.push(channel.build());
|
||||
}
|
||||
return getNativeModule(this._notifications).createChannels(
|
||||
nativeChannels
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
|
@ -1,18 +1,22 @@
|
|||
/**
|
||||
* @flow
|
||||
* Messaging (FCM) representation wrapper
|
||||
* Notifications representation wrapper
|
||||
*/
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { getLogger } from '../../utils/log';
|
||||
import ModuleBase from '../../utils/ModuleBase';
|
||||
import { getNativeModule } from '../../utils/native';
|
||||
import { isFunction, isObject } from '../../utils';
|
||||
import AndroidChannel from './AndroidChannel';
|
||||
import AndroidChannelGroup from './AndroidChannelGroup';
|
||||
import AndroidNotifications from './AndroidNotifications';
|
||||
import Notification from './Notification';
|
||||
import {
|
||||
BadgeIconType,
|
||||
Category,
|
||||
Defaults,
|
||||
GroupAlert,
|
||||
Importance,
|
||||
Priority,
|
||||
Visibility,
|
||||
} from './types';
|
||||
|
@ -64,6 +68,8 @@ export const NAMESPACE = 'notifications';
|
|||
* @class Notifications
|
||||
*/
|
||||
export default class Notifications extends ModuleBase {
|
||||
_android: AndroidNotifications;
|
||||
|
||||
constructor(app: App) {
|
||||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
|
@ -71,6 +77,7 @@ export default class Notifications extends ModuleBase {
|
|||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
this._android = new AndroidNotifications(this);
|
||||
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
|
@ -89,7 +96,7 @@ export default class Notifications extends ModuleBase {
|
|||
// public event name: onNotificationOpened
|
||||
'notifications_notification_opened',
|
||||
(notificationOpened: NativeNotificationOpened) => {
|
||||
SharedEventEmitter.emit('OnNotificationOpened', {
|
||||
SharedEventEmitter.emit('onNotificationOpened', {
|
||||
action: notificationOpened.action,
|
||||
notification: new Notification(notificationOpened.notification),
|
||||
});
|
||||
|
@ -109,6 +116,10 @@ export default class Notifications extends ModuleBase {
|
|||
);
|
||||
}
|
||||
|
||||
get android(): AndroidNotifications {
|
||||
return this._android;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all notifications
|
||||
*/
|
||||
|
@ -148,9 +159,11 @@ export default class Notifications extends ModuleBase {
|
|||
}
|
||||
|
||||
getInitialNotification(): Promise<Object> {
|
||||
return getNativeModule(this).getInitialNotification();
|
||||
// TODO
|
||||
// .then(notification => (notification ? new Notification(this, notification) : null));
|
||||
return getNativeModule(this)
|
||||
.getInitialNotification()
|
||||
.then(
|
||||
notification => (notification ? new Notification(notification) : null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,8 +291,11 @@ export const statics = {
|
|||
Android: {
|
||||
BadgeIconType,
|
||||
Category,
|
||||
Channel: AndroidChannel,
|
||||
ChannelGroup: AndroidChannelGroup,
|
||||
Defaults,
|
||||
GroupAlert,
|
||||
Importance,
|
||||
Priority,
|
||||
Visibility,
|
||||
},
|
||||
|
|
|
@ -39,6 +39,16 @@ export const GroupAlert = {
|
|||
Summary: 1,
|
||||
};
|
||||
|
||||
export const Importance = {
|
||||
Default: 3,
|
||||
High: 4,
|
||||
Low: 2,
|
||||
Max: 5,
|
||||
Min: 1,
|
||||
None: 3,
|
||||
Unspecified: -1000,
|
||||
};
|
||||
|
||||
export const Priority = {
|
||||
Default: 0,
|
||||
High: 1,
|
||||
|
@ -57,6 +67,7 @@ export type BadgeIconTypeType = $Values<typeof BadgeIconType>;
|
|||
export type CategoryType = $Values<typeof Category>;
|
||||
export type DefaultsType = $Values<typeof Defaults>;
|
||||
export type GroupAlertType = $Values<typeof GroupAlert>;
|
||||
export type ImportanceType = $Values<typeof Importance>;
|
||||
export type PriorityType = $Values<typeof Priority>;
|
||||
export type VisibilityType = $Values<typeof Visibility>;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import io.invertase.firebase.firestore.RNFirebaseFirestorePackage;
|
|||
import io.invertase.firebase.instanceid.RNFirebaseInstanceIdPackage;
|
||||
import io.invertase.firebase.links.RNFirebaseLinksPackage;
|
||||
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
|
||||
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
|
||||
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
|
||||
import io.invertase.firebase.storage.RNFirebaseStoragePackage;
|
||||
import com.oblador.vectoricons.VectorIconsPackage;
|
||||
|
@ -51,6 +52,7 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
new RNFirebaseInstanceIdPackage(),
|
||||
new RNFirebaseLinksPackage(),
|
||||
new RNFirebaseMessagingPackage(),
|
||||
new RNFirebaseNotificationsPackage(),
|
||||
new RNFirebasePerformancePackage(),
|
||||
new RNFirebaseStoragePackage()
|
||||
);
|
||||
|
|
|
@ -7,14 +7,6 @@ import DatabaseContents from './tests/support/DatabaseContents';
|
|||
RNfirebase.database.enableLogging(true);
|
||||
RNfirebase.firestore.enableLogging(true);
|
||||
|
||||
RNfirebase.messaging().onMessage(message => {
|
||||
console.log('got new message: ', message);
|
||||
});
|
||||
|
||||
RNfirebase.messaging().onTokenRefresh(token => {
|
||||
console.log('got new token: ', token);
|
||||
});
|
||||
|
||||
const init = async () => {
|
||||
try {
|
||||
await RNfirebase.messaging().requestPermission();
|
||||
|
@ -22,9 +14,47 @@ const init = async () => {
|
|||
console.log('instanceid: ', instanceid);
|
||||
const token = await RNfirebase.messaging().getToken();
|
||||
console.log('token: ', token);
|
||||
const initialMessage = await RNfirebase.messaging().getInitialMessage();
|
||||
console.log('initial message: ', initialMessage);
|
||||
const initialNotification = await RNfirebase.notifications().getInitialNotification();
|
||||
console.log('initialNotification: ', initialNotification);
|
||||
|
||||
RNfirebase.messaging().onMessage(message => {
|
||||
console.log('onMessage: ', message);
|
||||
});
|
||||
RNfirebase.messaging().onTokenRefresh(deviceToken => {
|
||||
dispatch(fcmTokenReceived(deviceToken));
|
||||
});
|
||||
RNfirebase.notifications().onNotification(notification => {
|
||||
console.log('onNotification: ', notification);
|
||||
});
|
||||
RNfirebase.notifications().onNotificationOpened(notification => {
|
||||
console.log('onNotificationOpened: ', notification);
|
||||
});
|
||||
RNfirebase.notifications().onNotificationDisplayed(notification => {
|
||||
console.log('onNotificationDisplayed: ', notification);
|
||||
});
|
||||
// RNfirebase.instanceid().delete();
|
||||
const channel = new RNfirebase.notifications.Android.Channel();
|
||||
channel
|
||||
.setChannelId('test')
|
||||
.setName('test')
|
||||
.setImportance(RNfirebase.notifications.Android.Importance.Max)
|
||||
.setDescription('test channel');
|
||||
RNfirebase.notifications().android.createChannel(channel);
|
||||
|
||||
const notification = new RNfirebase.notifications.Notification();
|
||||
notification
|
||||
.setTitle('Test title')
|
||||
.setBody('Test body')
|
||||
.android.setChannelId('test')
|
||||
.android.setPriority(RNfirebase.notifications.Android.Priority.Max);
|
||||
const date = new Date();
|
||||
date.setMinutes(date.getMinutes() + 1);
|
||||
setTimeout(() => {
|
||||
RNfirebase.notifications().displayNotification(notification);
|
||||
}, 5);
|
||||
RNfirebase.notifications().scheduleNotification(notification, {
|
||||
fireDate: date.getTime(),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('messaging init error:', error);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue