单击通知不会打开提及的活动

我正在尝试在单击通知时打开一个 Activity,下面是我的代码.

Intent 意图 = new Intent(this.getApplicationContext(), NotificationActivity.class);intent.putExtra("msgBody",messageBody);intent.putExtra(Constants.NOTIF_INTENT_TYPE,Constants.NOTIF_INTENT_TYPE);意图.addFlags(意图.FLAG_ACTIVITY_NEW_TASK|意图.FLAG_ACTIVITY_SINGLE_TOP|意图.FLAG_ACTIVITY_CLEAR_TOP);//在这里尝试了很多选项PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , intent,PendingIntent.FLAG_CANCEL_CURRENT);Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.otp_icon).setContentTitle("推送味精").setContentText(messageBody).setAutoCancel(真).setSound(defaultSoundUri).setContentIntent(pendingIntent);通知管理器通知管理器 =(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.notify(0, notificationBuilder.build());

Android 清单:

<?xml version="1.0" encoding="utf-8"?><清单 xmlns:android="http://schemas.android.com/apk/res/android"package="com.com.pushapp"><使用-sdk安卓:m​​inSdkVersion="17"android:targetSdkVersion="21"/>

每当我收到来自 FCM 的通知时,我都会调用此通知.每当我单击通知时,NotificationActivity 都不会打开,而是应用程序正在打开(splash screen->starting activity 我通常的应用程序流程).每当我在应用程序已打开时收到通知时,NotificationActivity 就会打开,但在应用程序尚未打开时不会.有人可以帮我解决这个问题吗?

注意:请我重申,当应用尚未打开状态时点击通知时,NotificationActivity.class 不会打开.

解决方案

根据FCM文档,用于接收和处理消息,

<块引用>

如果您想在您的应用处于前台,你需要添加一些消息处理逻辑.

要接收消息,请使用扩展的服务Firebase 消息服务.您的服务应该覆盖onMessageReceived 回调,为大多数消息类型提供,除了以下情况:

1).当您的应用程序在后台时发送的通知.在在这种情况下,通知会发送到设备的系统托盘.默认情况下,用户点击通知会打开应用启动器.

2).具有通知和数据有效负载的消息,均为背景和前景.在这种情况下,通知将发送到设备的系统托盘,数据负载在附加组件中交付启动器 Activity 的意图.

所以基本上,我们有两种类型的有效载荷

1).通知负载

2). 数据负载

3).两者(我们可以考虑的其他类型).

现在让我们一一讨论这些有效载荷.在此之前,您需要了解如何将这些 Payload 发送到您的应用程序.你所要做的就是使用任何可以执行HTTP POST Request的工具.就我而言,我使用的是 Postman 工具,一个 Google Chrome 插件.

在为 FCM 发出 HTTP Post Request 之前,您必须考虑三件事:

1).HTTP 发布请求网址:

3).正文: 在此我们将为 NotificationData Payloads 提供 JSON.

  • 所以从 Notification Payload 开始,这是最简单的.在这种情况下,onMessageReceived() 仅在应用程序位于 Foreground 时调用,对于所有其他情况,它是 System Tray Notification,它单击时打开 Launcher Activity.当您不想自己控制 Notifications 并且在 Notification 来临时没有太多数据需要处理时,这很有帮助.您甚至可以控制声音、图标和 click_action(仅当应用程序位于 Foreground 时),而无需在 onMessageReceived() 中编写任何代码.下面的屏幕截图中附有此类 HTTP POST 请求 正文的一个示例.

要在发送 click_action 参数时打开所需的 Activity,您必须在 onMessageReceived() 中使用以下代码.

@Override公共无效 onMessageReceived(RemoteMessage remoteMessage) {if (null != remoteMessage.getNotification().getClickAction()) {startActivity(remoteMessage.getNotification().getClickAction(), null, this);}}

下面是你的 startActivity() 方法:

public void startActivity(String className, Bundle extras, Context context) {类 cls = null;尝试 {cls = Class.forName(className);} 捕捉(ClassNotFoundException e){//表示您在 firebase 控制台中输入错误}意图意图=新意图(上下文,cls);if (null != extras) {意图.putExtras(附加);}意图.setFlags(意图.FLAG_ACTIVITY_NEW_TASK|意图.FLAG_ACTIVITY_CLEAR_TASK);context.startActivity(intent);}

<块引用>

注意:此 click_action 键仅在应用程序处于前台,适用于应用程序处于后台的所有其他情况,并且关闭,它不起作用.它甚至没有打开启动器活动,如果指定了此参数,则在 Background 和 Closed 的情况下.

  • 现在是数据负载.这与我们在 GCM 中的类似.如果我们想像处理 GCM 的情况一样自己处理所有 Notification 内容,这一点非常重要.此类 HTTP POST 请求 的主体示例如下所示.

所以在这种情况下,每次都会调用 onMessageReceived(),这将与 GCM 的工作方式相同,对我们所有人都有帮助.您必须 Override onMessageReceived() 如下所示.

@Override公共无效 onMessageReceived(RemoteMessage remoteMessage) {映射<字符串,字符串>数据 = remoteMessage.getData();if (null != data && 0 < data.size()) {if (data.containsKey("custom_key_1")) {sendNotification(data.get("custom_key_1"));}}}私人无效发送通知(字符串消息正文){Intent 意图 = new Intent(this, DesiredActivity.class);意图.addFlags(意图.FLAG_ACTIVITY_CLEAR_TOP);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0/* 请求代码 */, intent,PendingIntent.FLAG_ONE_SHOT);Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_stat_ic_notification).setContentTitle("FCM 消息").setContentText(messageBody).setAutoCancel(真).setSound(defaultSoundUri).setContentIntent(pendingIntent);通知管理器通知管理器 =(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.notify(0/* 通知 ID */, notificationBuilder.build());}

  • 最后但并非最不重要的一点是,我们也可以同时发送 NotificationData Payloads.在这种情况下,当应用程序在 Foreground 时调用 onMessageReceived().对于后台和关闭状态,Notification 类似于 Notification Payload 进入系统托盘,但唯一的区别是我们也可以有 data extras当点击 Notification 时,我们可以使用将用户重定向到所需的 Activity.下面是这样的 HTTP POST 请求 的主体示例.HTTP POST 请求 的主体示例如下所示.

点击系统托盘上的Notification时,会打开Launcher Activity,你需要Override onCreate() 您的 Launcher Activity 以获取 data extras 并将用户重定向到所需的 Activity.下面是代码,您必须在 ActivityonCreate() 中编写以将用户重定向到所需的 Activity.

@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);if(getIntent().hasExtra("custom_key_1") && getIntent().getStringExtra("custom_key_1").equals("custom_value_1")){startActivity(new Intent(this, DesiredActivity.class));结束();返回;}//其他操作}

这种类型的另一种情况是,当您的 Launcher Activitymanifest 中定义为 launchMode="true" 并且当 Notification 到达,你的 Launcher ActivityForeground.因此,当您单击通知时,您必须在 Launcher ActivityOverride onNewIntent() 方法才能打开所需的 Activity.以下是相同的示例代码.

@Override受保护的无效onNewIntent(意图意图){super.onNewIntent(intent);if (getIntent().hasExtra("custom_key_1") && getIntent().getStringExtra("custom_key_1").equals("custom_value_1")) {startActivity(new Intent(this, DesiredActivity.class));结束();}}

所以简而言之,我会说最好使用 Data Payload 类型,因为它提供了更多的灵活性和对 Notification 的控制,更重要的是,我们都是习惯了GCM,所以这种类型是我们都喜欢的.

<块引用>

注意:某些设备在接收通知时遇到问题背景,因为我在这里发现了一些相同的查询.此外在当时,我正在调查这些案例,我的华硕手机没有收到上述任何类型的后台通知.所以不确定这些设备有什么问题.

I am trying to open an Activity when the notification is clicked and below is my code.

Intent intent = new Intent(this.getApplicationContext(), NotificationActivity.class);
intent.putExtra("msgBody",messageBody);
intent.putExtra(Constants.NOTIF_INTENT_TYPE,Constants.NOTIF_INTENT_TYPE);

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                |Intent.FLAG_ACTIVITY_SINGLE_TOP
                |Intent.FLAG_ACTIVITY_CLEAR_TOP); //Tried with many options here

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , intent,
                                         PendingIntent.FLAG_CANCEL_CURRENT);

Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.otp_icon)
                .setContentTitle("Push MSG")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

notificationManager.notify(0, notificationBuilder.build());

Android Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.com.pushapp">

    <uses-sdk
        android:minSdkVersion="17"
        android:targetSdkVersion="21" />

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:name=".AndroidPushApp"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher">
        <activity
            android:name=".PushSplashScreen"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainApplicationScreen"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>
        </activity>
        <activity
            android:name=".StartActivity"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:uiOptions="splitActionBarWhenNarrow"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>
        </activity>

        <service android:name=".MyFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <service android:name=".MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <activity
            android:name=".NotificationActivity"
            android:exported="true"
            android:label="@string/title_activity">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Whenever I get notification from FCM I am calling this notification. The NotificationActivity is not opening whenever I click on notification, rather the app is opening(splash screen->starting activity of my usual app flow). Whenever I get notification while the app is already open, the NotificationActivity is getting opened, but not when app is not already opened. Could someone please help me on resolving this?

Note: Please I am reiterating that NotificationActivity.class is not getting opened when clicked on notification when app is not already opened state.

解决方案

According to FCM Documentation, for receiving and handling messages,

If you want to receive notifications when your app is in the foreground, you need to add some message handling logic.

To receive messages, use a service that extends FirebaseMessagingService. Your service should override the onMessageReceived callback, which is provided for most message types, with the following exceptions:

1). Notifications delivered when your app is in the background. In this case, the notification is delivered to the device’s system tray. A user tap on a notification opens the app launcher by default.

2). Messages with both notification and data payload, both background and foreground. In this case, the notification is delivered to the device’s system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.

So Basically, we have two types of Payloads

1). Notification Payload

2). Data Payload

3). Both (an additional type we can consider).

Now let's discuss one by one these payloads. Before that you need to understand how can you send these Payloads to your app. All you have to do is to make use of any tool that can perform HTTP POST Request. In my case, I am using the Postman tool, a Google Chrome Plugin.

Before making a HTTP Post Request for FCM, you have to consider three things:

1). HTTP Post Request URL : https://fcm.googleapis.com/fcm/send

2). Request Headers :

i). Content-Type : application/json

ii). Authorization : key = YOUR_SERVER_KEY

Below is the screenshot for the same to show how it looks.

3). Body : In this we are going to have JSON for Notification and Data Payloads.

  • So starting with Notification Payload, the simplest of all. In this case, onMessageReceived() is called only when the app is in Foreground, For all other cases, it's a System Tray Notification, which opens the Launcher Activity when clicked. This is helpful when you don't want to control Notifications by your own and not much data to deal with when Notification comes. You can even control the sound, icon and click_action(only when the app is in Foreground) without writing any code in your onMessageReceived(). One example of a body of such HTTP POST Request is attached in the screenshot below.

For opening desired Activity when sending click_action parameter, you have to use the below code in your onMessageReceived().

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    if (null != remoteMessage.getNotification().getClickAction()) {
            startActivity(remoteMessage.getNotification().getClickAction(), null, this);
    }
}

and below is your startActivity() method :

public void startActivity(String className, Bundle extras, Context context) {
    Class cls = null;
    try {
        cls = Class.forName(className);
    } catch (ClassNotFoundException e) {
        //means you made a wrong input in firebase console
    }
    Intent intent = new Intent(context, cls);
    if (null != extras) {
        intent.putExtras(extras);
    }
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
            | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    context.startActivity(intent);
}

NOTE : This click_action key will work only when the app is in Foreground, for all other case when the app is in Background and closed, it doesn't work. It doesn't even open the Launcher Activity, in case of Background and Closed, if this parameter is specified.

  • Now comes the Data Payload. This is similar to the one we have in GCM. This is very important if we want to handle all the Notification stuff by ourselve same as we all were doing in case of GCM. Example of a body of such HTTP POST Request is shown below.

So in this case, onMessageReceived() is called everytime and this will work in the same way as that of GCM, so helpful to all of us. You have to Override onMessageReceived() as shown below.

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Map<String, String> data = remoteMessage.getData();
    if (null != data && 0 < data.size()) {
        if (data.containsKey("custom_key_1")) {
            sendNotification(data.get("custom_key_1"));
        }
    }
}

private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, DesiredActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setContentTitle("FCM Message")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}

  • Last but not the least, we can send both Notification and Data Payloads as well. In this case, onMessageReceived() is called when the app is in Foreground. For background and closed state, Notification comes in the system tray similar to Notification Payload but the only difference is we can have data extras as well that we can use to redirect user to a desired Activity, when clicked on a Notification. Below is the example of a body of such HTTP POST Request.Example of a body of such HTTP POST Request is shown below.

When clicking on a Notification on System Tray, it will open the Launcher Activity and You need to Override onCreate() of your Launcher Activity to get the data extras and redirect user to the desired Activity. Below is the code, you have to write in onCreate() of your Activity to redirect user to the desired Activity.

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if(getIntent().hasExtra("custom_key_1") && getIntent().getStringExtra("custom_key_1")
            .equals("custom_value_1")){
        startActivity(new Intent(this, DesiredActivity.class));
        finish();
        return;
    }

    // other operations
}

Another case to this type is, when your Launcher Activity is defined as launchMode="true" in the manifest and when the Notification Arrives, your Launcher Activity is in the Foreground. So when you click on the Notification, you have to Override the onNewIntent() method in your Launcher Activity to open the desired Activity. Below is the sample code for the same.

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    if (getIntent().hasExtra("custom_key_1") && getIntent().getStringExtra("custom_key_1")
                .equals("custom_value_1")) {
            startActivity(new Intent(this, DesiredActivity.class));
            finish();
    }
}

So in short, I would say it's good to go with the Data Payload type as it provides more flexibility and control over the Notification and more importantly as we all are used to GCM, so this type is what we all would like to prefer.

Note : Some devices are having issue receiving Notifications in Background as I found some queries over same here. Moreover at the time, I was investigating these cases, my ASUS phone was not receiving notifications in Background for any of the types mentioned above. So not sure what's the issue with these devices.

相关文章