package com.evollu.react.fcm; import android.app.Activity; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Intent; import android.content.IntentFilter; 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.ReadableMap; import com.facebook.react.bridge.ReadableMapKeySetIterator; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; 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 android.app.Application; import android.os.Build; import android.os.Bundle; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.content.Context; import java.io.IOException; import java.util.ArrayList; import java.util.Map; import java.util.Set; import java.util.UUID; import com.google.firebase.FirebaseApp; import static android.content.Context.NOTIFICATION_SERVICE; public class FIRMessagingModule extends ReactContextBaseJavaModule implements LifecycleEventListener, ActivityEventListener { private final static String TAG = FIRMessagingModule.class.getCanonicalName(); private FIRLocalMessagingHelper mFIRLocalMessagingHelper; private BadgeHelper mBadgeHelper; public FIRMessagingModule(ReactApplicationContext reactContext) { super(reactContext); mFIRLocalMessagingHelper = new FIRLocalMessagingHelper((Application) reactContext.getApplicationContext()); mBadgeHelper = new BadgeHelper(reactContext.getApplicationContext()); getReactApplicationContext().addLifecycleEventListener(this); getReactApplicationContext().addActivityEventListener(this); registerTokenRefreshHandler(); registerMessageHandler(); registerLocalMessageHandler(); } @Override public String getName() { return "RNFIRMessaging"; } @ReactMethod public void getInitialNotification(Promise promise){ Activity activity = getCurrentActivity(); if(activity == null){ promise.resolve(null); return; } promise.resolve(parseIntent(activity.getIntent())); } @ReactMethod public void requestPermissions(Promise promise){ if(NotificationManagerCompat.from(getReactApplicationContext()).areNotificationsEnabled()){ promise.resolve(true); } else { promise.reject(null, "Notification disabled"); } } @ReactMethod public void createNotificationChannel(ReadableMap details, Promise promise){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager mngr = (NotificationManager) getReactApplicationContext().getSystemService(NOTIFICATION_SERVICE); String id = details.getString("id"); String name = details.getString("name"); String priority = details.getString("priority"); int importance; switch(priority) { case "min": importance = NotificationManager.IMPORTANCE_MIN; break; case "low": importance = NotificationManager.IMPORTANCE_LOW; break; case "high": importance = NotificationManager.IMPORTANCE_HIGH; break; case "max": importance = NotificationManager.IMPORTANCE_MAX; break; default: importance = NotificationManager.IMPORTANCE_DEFAULT; } if (mngr.getNotificationChannel(id) != null) { promise.resolve(null); return; } // NotificationChannel channel = new NotificationChannel( id, name, importance); // Configure the notification channel. if(details.hasKey("description")){ channel.setDescription(details.getString("description")); } mngr.createNotificationChannel(channel); } promise.resolve(null); } @ReactMethod public void deleteNotificationChannel(String id, Promise promise) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager mngr = (NotificationManager) getReactApplicationContext().getSystemService(NOTIFICATION_SERVICE); mngr.deleteNotificationChannel(id); } promise.resolve(null); } @ReactMethod public void getFCMToken(Promise promise) { try { Log.d(TAG, "Firebase token: " + FirebaseInstanceId.getInstance().getToken()); promise.resolve(FirebaseInstanceId.getInstance().getToken()); } catch (Throwable e) { e.printStackTrace(); promise.reject(null,e.getMessage()); } } @ReactMethod public void getEntityFCMToken(Promise promise) { try { String senderId = FirebaseApp.getInstance().getOptions().getGcmSenderId(); String token = FirebaseInstanceId.getInstance().getToken(senderId, "FCM"); Log.d(TAG, "Firebase token: " + token); promise.resolve(token); } catch (Throwable e) { e.printStackTrace(); promise.reject(null,e.getMessage()); } } @ReactMethod public void deleteEntityFCMToken(Promise promise) { try { String senderId = FirebaseApp.getInstance().getOptions().getGcmSenderId(); FirebaseInstanceId.getInstance().deleteToken(senderId, "FCM"); promise.resolve(null); } catch (Throwable e) { e.printStackTrace(); promise.reject(null,e.getMessage()); } } @ReactMethod public void deleteInstanceId(Promise promise){ try { FirebaseInstanceId.getInstance().deleteInstanceId(); promise.resolve(null); } catch (Exception e) { e.printStackTrace(); promise.reject(null,e.getMessage()); } } @ReactMethod public void presentLocalNotification(ReadableMap details) { Bundle bundle = Arguments.toBundle(details); mFIRLocalMessagingHelper.sendNotification(bundle); } @ReactMethod public void scheduleLocalNotification(ReadableMap details) { Bundle bundle = Arguments.toBundle(details); mFIRLocalMessagingHelper.sendNotificationScheduled(bundle); } @ReactMethod public void cancelLocalNotification(String notificationID) { mFIRLocalMessagingHelper.cancelLocalNotification(notificationID); } @ReactMethod public void cancelAllLocalNotifications() { mFIRLocalMessagingHelper.cancelAllLocalNotifications(); } @ReactMethod public void removeDeliveredNotification(String notificationID) { mFIRLocalMessagingHelper.removeDeliveredNotification(notificationID); } @ReactMethod public void removeAllDeliveredNotifications(){ mFIRLocalMessagingHelper.removeAllDeliveredNotifications(); } @ReactMethod public void subscribeToTopic(String topic, Promise promise){ try { FirebaseMessaging.getInstance().subscribeToTopic(topic); promise.resolve(null); } catch (Exception e) { e.printStackTrace(); promise.reject(null,e.getMessage()); } } @ReactMethod public void unsubscribeFromTopic(String topic, Promise promise){ try { FirebaseMessaging.getInstance().unsubscribeFromTopic(topic); promise.resolve(null); } catch (Exception e) { e.printStackTrace(); promise.reject(null,e.getMessage()); } } @ReactMethod public void getScheduledLocalNotifications(Promise promise){ ArrayList<Bundle> bundles = mFIRLocalMessagingHelper.getScheduledLocalNotifications(); WritableArray array = Arguments.createArray(); for(Bundle bundle:bundles){ array.pushMap(Arguments.fromBundle(bundle)); } promise.resolve(array); } @ReactMethod public void setBadgeNumber(int badgeNumber) { mBadgeHelper.setBadgeCount(badgeNumber); } @ReactMethod public void getBadgeNumber(Promise promise) { promise.resolve(mBadgeHelper.getBadgeCount()); } private void sendEvent(String eventName, Object params) { getReactApplicationContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params); } private void registerTokenRefreshHandler() { IntentFilter intentFilter = new IntentFilter("com.evollu.react.fcm.FCMRefreshToken"); LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (getReactApplicationContext().hasActiveCatalystInstance()) { String token = intent.getStringExtra("token"); sendEvent("FCMTokenRefreshed", token); } } }, intentFilter); } @ReactMethod public void send(String senderId, ReadableMap payload) throws Exception { FirebaseMessaging fm = FirebaseMessaging.getInstance(); RemoteMessage.Builder message = new RemoteMessage.Builder(senderId + "@gcm.googleapis.com") .setMessageId(UUID.randomUUID().toString()); ReadableMapKeySetIterator iterator = payload.keySetIterator(); while (iterator.hasNextKey()) { String key = iterator.nextKey(); String value = getStringFromReadableMap(payload, key); message.addData(key, value); } fm.send(message.build()); } private String getStringFromReadableMap(ReadableMap map, String key) throws Exception { switch (map.getType(key)) { case String: return map.getString(key); case Number: try { return String.valueOf(map.getInt(key)); } catch (Exception e) { return String.valueOf(map.getDouble(key)); } case Boolean: return String.valueOf(map.getBoolean(key)); default: throw new Exception("Unknown data type: " + map.getType(key).name() + " for message key " + key ); } } private void registerMessageHandler() { IntentFilter intentFilter = new IntentFilter("com.evollu.react.fcm.ReceiveNotification"); LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (getReactApplicationContext().hasActiveCatalystInstance()) { RemoteMessage message = intent.getParcelableExtra("data"); WritableMap params = Arguments.createMap(); WritableMap fcmData = Arguments.createMap(); if (message.getNotification() != null) { Notification notification = message.getNotification(); fcmData.putString("title", notification.getTitle()); fcmData.putString("body", notification.getBody()); fcmData.putString("color", notification.getColor()); fcmData.putString("icon", notification.getIcon()); fcmData.putString("tag", notification.getTag()); fcmData.putString("action", notification.getClickAction()); } params.putMap("fcm", fcmData); params.putString("collapse_key", message.getCollapseKey()); params.putString("from", message.getFrom()); params.putString("google.message_id", message.getMessageId()); params.putDouble("google.sent_time", message.getSentTime()); if(message.getData() != null){ Map<String, String> data = message.getData(); Set<String> keysIterator = data.keySet(); for(String key: keysIterator){ params.putString(key, data.get(key)); } } sendEvent("FCMNotificationReceived", params); } } }, intentFilter); } private void registerLocalMessageHandler() { IntentFilter intentFilter = new IntentFilter("com.evollu.react.fcm.ReceiveLocalNotification"); LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (getReactApplicationContext().hasActiveCatalystInstance()) { sendEvent("FCMNotificationReceived", Arguments.fromBundle(intent.getExtras())); } } }, intentFilter); } private WritableMap parseIntent(Intent intent){ WritableMap params; Bundle extras = intent.getExtras(); if (extras != null) { try { params = Arguments.fromBundle(extras); } catch (Exception e){ Log.e(TAG, e.getMessage()); params = Arguments.createMap(); } } else { params = Arguments.createMap(); } WritableMap fcm = Arguments.createMap(); fcm.putString("action", intent.getAction()); params.putMap("fcm", fcm); params.putInt("opened_from_tray", 1); return params; } @Override public void onHostResume() { mFIRLocalMessagingHelper.setApplicationForeground(true); } @Override public void onHostPause() { mFIRLocalMessagingHelper.setApplicationForeground(false); } @Override public void onHostDestroy() { } @Override public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { } @Override public void onNewIntent(Intent intent){ sendEvent("FCMNotificationReceived", parseIntent(intent)); } }