Merge pull request #1074 from dluksza/android-notification-action-background-handler

Implement handling of Android actions in background
This commit is contained in:
Chris Bianca 2018-05-16 10:39:18 +01:00 committed by GitHub
commit 640d7aa7ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 3 deletions

View File

@ -294,9 +294,11 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
} }
private NotificationCompat.Action createAction(Bundle action, Class intentClass, Bundle notification) { private NotificationCompat.Action createAction(Bundle action, Class intentClass, Bundle notification) {
boolean runInBackground = action.containsKey("runInBackground") && action.getBoolean("runInBackground");
String actionKey = action.getString("action"); String actionKey = action.getString("action");
PendingIntent actionIntent = createIntent(intentClass, notification, actionKey); PendingIntent actionIntent = runInBackground ?
createBroadcastIntent(notification, actionKey) :
createIntent(intentClass, notification, actionKey);
int icon = getIcon(action.getString("icon")); int icon = getIcon(action.getString("icon"));
String title = action.getString("title"); String title = action.getString("title");
@ -334,10 +336,21 @@ public class DisplayNotificationTask extends AsyncTask<Void, Void, Void> {
} }
String notificationId = notification.getString("notificationId"); String notificationId = notification.getString("notificationId");
return PendingIntent.getActivity(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT); return PendingIntent.getActivity(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
} }
private PendingIntent createBroadcastIntent(Bundle notification, String action) {
Intent intent = new Intent(context, RNFirebaseBackgroundNotificationActionReceiver.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
String notificationId = notification.getString("notificationId") + action;
intent.setAction("io.invertase.firebase.notifications.BackgroundAction");
intent.putExtra("action", action);
intent.putExtra("notification", notification);
return PendingIntent.getBroadcast(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private RemoteInput createRemoteInput(Bundle remoteInput) { private RemoteInput createRemoteInput(Bundle remoteInput) {
String resultKey = remoteInput.getString("resultKey"); String resultKey = remoteInput.getString("resultKey");

View File

@ -0,0 +1,50 @@
package io.invertase.firebase.notifications;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.ReactApplication;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import io.invertase.firebase.Utils;
public class RNFirebaseBackgroundNotificationActionReceiver extends BroadcastReceiver {
static boolean isBackgroundNotficationIntent(Intent intent) {
return intent.getExtras() != null && intent.hasExtra("action") && intent.hasExtra("notification");
}
static WritableMap toNotificationOpenMap(Intent intent) {
Bundle extras = intent.getExtras();
WritableMap notificationMap = Arguments.makeNativeMap(extras.getBundle("notification"));
WritableMap notificationOpenMap = Arguments.createMap();
notificationOpenMap.putString("action", extras.getString("action"));
notificationOpenMap.putMap("notification", notificationMap);
return notificationOpenMap;
}
@Override
public void onReceive(Context context, Intent intent) {
if (!isBackgroundNotficationIntent(intent)) {
return;
}
if (Utils.isAppInForeground(context)) {
WritableMap notificationOpenMap = toNotificationOpenMap(intent);
ReactApplication reactApplication = (ReactApplication)context.getApplicationContext();
ReactContext reactContext = reactApplication.getReactNativeHost().getReactInstanceManager().getCurrentReactContext();
Utils.sendEvent(reactContext, "notifications_notification_opened", notificationOpenMap);
} else {
Intent serviceIntent = new Intent(context, RNFirebaseBackgroundNotificationActionsService.class);
serviceIntent.putExtras(intent.getExtras());
context.startService(serviceIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
}
}
}

View File

@ -0,0 +1,29 @@
package io.invertase.firebase.notifications;
import android.content.Intent;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
import javax.annotation.Nullable;
import static io.invertase.firebase.notifications.RNFirebaseBackgroundNotificationActionReceiver.isBackgroundNotficationIntent;
import static io.invertase.firebase.notifications.RNFirebaseBackgroundNotificationActionReceiver.toNotificationOpenMap;
public class RNFirebaseBackgroundNotificationActionsService extends HeadlessJsTaskService {
@Override
protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
if (isBackgroundNotficationIntent(intent)) {
WritableMap notificationOpenMap = toNotificationOpenMap(intent);
return new HeadlessJsTaskConfig(
"RNFirebaseBackgroundNotificationAction",
notificationOpenMap,
60000,
true
);
}
return null;
}
}

2
lib/index.d.ts vendored
View File

@ -1277,6 +1277,7 @@ declare module 'react-native-firebase' {
semanticAction?: SemanticAction; semanticAction?: SemanticAction;
showUserInterface?: boolean; showUserInterface?: boolean;
title: string; title: string;
runInBackground?: boolean;
constructor(action: string, icon: string, title: string); constructor(action: string, icon: string, title: string);
@ -1284,6 +1285,7 @@ declare module 'react-native-firebase' {
setAllowGenerateReplies(allowGeneratedReplies: boolean): Action; setAllowGenerateReplies(allowGeneratedReplies: boolean): Action;
setSemanticAction(semanticAction: SemanticAction): Action; setSemanticAction(semanticAction: SemanticAction): Action;
setShowUserInterface(showUserInterface: boolean): Action; setShowUserInterface(showUserInterface: boolean): Action;
setRunInBackground(runInBackground: boolean): Action;
} }
class RemoteInput { class RemoteInput {

View File

@ -16,6 +16,7 @@ export default class AndroidAction {
_semanticAction: SemanticActionType | void; _semanticAction: SemanticActionType | void;
_showUserInterface: boolean | void; _showUserInterface: boolean | void;
_title: string; _title: string;
_runInBackground: boolean | void;
constructor(action: string, icon: string, title: string) { constructor(action: string, icon: string, title: string) {
this._action = action; this._action = action;
@ -52,6 +53,10 @@ export default class AndroidAction {
return this._title; return this._title;
} }
get runInBackground(): ?boolean {
return this._runInBackground;
}
/** /**
* *
* @param remoteInput * @param remoteInput
@ -102,6 +107,16 @@ export default class AndroidAction {
return this; return this;
} }
/**
*
* @param runInBackground
* @returns {AndroidAction}
*/
setRunInBackground(runInBackground: boolean): AndroidAction {
this._runInBackground = runInBackground
return this;
}
build(): NativeAndroidAction { build(): NativeAndroidAction {
if (!this._action) { if (!this._action) {
throw new Error('AndroidAction: Missing required `action` property'); throw new Error('AndroidAction: Missing required `action` property');
@ -119,6 +134,7 @@ export default class AndroidAction {
semanticAction: this._semanticAction, semanticAction: this._semanticAction,
showUserInterface: this._showUserInterface, showUserInterface: this._showUserInterface,
title: this._title, title: this._title,
runInBackground: this._runInBackground
}; };
} }
} }
@ -145,6 +161,9 @@ export const fromNativeAndroidAction = (
if (nativeAction.showUserInterface) { if (nativeAction.showUserInterface) {
action.setShowUserInterface(nativeAction.showUserInterface); action.setShowUserInterface(nativeAction.showUserInterface);
} }
if (nativeAction.runInBackground) {
action.setRunInBackground(nativeAction.runInBackground);
}
return action; return action;
}; };

View File

@ -136,6 +136,7 @@ export type NativeAndroidAction = {|
semanticAction?: SemanticActionType, semanticAction?: SemanticActionType,
showUserInterface?: boolean, showUserInterface?: boolean,
title: string, title: string,
runInBackground?: boolean,
|}; |};
export type NativeAndroidNotification = {| export type NativeAndroidNotification = {|