如何在Firebase中的后台应用时处理通知

Par*_*tel 379 android firebase firebase-cloud-messaging

这是我的清单

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

    <service android:name=".fcm.PshycoFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>
Run Code Online (Sandbox Code Playgroud)

当应用程序处于后台并且通知到达时,默认通知将会运行并且不会运行我的代码onMessageReceived.

这是我的onMessageReceived代码.如果我的应用程序在前台运行,而不是在后台应用程序时,则调用此方法.如何在应用程序处于后台时运行此代码?

// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // If the application is in the foreground handle both data and notification messages here.
    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
    data = remoteMessage.getData();
    String title = remoteMessage.getNotification().getTitle();
    String message = remoteMessage.getNotification().getBody();
    String imageUrl = (String) data.get("image");
    String action = (String) data.get("action");
    Log.i(TAG, "onMessageReceived: title : "+title);
    Log.i(TAG, "onMessageReceived: message : "+message);
    Log.i(TAG, "onMessageReceived: imageUrl : "+imageUrl);
    Log.i(TAG, "onMessageReceived: action : "+action);

    if (imageUrl == null) {
        sendNotification(title,message,action);
    } else {
        new BigPictureNotification(this,title,message,imageUrl,action);
    }
}
// [END receive_message]
Run Code Online (Sandbox Code Playgroud)

Ant*_*nio 599

1.为什么会这样?

FCM(Firebase云消息传递)中有两种类型的消息:

  1. 显示消息:onMessageReceived()仅当您的应用处于前台时,这些消息才会触发回调
  2. 数据消息:即使您的应用程序处于前台/后台/已杀死,这些消息也会触发onMessageReceived()回调

Firebase团队尚未开发用于发送data-messages到您设备的UI .

2.怎么样?

要实现此目的,您必须对POST以下URL 执行请求:

POST https://fcm.googleapis.com/fcm/send

  • 关键: Content-Type,价值: application/json
  • 关键: Authorization,价值: key=<your-server-key>

身体使用主题

{
    "to": "/topics/my_topic",
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您想将其发送到特定设备

{
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     },
    "registration_ids": ["{device-token}","{device2-token}","{device3-token}"]
}
Run Code Online (Sandbox Code Playgroud)


注意:确保您没有添加 JSON密钥notification
注意:要获取服务器密钥,您可以在firebase控制台中找到它:Your project -> settings -> Project settings -> Cloud messaging -> Server Key

3.如何处理推送通知消息?

这是您处理收到的消息的方式:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String myCustomKey = data.get("my_custom_key");

     // Manage data
}
Run Code Online (Sandbox Code Playgroud)

  • 当应用程序处于后台时,"onMessageReceived"不会被调用,这是FCM中的一个严重问题!另请更新您的答案. (44认同)
  • 三年后,这“仍然”是一个问题:如果您的应用程序在后台运行,如果您的消息有“通知”键,则 onReceiveMessage 将“不会”被调用,无论它是否有“数据”键。由于您的服务器无法确定应用程序是否在后台运行,因此它需要发送*两条*消息。荒谬的 (14认同)
  • 5 年过去了,我们仍然无法使用“onMessageReceived”处理后台 FCM,也无法在 FCM 控制台中提供简单的 UI。这意味着需要更多的时间和后端工程师来开发诸如为用户提供的应用内通知中心和为营销成员提供的控制台等功能。为什么 Firebase 坚持不修复它? (11认同)
  • `Firebase团队还没有开发用于向您的设备发送数据消息的用户界面,但是.过去一年中这种情况发生了变化吗? (10认同)
  • 您可以按照以下步骤在同一通知中发送"数据"和"通知"键http://stackoverflow.com/a/42279260/2734021 :) (4认同)
  • 带有通知负载的后台应用程序是有史以来最愚蠢的事情。这有实际用途吗?99% 的通知会在您的应用程序处于后台时发送,以让用户返回您的应用程序。 (3认同)
  • 如果您使用邮递员不要使用授权部分,请改用标题键/值部分,不要忘记值键服务器中的“key=”后缀:。/sf/ask/3171677211/ (3认同)
  • @Antonio在Oreo中,当应用程序被杀死时,不会调用onMessageReceived。我只是有数据的有效载荷。你有什么更新吗? (2认同)
  • 好吧,对我来说,似乎这种情况发生在某些Android设备上.花了好几个小时认为这是一个实际问题,但后来证明是没有.所以我的建议是在不同的设备上测试它.我甚至在虚拟机上测试了它,即使应用程序被杀,我也收到了通知.我只是这样说是为了节省一些人的时间. (2认同)

Tee*_*rat 139

在以下情况下使firebase库调用onMessageReceived()

  1. 应用程序在前台
  2. 应用程序在后台
  3. 应用程序已被杀死

您不得在请求中将JSON密钥"通知"放入firebase API,而是使用"数据",请参阅下文.

当您的应用程序处于后台或被杀时,以下消息将不会调用您的onMessageReceived(),并且您无法自定义通知.

{
   "to": "/topics/journal",
   "notification": {
   "title" : "title",
   "text": "data!",
   "icon": "ic_notification"
    }
}
Run Code Online (Sandbox Code Playgroud)

但改为使用它会起作用

{
  "to": "/topics/dev_journal",
   "data": {
       "text":"text",
       "title":"",
       "line1":"Journal",
       "line2":"??"
   }
} 
Run Code Online (Sandbox Code Playgroud)

基本上,消息在参数RemoteMessage中与您的数据对象一起作为Map发送,然后您可以在onMessageReceived中管理通知,就像在这里的片段一样

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();

     //you can get your text message here.
     String text= data.get("text");


     NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
        // optional, this is to make beautiful icon
             .setLargeIcon(BitmapFactory.decodeResource(
                                    getResources(), R.mipmap.ic_launcher))  
        .setSmallIcon(smallIcon)  //mandatory
      .......
    /*You can read more on notification here:
    https://developer.android.com/training/notify-user/build-notification.html
    https://www.youtube.com/watch?v=-iog_fmm6mE
    */
}
Run Code Online (Sandbox Code Playgroud)

  • 当应用程序处于后台时,您的方法可以正常工作,但是当应用程序被杀死时,我没有收到数据 (21认同)
  • 桑扎尔的问题一样.如果应用程序被杀,我不会收到任何消息. (6认同)

Dan*_* S. 89

我觉得所有的回复都是不完整的,但是当你的应用处于后台时,所有这些回复都需要处理包含数据的通知.

按照以下步骤操作,您就可以在应用处于后台时处理通知.

1.添加如下的intent-filter:

<activity android:name=".MainActivity">
      <intent-filter>
           <action android:name=".MainActivity" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)

到您要处理通知数据的活动.

  1. 使用下一格式发送通知:

    { 
     "notification" : {
            "click_action" : ".MainActivity", 
            "body" : "new Symulti update !", 
            "title" : "new Symulti update !", 
            "icon" : "ic_notif_symulti" }, 
     "data": { ... },
     "to" : "c9Vaa3ReGdk:APA91bH-AuXgg3lDN2WMcBrNhJZoFtYF9" }
    
    Run Code Online (Sandbox Code Playgroud)

这里的关键是添加

"click_action" : ".MainActivity"
Run Code Online (Sandbox Code Playgroud)

其中.MainActivity是您在步骤1中添加的intent-filter的活动.

  1. 从".MainActivity"的onCreate中获取通知中的"数据"信息:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //get notification data info
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
           //bundle must contain all info sent in "data" field of the notification
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

这应该就是你需要做的一切.我希望这有助于某人:)

  • 这应该是正确的答案.没有任何文档说过要求click_action和Intent Filter来通知甚至显示在托盘中.它们都是必需的. (5认同)
  • 我只是不明白这不是公认的答案.没有click_action,它就行不通.救了我的一天 (3认同)
  • 感谢您对@ArunShankar的支持.接受的答案是在我的前7个月回复,这是一个很好的答案.我无法理解为什么没有人谈论click_action,这就是我添加答案的原因.我很高兴它对很多人来说非常有用,这就是最重要的事情:) (3认同)

小智 35

根据使用firebase发送下游的firebase文档,有两种类型的有效负载:

  1. 数据

    此参数指定消息的有效内容的自定义键值对.客户端应用程序负责处理数据消息.数据消息只有自定义键值对.

  2. 通知

    此参数指定通知有效内容的预定义的,用户可见的键值对.FCM代表客户端应用自动向最终用户设备显示消息.通知消息具有一组预定义的用户可见键.

当您在前台时,您可以使用onMessageReceived()在FCM中获取数据,您可以从数据有效负载中获取数据.

data = remoteMessage.getData();
String customData = (String) data.get("customData");
Run Code Online (Sandbox Code Playgroud)

当您在后台时,FCM将根据通知有效负载中的信息在系统托盘中显示通知.用于系统托盘上的通知的标题,消息和图标来自通知有效负载.

{
  "notification": {
        "title" : "title",
        "body"  : "body text",
        "icon"  : "ic_notification",
        "click_action" : "OPEN_ACTIVITY_1"
       }
}
Run Code Online (Sandbox Code Playgroud)

当您希望在应用程序处于后台时在系统托盘上自动显示通知时,将使用此通知有效内容.要在后台运行应用时获取通知数据,您应在通知有效负载内添加click_action .

如果要打开应用程序并执行特定操作[在后台运行时],请在通知有效内容中设置click_action并将其映射到要启动的活动中的意图过滤器.例如,将click_action设置为OPEN_ACTIVITY_1以触发如下所示的intent过滤器:

<intent-filter>
  <action android:name="OPEN_ACTIVITY_1" />
  <category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Run Code Online (Sandbox Code Playgroud)

将intent-filter放在应用程序标记内的清单上.单击通知后,它将打开应用程序并直接进入您在click_action中定义的活动,在本例中为"OPEN_ACTIVTY_1".在该活动中,您可以通过以下方式获取数据:

Bundle b = getIntent().getExtras();
String someData = b.getString("someData");
Run Code Online (Sandbox Code Playgroud)

我正在为我的Android应用程序使用FCM并使用两个有效负载.这是我正在使用的示例JSON:

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification",
    "click_action" : "OPEN_ACTIVITY_1"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}
Run Code Online (Sandbox Code Playgroud)


Shu*_*ank 31

根据文件

处理背景应用程序中的消息

当您的应用在后台时,Android会将通知消息定向到系统托盘.用户点按通知会默认打开应用启动器.

这包括包含通知和数据有效负载的消息.在这些情况下,通知将传递到设备的系统托盘,并且数据有效负载将在启动器活动的附加内容中传递.

如果要打开应用程序并执行特定操作,请在通知有效内容中设置click_action,并将其映射到要启动的活动中的intent过滤器.例如,将click_action设置为OPEN_ACTIVITY_1以触发如下所示的intent过滤器:

 <intent-filter>   <action android:name="OPEN_ACTIVITY_1" />  
 <category android:name="android.intent.category.DEFAULT" />
 </intent-filter>
Run Code Online (Sandbox Code Playgroud)

编辑:

基于这个帖子:

您无法使用Firebase控制台设置click_action有效内容.您可以尝试使用curl命令或自定义http服务器进行测试

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" 
     --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  
     -d "{\"to\":\"/topics/news\",\"notification\": 
         {\"title\": \"Click Action Message\",\"text\": \"Sample message\",
            \"click_action\":\"OPEN_ACTIVITY_1\"}}"
Run Code Online (Sandbox Code Playgroud)


Ani*_*nan 20

由于display-messages从Firebase Notification UI发送的内容仅适用于您的应用位于前台的情况.因为data-messages,需要对FCM进行POST调用

脚步

  1. 安装Advanced Rest Client Google Chrome扩展程序 在此输入图像描述

  2. 添加以下标头

    密钥:内容类型,:application/json

    密钥:授权,价值:密钥="您的服务器密钥" 在此输入图像描述

  3. 添加身体


而已!.现在onMessageReceived像往常一样听回调.

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String value1 = data.get("key1");
     String value2 = data.get("key2");
}
Run Code Online (Sandbox Code Playgroud)


小智 17

要在后台捕获消息,您需要使用a BroadcastReceiver

import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.legacy.content.WakefulBroadcastReceiver
import com.google.firebase.messaging.RemoteMessage

class FirebaseBroadcastReceiver : WakefulBroadcastReceiver() {

    val TAG: String = FirebaseBroadcastReceiver::class.java.simpleName

    override fun onReceive(context: Context, intent: Intent) {

        val dataBundle = intent.extras
        if (dataBundle != null)
            for (key in dataBundle.keySet()) {
                Log.d(TAG, "dataBundle: " + key + " : " + dataBundle.get(key))
            }
        val remoteMessage = RemoteMessage(dataBundle)
        }
    }
Run Code Online (Sandbox Code Playgroud)

并将其添加到您的清单:

<receiver
      android:name="MY_PACKAGE_NAME.FirebaseBroadcastReceiver"
      android:exported="true"
      android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
</receiver>
Run Code Online (Sandbox Code Playgroud)

  • 当应用程序处于后台时,这确实会收到通知消息.但它并不会阻止默认的Firebase接收器处理它,因此消息仍会显示为通知警报. (7认同)

Avi*_*aun 16

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}
Run Code Online (Sandbox Code Playgroud)

每次只有当app在forground中时才调用它

有一个覆盖方法每次调用此方法,无论前台或后台有什么应用程序或被杀死,但此方法可用于此firebase api版本

这是你必须从gradle导入的版本

compile 'com.google.firebase:firebase-messaging:10.2.1'
Run Code Online (Sandbox Code Playgroud)

这是方法

@Override
public void handleIntent(Intent intent) {
    super.handleIntent(intent);

    // you can get ur data here 
    //intent.getExtras().get("your_data_key") 


}
Run Code Online (Sandbox Code Playgroud)

使用以前的firebase api这个方法不存在,所以在这种情况下,当app在后台时,fire base handle本身....现在你有这个方法你想做什么...你可以在这个方法中做到这一点.. ...

如果你使用以前的版本而不是默认活动,那么在这种情况下你可以获得相同的数据

if(getIntent().getExtras() != null && getIntent().getExtras().get("your_data_key") != null) {
String strNotificaiton = getIntent().getExtras().get("your_data_key").toString();
Run Code Online (Sandbox Code Playgroud)

//做你想做的事......

通常这是我们通知服务器的结构

{
    "notification": {
        "body": "Cool offers. Get them before expiring!",
        "title": "Flat 80% discount",
        "icon": "appicon",
        "click_action": "activity name" //optional if required.....
    },
    "data": {
        "product_id": 11,
        "product_details": "details.....",
        "other_info": "......."
    }
}
Run Code Online (Sandbox Code Playgroud)

这取决于你如何想要提供数据密钥或者你想要给出任何你可以给出的通知.......你将用相同的密钥给你什么,你将得到那些数据........ .

如果你没有发送点击动作的情况很少,你会点击通知默认活动会打开,但如果你想在应用程序处于后台时打开你的特定活动,你可以在handleIntent方法上调用你的活动,因为这个每次都被召唤


Md.*_*rim 13

这里有关于firebase消息的更清晰的概念.我是从他们的支持团队那里找到的.

Firebase有三种消息类型:

通知消息:通知消息适用于背景或前景.当应用程序处于后台时,通知消息将传递到系统托盘.如果应用程序是在前台,消息被处理onMessageReceived()didReceiveRemoteNotification回调.这些基本上就是所谓的显示消息.

数据消息:在Android平台上,数据消息可以在后台和前台工作.数据消息将由onMessageReceived()处理.这里的平台特定说明如下:在Android上,可以在用于启动活动的Intent中检索数据有效负载.具体地说就是,如果你有"click_action":"launch_Activity_1",你可以通过检索此意图getIntent()仅从Activity_1.

具有通知和数据有效负载的消息:在后台,应用程序在通知托盘中接收通知有效负载,并且仅在用户点击通知时处理数据有效负载.在前台时,您的应用会收到一个消息对象,其中包含两个可用的有效负载.其次,该click_action参数通常用于通知有效载荷而不用于数据有效载荷.如果在数据有效内容中使用,则此参数将被视为自定义键值对,因此您需要实现自定义逻辑才能使其按预期工作.

另外,我建议您使用onMessageReceived方法(请参阅数据消息)来提取数据包.根据您的逻辑,我检查了bundle对象,但没有找到预期的数据内容.以下是对可能提供更清晰的类似案例的引用.

有关更多信息,请访问我的主题


小智 11

根据文件:2017年5月17日

当您的应用在后台时,Android会将通知消息定向到系统托盘.用户点按通知会默认打开应用启动器.

这包括包含通知和数据有效负载的消息(以及从Notifications控制台发送的所有消息).在这些情况下,通知将传递到设备的系统托盘,并且数据有效负载将在启动器活动的附加内容中传递.

因此,您应该使用有效负载通知+数据:

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}
Run Code Online (Sandbox Code Playgroud)

没有必要使用click_action.You应该只是对LAUNCHER活动的意图

<activity android:name=".MainActivity">
        <intent-filter>
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)

Java代码应该在MainActivity上的onCreate方法上:

Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
    Bundle extras = intent.getExtras();
    String someData= extras.getString("someData");
    String someData2 = extras.getString("someData2");
}
Run Code Online (Sandbox Code Playgroud)

您可以从Firebase Notifications Console测试两个有效负载通知+数据.不要忘记在高级选项部分填写自定义数据字段


pul*_*ion 10

2017年更新答案

以下是有关此问题的文档的明确答案:

在此输入图像描述


alv*_*aro 8

截至2019年7月

Android compileSdkVersion 28,buildToolsVersion 28.0.3和firebase-messaging:19.0.1

在研究了所有其他其他StackOverflow问题和答案,并尝试了无数过时的解决方案之后,该解决方案设法在以下3种情况下显示了通知:

-应用程序处于前台:
通过MyFirebaseMessagingService类的onMessageReceived方法接收通知

-应用已被终止(它不是在后台运行): 通知由FCM自动发送到通知托盘。当用户触摸通知时,将通过调用清单中具有android.intent.category.LAUNCHER的活动来启动应用。您可以通过在onCreate()方法中使用getIntent()。getExtras()来获取通知的数据部分。

-应用程序处于后台: 通知将由FCM自动发送到通知托盘。当用户触摸通知时,通过启动清单中包含android.intent.category.LAUNCHER的活动,使应用程序进入前台。由于我的应用程序在该活动中具有launchMode =“ singleTop”,因此不会调用onCreate()方法,因为已经创建了同一类的一个活动,而是调用了该类的onNewIntent()方法,并且您获得了通过使用intent.getExtras()获得通知。

步骤:1-如果您定义应用的主要活动是这样的:

<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:screenOrientation="portrait"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name=".MainActivity" />
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)

2-将这些行添加到MainActivity.class的onCreate()方法中

Intent i = getIntent();
Bundle extras = i.getExtras();
if (extras != null) {
    for (String key : extras.keySet()) {
        Object value = extras.get(key);
        Log.d(Application.APPTAG, "Extras received at onCreate:  Key: " + key + " Value: " + value);
    }
    String title = extras.getString("title");
    String message = extras.getString("body");
    if (message!=null && message.length()>0) {
        getIntent().removeExtra("body");
        showNotificationInADialog(title, message);
    }
}
Run Code Online (Sandbox Code Playgroud)

和这些方法相同的MainActivity.class:

@Override
public void onNewIntent(Intent intent){
    //called when a new intent for this class is created.
    // The main case is when the app was in background, a notification arrives to the tray, and the user touches the notification

    super.onNewIntent(intent);

    Log.d(Application.APPTAG, "onNewIntent - starting");
    Bundle extras = intent.getExtras();
    if (extras != null) {
        for (String key : extras.keySet()) {
            Object value = extras.get(key);
            Log.d(Application.APPTAG, "Extras received at onNewIntent:  Key: " + key + " Value: " + value);
        }
        String title = extras.getString("title");
        String message = extras.getString("body");
        if (message!=null && message.length()>0) {
            getIntent().removeExtra("body");
            showNotificationInADialog(title, message);
        }
    }
}


private void showNotificationInADialog(String title, String message) {

    // show a dialog with the provided title and message
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title);
    builder.setMessage(message);
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();
}
Run Code Online (Sandbox Code Playgroud)

3-创建类MyFirebase,如下所示:

package com.yourcompany.app;

import android.content.Intent;
import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyFirebaseMessagingService extends FirebaseMessagingService {


    public MyFirebaseMessagingService() {
        super();
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        Log.d(Application.APPTAG, "myFirebaseMessagingService - onMessageReceived - message: " + remoteMessage);

        Intent dialogIntent = new Intent(this, NotificationActivity.class);
        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        dialogIntent.putExtra("msg", remoteMessage);
        startActivity(dialogIntent);

    }

}
Run Code Online (Sandbox Code Playgroud)

4-创建一个新的类NotificationActivity.class像这样:

package com.yourcompany.app;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;

import com.google.firebase.messaging.RemoteMessage;

public class NotificationActivity extends AppCompatActivity {

private Activity context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    context = this;
    Bundle extras = getIntent().getExtras();

    Log.d(Application.APPTAG, "NotificationActivity - onCreate - extras: " + extras);

    if (extras == null) {
        context.finish();
        return;
    }

    RemoteMessage msg = (RemoteMessage) extras.get("msg");

    if (msg == null) {
        context.finish();
        return;
    }

    RemoteMessage.Notification notification = msg.getNotification();

    if (notification == null) {
        context.finish();
        return;
    }

    String dialogMessage;
    try {
        dialogMessage = notification.getBody();
    } catch (Exception e){
        context.finish();
        return;
    }
    String dialogTitle = notification.getTitle();
    if (dialogTitle == null || dialogTitle.length() == 0) {
        dialogTitle = "";
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(context, R.style.myDialog));
    builder.setTitle(dialogTitle);
    builder.setMessage(dialogMessage);
    builder.setPositiveButton(getResources().getString(R.string.accept), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();

}
Run Code Online (Sandbox Code Playgroud)

}

5-将这些行添加到标签内的应用清单中

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

    <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id"/>

    <activity android:name=".NotificationActivity"
        android:theme="@style/myDialog"> </activity>

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/notification_icon"/>

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/color_accent" />
Run Code Online (Sandbox Code Playgroud)

6-将以下行添加到Application.java onCreate()方法或MainActivity.class onCreate()方法中:

      // notifications channel creation
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      // Create channel to show notifications.
      String channelId = getResources().getString("default_channel_id");
      String channelName = getResources().getString("General announcements");
      NotificationManager notificationManager = getSystemService(NotificationManager.class);
      notificationManager.createNotificationChannel(new NotificationChannel(channelId,
              channelName, NotificationManager.IMPORTANCE_LOW));
  }
Run Code Online (Sandbox Code Playgroud)

做完了

现在,要使其在上述3个方案中都能正常工作,您必须通过以下方式从Firebase Web控制台发送通知:

在“通知”部分中:通知标题=要在通知对话框中显示的标题(可选)通知文本=要向用户显示的消息(必填)然后在“目标”部分:App =您的Android应用程序,在“其他选项”部分:Android通知频道= default_channel_id自定义数据键:标题值:(此处与“通知”部分的“标题”字段中的文本相同)键:主体值:(此处与“通知”部分的“消息”字段中的文本相同)键:click_action值:.MainActivity声音=失效
期限= 4周

您可以使用带有Google Play的API 28在仿真器中对其进行调试。

编码愉快!

  • 谢谢你的回答。 (2认同)
  • 当应用程序关闭或终止时,vivo opp 手机无法工作 (2认同)
  • 这是最新的答案,正如 Firebase 文档现在的内容所示:当您的应用程序位于后台时,Android 会将通知消息定向到系统托盘。默认情况下,用户点击通知会打开应用程序启动器。这包括包含通知和数据负载的消息。在这些情况下,通知将传递到设备的系统托盘,并且数据负载将在启动器活动的意图的附加内容中传递。(https://firebase.google.com/docs/cloud-messaging/android/receive#backgrounded)很多旧答案都已经过时了 (2认同)

goo*_*ofy 8

我有同样的问题。经过一番挖掘,为什么我的 MainActivity 在没有数据的情况下被有意调用,我意识到我的 LAUNCHER 活动(如清单中所示)是 SplashActivity。在那里我找到了消息数据并将它们转发到 MainActivity。像沙姆沙伊赫一样工作。我相信这可以帮助某人。

感谢所有其他答案。


Ard*_*rda 7

像这样简单的总结

是触发器.

并非由direclty触发和交付.如果你有任何特定的键值对.他们不工作因为onMessageReceived()无效.

我已经找到了这种方式;

在你的启动器活动中,把这个逻辑,

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState, R.layout.activity_splash);

    if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("PACKAGE_NAME")) {

        // do what you want

        // and this for killing app if we dont want to start
        android.os.Process.killProcess(android.os.Process.myPid());

    } else {

        //continue to app
    }
}
Run Code Online (Sandbox Code Playgroud)

在此if块中,根据firebase UI搜索您的密钥.

在这个例子中我的关键和价值如上; (抱歉语言=)) 在此输入图像描述

当我的代码工作时,我得到"com.rda.note".

android.os.Process.killProcess(android.os.Process.myPid());
Run Code Online (Sandbox Code Playgroud)

使用这行代码,我关闭了我的应用程序并打开了Google Play Market

快乐的编码=)


Sha*_*jib 6

我想出了这些场景,

当app在前台时, 从FirebaseService调用onMessageReceived()方法.因此将调用服务类中定义的pendingIntent.

当app在后台时,会调用第一个活动.

现在,如果你使用splash事件,那么必须记住将调用splashactivity,否则如果没有splashActivity,那么无论第一个活动是什么,都将被调用.

然后,你需要检查getIntent()中的firstActivity,看它是否有任何捆绑.如果一切正常,你会看到包是有与填充值.如果值数据标签从服务器发送看起来像这样,

"data": {
    "user_name": "arefin sajib",
    "value": "user name notification"
  }
Run Code Online (Sandbox Code Playgroud)

然后在第一个活动中,您将看到,有一个有效的意图(getIntent()不为null),有效的bundle和内部bundle,将上面提到的整个JSON以数据 作为.

对于这种情况,提取值的代码将如下所示,

    if(getIntent()!=null){
            Bundle bundle = getIntent().getExtras();
            if (bundle != null) {
                try {
                   JSONObject object = new JSONObject(bundle.getStringExtra("data"));
String user_name = object.optString("user_name");

                } catch (JSONException e) {
                    e.printStackTrace();
                }


            }
        }
Run Code Online (Sandbox Code Playgroud)


Zoh*_*Ali 5

从服务器请求中完全删除通知负载。发送数据并在 中处理它onMessageReceived(),否则onMessageReceived当应用程序在后台或被杀死时,您将不会被触发。

这是我从服务器发送的内容:

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......"
}
Run Code Online (Sandbox Code Playgroud)

所以你可以这样接收你的数据onMessageReceived(RemoteMessage message):(假设我必须获取id)

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }
Run Code Online (Sandbox Code Playgroud)

同样,您可以获取从服务器发送的任何数据onMessageReceived()


And*_*lah 5

感谢大家的回答。但我通过发送数据消息而不是发送Notification解决了这个问题。服务器代码

<?php
$url = "https://fcm.googleapis.com/fcm/send";
$token = "C-l6T_a7HouUK****";
$serverKey = "AAAAaOcKS00:********";
define( 'API_ACCESS_KEY', $serverKey );
$registrationIds = array($token);
// prep the bundle

$msg = array

(
 'message'  => 'here is a message. message',
 'title'        => 'This is a title. title',
 'subtitle' => 'This is a subtitle. subtitle',
 'tickerText'   => 'Ticker text here...Ticker text here...Ticker text 
 here',
 'vibrate'  => 1,
 'sound'        => 1,
 'largeIcon'    => 'large_icon',
 'smallIcon'    => 'small_icon'

);

$fields = array

(
  'registration_ids'    => $registrationIds,
  'data'            => $msg

);
$headers = array

(
  'Authorization: key=' . API_ACCESS_KEY,
 'Content-Type: application/json'

);


$ch = curl_init();

curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send' 
);

curl_setopt( $ch,CURLOPT_POST, true );

curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );

curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );

curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );

$result = curl_exec($ch );

curl_close( $ch );

echo $result;

?>
Run Code Online (Sandbox Code Playgroud)

并捕获 onMessageReceived 中的数据

public class MyFirebaseMessagingService extends FirebaseMessagingService     {

  private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

      sendNotification(remoteMessage.getData().get("message"));
     }
   // Check if message contains a notification payload.
    else if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    sendNotification(remoteMessage.getNotification().getBody());
    }


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

    String channelId = "idddd";
    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(MyFirebaseMessagingService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .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());
}
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

305702 次

最近记录:

5 年,11 月 前