Trying to migrate from Parse to OneSignal and I am stuck on how to start a new Activity after the user clicks on a push notification. My handler is working, the log shows the text, the issue seems to be how to gain access to the application context from within my push opened handler. The example code is vague, getApplicationContext()
does not work without first doing something else.
One post I came upon, unrelated to OneSignal, suggests extending the Application class to gain access to the application context. This did not produce any syntax errors but my app crashes.
Code:
package com.linkedresponder.onesignal;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import com.onesignal.OSNotificationAction;
import com.onesignal.OSNotificationOpenResult;
import com.onesignal.OneSignal;
import org.json.JSONObject;
class NotificationOpenHandler extends Application implements OneSignal.NotificationOpenedHandler {
// This fires when a notification is opened by tapping on it.
private Context mContext;
@Override
public void onCreate() {
this.mContext = getApplicationContext();
}
@Override
public void notificationOpened(OSNotificationOpenResult result) {
OSNotificationAction.ActionType actionType = result.action.type;
JSONObject data = result.notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("customkey", null);
if (customKey != null) {
Log.i("OneSignalExample", "customkey set with value: " + customKey);
} else {
Log.i("OneSignalExample", "No data");
}
}
if (actionType == OSNotificationAction.ActionType.ActionTaken)
Log.i("OneSignalExample", "Button pressed with id: " + result.action.actionID);
Intent intent = new Intent(mContext, PushClicked.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Error:
er.onesignal E/AndroidRuntime: FATAL EXCEPTION: main Process: com.linkedresponder.onesignal, PID: 5680
java.lang.RuntimeException: Unable to start receiver com.onesignal.NotificationOpenedReceiver: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3018)
at android.app.ActivityThread.-wrap18(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1544)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.content.ComponentName.<init>(ComponentName.java:128)
at android.content.Intent.<init>(Intent.java:4868)
at com.linkedresponder.onesignal.NotificationOpenHandler.notificationOpened(NotificationOpenHandler.java:41)
at com.onesignal.OneSignal.fireNotificationOpenedHandler(OneSignal.java:1009)
at com.onesignal.OneSignal.runNotificationOpenedCallback(OneSignal.java:954)
at com.onesignal.OneSignal.handleNotificationOpen(OneSignal.java:1041)
at com.onesignal.NotificationOpenedProcessor.processIntent(NotificationOpenedProcessor.java:101)
at com.onesignal.NotificationOpenedProcessor.processFromActivity(NotificationOpenedProcessor.java:57)
at com.onesignal.NotificationOpenedReceiver.onReceive(NotificationOpenedReceiver.java:11)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3011)
at android.app.ActivityThread.-wrap18(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1544)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Here's how I made it work:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
OneSignal.startInit(this)
.setNotificationOpenedHandler(new MyNotificationOpenedHandler(this))
.init();
}
}
The NotificationOpenedHandler
custom class
public class MyNotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
private Application application;
public MyNotificationOpenedHandler(Application application) {
this.application = application;
}
@Override
public void notificationOpened(OSNotificationOpenResult result) {
// Get custom datas from notification
JSONObject data = result.notification.payload.additionalData;
if (data != null) {
String myCustomData = data.optString("key", null);
}
// React to button pressed
OSNotificationAction.ActionType actionType = result.action.type;
if (actionType == OSNotificationAction.ActionType.ActionTaken)
Log.i("OneSignalExample", "Button pressed with id: " + result.action.actionID);
// Launch new activity using Application object
startApp();
}
private void startApp() {
Intent intent = new Intent(application, MyActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
}
Don't forget to add this to your manifest:
<application ...>
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
</application>
The short answer to this issue is to include your handler for the push notification open within the same class where you initialize OneSignal:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Init OneSignal
OneSignal.startInit(this).setNotificationOpenedHandler(new NotificationOpenHandler()).init();
Toolbar mToolbar = (Toolbar) findViewById(R.id.app_bar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayUseLogoEnabled(true);
getSupportActionBar().setLogo(R.drawable.ic_launcher);
getSupportActionBar().setDisplayShowTitleEnabled(false);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new RecordingsFragment())
.commit();
}
}
class NotificationOpenHandler implements OneSignal.NotificationOpenedHandler {
// This fires when a notification is opened by tapping on it.
@Override
public void notificationOpened(OSNotificationOpenResult result) {
OSNotificationAction.ActionType actionType = result.action.type;
JSONObject data = result.notification.payload.additionalData;
String stationName = data.optString("stationName");
String timestamp = data.optString("timestamp");
String filename = data.optString("filename");
String url = getString(R.string.callResourceUrl) + filename;
Intent intent = new Intent(getApplicationContext(), CallActivity.class);
intent.putExtra("stationName", stationName);
intent.putExtra("time", timestamp);
intent.putExtra("url", url);
// intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
Updated code in 2022
OneSignal.NotificationOpenedHandler
replaced by OneSignal.OSNotificationOpenedHandler
and result.notification.payload.additionalData
replaced by result.notification.additionalData
Full code
class OneSignalNotificationOpenHandler(private val context : Context) : OneSignal.OSNotificationOpenedHandler {
override fun notificationOpened(result: OSNotificationOpenedResult?) {
if (result == null) return
val type = result.action.type
val data = result.notification.additionalData
val name = data.optString("name")
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_NEW_TASK
intent.putExtra("name", name)
context.startActivity(intent)
}
}
Add it to OneSignel after OneSignal.initWithContext(this)
OneSignal.setNotificationOpenedHandler(OneSignalNotificationOpenHandler(applicationContext))
Don't forget to Add the following to your AndroidManifest.xml to prevent the launching of your main Activity
<application ...>
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
</application>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With