[notifications] Fix some android issues with local notifications
This commit is contained in:
parent
aa367e7be8
commit
57ffa9bd3e
|
@ -1,5 +1,7 @@
|
|||
package io.invertase.firebase;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -522,4 +524,26 @@ public class Utils {
|
|||
}
|
||||
return deconstructedList;
|
||||
}
|
||||
|
||||
public static boolean isAppInForeground(Context context) {
|
||||
/**
|
||||
We need to check if app is in foreground otherwise the app will crash.
|
||||
http://stackoverflow.com/questions/8489993/check-android-application-is-in-foreground-or-not
|
||||
**/
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningAppProcessInfo> appProcesses =
|
||||
activityManager.getRunningAppProcesses();
|
||||
if (appProcesses == null) {
|
||||
return false;
|
||||
}
|
||||
final String packageName = context.getPackageName();
|
||||
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
|
||||
if (appProcess.importance ==
|
||||
ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
|
||||
appProcess.processName.equals(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.util.Log;
|
|||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
|
@ -36,6 +37,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.Utils;
|
||||
import io.invertase.firebase.messaging.BundleJSONConverter;
|
||||
|
||||
public class RNFirebaseNotificationManager {
|
||||
|
@ -44,10 +46,15 @@ public class RNFirebaseNotificationManager {
|
|||
private static final String TAG = "RNFNotificationManager";
|
||||
private AlarmManager alarmManager;
|
||||
private Context context;
|
||||
private boolean isForeground = false;
|
||||
private ReactApplicationContext reactContext;
|
||||
private NotificationManager notificationManager;
|
||||
private SharedPreferences preferences;
|
||||
|
||||
public RNFirebaseNotificationManager(ReactApplicationContext reactContext) {
|
||||
this(reactContext.getApplicationContext());
|
||||
this.reactContext = reactContext;
|
||||
}
|
||||
|
||||
public RNFirebaseNotificationManager(Context context) {
|
||||
this.alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
this.context = context;
|
||||
|
@ -117,11 +124,6 @@ public class RNFirebaseNotificationManager {
|
|||
}
|
||||
|
||||
public void displayScheduledNotification(Bundle notification) {
|
||||
// Broadcast the notification to the RN Application
|
||||
Intent scheduledNotificationEvent = new Intent(SCHEDULED_NOTIFICATION_EVENT);
|
||||
scheduledNotificationEvent.putExtra("notification", notification);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(scheduledNotificationEvent);
|
||||
|
||||
// If this isn't a repeated notification, clear it from the scheduled notifications list
|
||||
if (!notification.getBundle("schedule").containsKey("repeated")
|
||||
|| !notification.getBundle("schedule").getBoolean("repeated")) {
|
||||
|
@ -129,9 +131,14 @@ public class RNFirebaseNotificationManager {
|
|||
preferences.edit().remove(notificationId).apply();;
|
||||
}
|
||||
|
||||
// If the app isn't in the foreground, then we display it
|
||||
// Otherwise, it is up to the JS to decide whether to send the notification
|
||||
if (!isForeground) {
|
||||
if (Utils.isAppInForeground(context)) {
|
||||
// If the app is in the foregound, broadcast the notification to the RN Application
|
||||
// It is up to the JS to decide whether to display the notification
|
||||
Intent scheduledNotificationEvent = new Intent(SCHEDULED_NOTIFICATION_EVENT);
|
||||
scheduledNotificationEvent.putExtra("notification", notification);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(scheduledNotificationEvent);
|
||||
} else {
|
||||
// If the app is in the background, then we display it automatically
|
||||
displayNotification(notification, null);
|
||||
}
|
||||
}
|
||||
|
@ -175,10 +182,6 @@ public class RNFirebaseNotificationManager {
|
|||
scheduleNotification(notificationBundle, promise);
|
||||
}
|
||||
|
||||
public void setIsForeground(boolean isForeground) {
|
||||
this.isForeground = isForeground;
|
||||
}
|
||||
|
||||
private void cancelAlarm(String notificationId) {
|
||||
Intent notificationIntent = new Intent(context, RNFirebaseNotificationManager.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId.hashCode(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
@ -201,7 +204,6 @@ public class RNFirebaseNotificationManager {
|
|||
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 >= Build.VERSION_CODES.O) {
|
||||
nb = new NotificationCompat.Builder(context, channelId);
|
||||
} else {
|
||||
|
@ -343,20 +345,27 @@ public class RNFirebaseNotificationManager {
|
|||
nb = nb.setTicker(android.getString("ticker"));
|
||||
}
|
||||
if (android.containsKey("timeoutAfter")) {
|
||||
nb = nb.setTimeoutAfter(android.getLong("timeoutAfter"));
|
||||
Double timeoutAfter = android.getDouble("timeoutAfter");
|
||||
nb = nb.setTimeoutAfter(timeoutAfter.longValue());
|
||||
}
|
||||
if (android.containsKey("usesChronometer")) {
|
||||
nb = nb.setUsesChronometer(android.getBoolean("usesChronometer"));
|
||||
}
|
||||
if (android.containsKey("vibrate")) {
|
||||
nb = nb.setVibrate(android.getLongArray("vibrate"));
|
||||
double[] vibrate = android.getDoubleArray("vibrate");
|
||||
long[] vibrateArray = new long[vibrate.length];
|
||||
for (int i = 0; i < vibrate.length; i++) {
|
||||
vibrateArray[i] = ((Double)vibrate[i]).longValue();
|
||||
}
|
||||
nb = nb.setVibrate(vibrateArray);
|
||||
}
|
||||
if (android.containsKey("visibility")) {
|
||||
Double visibility = android.getDouble("visibility");
|
||||
nb = nb.setVisibility(visibility.intValue());
|
||||
}
|
||||
if (android.containsKey("when")) {
|
||||
nb = nb.setWhen(android.getLong("when"));
|
||||
Double when = android.getDouble("when");
|
||||
nb = nb.setWhen(when.longValue());
|
||||
}
|
||||
|
||||
// TODO: Big text / Big picture
|
||||
|
@ -393,6 +402,10 @@ public class RNFirebaseNotificationManager {
|
|||
// Build the notification and send it
|
||||
Notification builtNotification = nb.build();
|
||||
notificationManager.notify(notificationId.hashCode(), builtNotification);
|
||||
|
||||
if (reactContext != null) {
|
||||
Utils.sendEvent(reactContext, "notifications_notification_displayed", Arguments.fromBundle(notification));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (promise == null) {
|
||||
Log.e(TAG, "Failed to send notification", e);
|
||||
|
@ -525,7 +538,7 @@ public class RNFirebaseNotificationManager {
|
|||
String notificationId = notification.getString("notificationId");
|
||||
Bundle schedule = notification.getBundle("schedule");
|
||||
|
||||
long fireDate = schedule.getLong("fireDate");
|
||||
Double fireDate = schedule.getDouble("fireDate");
|
||||
|
||||
// Scheduled alarms are cleared on restart
|
||||
// We store them so that they can be re-scheduled when the phone restarts in RNFirebaseNotificationsRebootReceiver
|
||||
|
@ -567,14 +580,14 @@ public class RNFirebaseNotificationManager {
|
|||
return;
|
||||
}
|
||||
|
||||
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, fireDate, interval, pendingIntent);
|
||||
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, fireDate.longValue(), interval, pendingIntent);
|
||||
} else {
|
||||
if (schedule.containsKey("exact")
|
||||
&& schedule.getBoolean("exact")
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, fireDate.longValue(), pendingIntent);
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, fireDate.longValue(), pendingIntent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import io.invertase.firebase.Utils;
|
|||
import io.invertase.firebase.messaging.RNFirebaseMessagingService;
|
||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
|
||||
public class RNFirebaseNotifications extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
|
||||
public class RNFirebaseNotifications extends ReactContextBaseJavaModule implements ActivityEventListener {
|
||||
private static final String BADGE_FILE = "BadgeCountFile";
|
||||
private static final String BADGE_KEY = "BadgeCount";
|
||||
private static final String TAG = "RNFirebaseNotifications";
|
||||
|
@ -41,9 +41,8 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
|
|||
public RNFirebaseNotifications(ReactApplicationContext context) {
|
||||
super(context);
|
||||
context.addActivityEventListener(this);
|
||||
context.addLifecycleEventListener(this);
|
||||
|
||||
notificationManager = new RNFirebaseNotificationManager(context.getApplicationContext());
|
||||
notificationManager = new RNFirebaseNotificationManager(context);
|
||||
sharedPreferences = context.getSharedPreferences(BADGE_FILE, Context.MODE_PRIVATE);
|
||||
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
|
||||
|
@ -86,13 +85,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
|
|||
|
||||
@ReactMethod
|
||||
public void getInitialNotification(Promise promise) {
|
||||
// TODO
|
||||
if (getCurrentActivity() == null) {
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
WritableMap notificationOpenMap = parseIntentForRemoteNotification(getCurrentActivity().getIntent());
|
||||
promise.resolve(notificationOpenMap);
|
||||
WritableMap notificationOpenMap = null;
|
||||
if (getCurrentActivity() != null) {
|
||||
notificationOpenMap = parseIntentForNotification(getCurrentActivity().getIntent());
|
||||
}
|
||||
promise.resolve(notificationOpenMap);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
|
@ -173,37 +170,36 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen
|
|||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
WritableMap notificationOpenMap = parseIntentForRemoteNotification(intent);
|
||||
WritableMap notificationOpenMap = parseIntentForNotification(intent);
|
||||
if (notificationOpenMap != null) {
|
||||
Log.d(TAG, "onNewIntent called with new remote notification");
|
||||
Utils.sendEvent(getReactApplicationContext(), "notifications_notification_opened", notificationOpenMap);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// End ActivityEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Start LifecycleEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
notificationManager.setIsForeground(true);
|
||||
private WritableMap parseIntentForNotification(Intent intent) {
|
||||
WritableMap notificationOpenMap = parseIntentForRemoteNotification(intent);
|
||||
if (notificationOpenMap == null) {
|
||||
notificationOpenMap = parseIntentForLocalNotification(intent);
|
||||
}
|
||||
return notificationOpenMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
notificationManager.setIsForeground(false);
|
||||
private WritableMap parseIntentForLocalNotification(Intent intent) {
|
||||
if (intent.getExtras() == null || !intent.hasExtra("notificationId")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostDestroy() {
|
||||
// Do nothing
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// End LifecycleEventListener methods
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
WritableMap notificationMap = Arguments.makeNativeMap(intent.getExtras());
|
||||
WritableMap notificationOpenMap = Arguments.createMap();
|
||||
notificationOpenMap.putString("action", intent.getAction());
|
||||
notificationOpenMap.putMap("notification", notificationMap);
|
||||
|
||||
return notificationOpenMap;
|
||||
}
|
||||
|
||||
private WritableMap parseIntentForRemoteNotification(Intent intent) {
|
||||
// Check if FCM data exists
|
||||
|
|
|
@ -293,6 +293,16 @@ export default class AndroidNotification {
|
|||
return this._notification;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param clickAction
|
||||
* @returns {Notification}
|
||||
*/
|
||||
setClickAction(clickAction: string): Notification {
|
||||
this._clickAction = clickAction;
|
||||
return this._notification;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param color
|
||||
|
|
|
@ -38,7 +38,7 @@ type OnNotificationObserver = {
|
|||
type OnNotificationOpened = NotificationOpen => any;
|
||||
|
||||
type OnNotificationOpenedObserver = {
|
||||
next: OnNotificationOpen,
|
||||
next: NotificationOpen,
|
||||
};
|
||||
|
||||
const NATIVE_EVENTS = [
|
||||
|
@ -158,12 +158,18 @@ export default class Notifications extends ModuleBase {
|
|||
return getNativeModule(this).getBadge();
|
||||
}
|
||||
|
||||
getInitialNotification(): Promise<Object> {
|
||||
getInitialNotification(): Promise<NotificationOpen> {
|
||||
return getNativeModule(this)
|
||||
.getInitialNotification()
|
||||
.then(
|
||||
notification => (notification ? new Notification(notification) : null)
|
||||
);
|
||||
.then((notificationOpen: NativeNotificationOpen) => {
|
||||
if (notificationOpen) {
|
||||
return {
|
||||
action: notificationOpen.action,
|
||||
notification: new Notification(notificationOpen.notification),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,16 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<receiver android:name="io.invertase.firebase.notifications.RNFirebaseNotificationReceiver"/>
|
||||
<receiver android:enabled="true" android:exported="true" android:name="io.invertase.firebase.notifications.RNFirebaseNotificationsRebootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
|
||||
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
|
|
|
@ -45,16 +45,19 @@ const init = async () => {
|
|||
notification
|
||||
.setTitle('Test title')
|
||||
.setBody('Test body')
|
||||
.setNotificationId('displayed')
|
||||
.android.setChannelId('test')
|
||||
.android.setClickAction('action')
|
||||
.android.setPriority(RNfirebase.notifications.Android.Priority.Max);
|
||||
const date = new Date();
|
||||
date.setMinutes(date.getMinutes() + 1);
|
||||
setTimeout(() => {
|
||||
RNfirebase.notifications().displayNotification(notification);
|
||||
}, 5);
|
||||
notification.setNotificationId('scheduled');
|
||||
RNfirebase.notifications().scheduleNotification(notification, {
|
||||
fireDate: date.getTime(),
|
||||
});
|
||||
}, 5);
|
||||
} catch (error) {
|
||||
console.error('messaging init error:', error);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue