I just built a native module for emitting an event to React Native, the desired affect is taking push notifications that are sent through Braze, peeling the deep links from them in react native to route my application appropriately. This works perfect if the app is backgrounded, but if it's closed, it will result in a crash with the following error in Logcat:
10-02 15:11:34.888 20942-20942/com.my.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.my.app, PID: 20942
java.lang.RuntimeException: Unable to start receiver com.my.app.AppboyBroadcastReceiver: java.lang.NullPointerException: Attempt to invoke virtual method 'com.facebook.react.bridge.JavaScriptModule com.facebook.react.bridge.ReactApplicationContext.getJSModule(java.lang.Class)' on a null object reference
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3259)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1677)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'com.facebook.react.bridge.JavaScriptModule com.facebook.react.bridge.ReactApplicationContext.getJSModule(java.lang.Class)' on a null object reference
at com.my.app.AppboyNotification.sendEvent(AppboyNotification.java:36)
at com.my.app.AppboyBroadcastReceiver.onReceive(AppboyBroadcastReceiver.java:42)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3252)
I'm assuming this is caused because the app hasn't properly started yet and it's already trying to fire things it shouldn't. My broadcast receiver looks like this, where notificationOpenedAction.equals(action)
is called:
public class AppboyBroadcastReceiver extends BroadcastReceiver{
private static final String TAG = AppboyLogger.getAppboyLogTag(AppboyBroadcastReceiver.class);
@Override
public void onReceive(Context context, Intent intent) {
String packageName = context.getPackageName();
String pushReceivedAction = packageName + AppboyNotificationUtils.APPBOY_NOTIFICATION_RECEIVED_SUFFIX;
String notificationOpenedAction = packageName + AppboyNotificationUtils.APPBOY_NOTIFICATION_OPENED_SUFFIX;
String notificationDeletedAction = packageName + AppboyNotificationUtils.APPBOY_NOTIFICATION_DELETED_SUFFIX;
String action = intent.getAction();
Log.d(TAG, String.format("Received intent with action %s", action));
logNotificationDuration(intent);
if (pushReceivedAction.equals(action)) {
Log.d(TAG, "Received push notification.");
} else if (notificationOpenedAction.equals(action)) {
String deepLink = intent.getStringExtra(Constants.APPBOY_PUSH_DEEP_LINK_KEY);
WritableNativeMap params = new WritableNativeMap();
params.putString("appboyDeeplink", deepLink);
Log.d(TAG, "Received push open action notification.");
Log.d(TAG, String.format("DeeplinkData: %s", deepLink));
AppboyNotification.sendEvent("appboyNotificationReceived", params);
} else if (notificationDeletedAction.equals(action)) {
Log.d(TAG, "Received push notification deleted intent.");
} else {
Log.d(TAG, String.format("Ignoring intent with unsupported action %s", action));
}
}
My ActivityEventListener is as follows:
public class AppboyNotification extends ReactContextBaseJavaModule implements ActivityEventListener{
private static final String TAG = "AppboyMessaging";
private static ReactApplicationContext reactContext;
private String thisApp;
public AppboyNotification(ReactApplicationContext reactContext){
super(reactContext);
this.reactContext = reactContext;
Log.d(TAG, String.format("React_context %s", reactContext));
reactContext.addActivityEventListener(this);
thisApp = reactContext.getPackageName();
}
@Override
public String getName() {
return TAG;
}
public static void sendEvent(String event, WritableNativeMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(event, params);
}
@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {}
@Override
public void onNewIntent(Intent intent){}
}
And my Package file:
public class AppboyMessaging implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AppboyNotification(reactContext));
return modules;
}
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
is there some way I can avoid this error, and handle this gracefully so when I open from a push notification, I still get the data I need to?