如何在Firebase中的后台应用中处理通知
这是我的清单
<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>
当应用程序在后台,通知到达时,默认通知来,并不会运行我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]
1.为什么发生这种情况?
在FCM中有两种types的消息(Firebase云消息传递):
- 显示消息 :只有当您的应用处于前台时,这些消息才会触发
onMessageReceived()
callback - 数据消息 : 即使您的应用程序处于前景/背景/死亡状态,这些消息也会触发
onMessageReceived()
callback
Firebase团队还没有开发一个UI来发送data-messages
到您的设备。
2.如何?
要做到这一点,你必须执行POST
到以下URL:
和以下标题:
- 键:
Content-Type
, 值:application/json
- 密钥:
Authorization
, 值:key=<your-server-key>
正文使用主题 :
{ "to": "/topics/my_topic", "data": { "my_custom_key" : "my_custom_value", "other_key" : true } }
或者,如果您想将其发送到特定设备:
{ "data": { "my_custom_key" : "my_custom_value", "other_key" : true }, "registration_ids": ["{device-token}","{device2-token}","{device3-token}"] }
注意:确保你没有添加 JSON密钥
notification
注意:要获得服务器密钥,您可以在Firebase控制台中find它: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 }
在以下情况下,让firebase库调用onMessageReceived()
- 在前台的应用程序
- App在背景中
- 应用程序已被杀害
您不能将JSON密钥“通知”放入您对Firebase API的请求中,而是使用“数据”,如下所示。
当您的应用程序处于后台或被终止时,以下消息将不会调用onMessageReceived() ,并且您无法自定义您的通知。
{ "to": "/topics/journal", "notification": { "title" : "title", "text": "data!", "icon": "ic_notification" } }
但相反,使用这将工作
{ "to": "/topics/dev_journal", "data": { "text":"text", "title":"", "line1":"Journal", "line2":"刊物" } }
基本上,这个消息是通过RemoteMessage参数和数据对象一起发送的,然后你可以像这里的代码片段那样pipe理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 */ }
我觉得所有的反应都是不完整的,但是当你的应用程序处于后台时,他们都有一些需要处理的通知。
按照这些步骤,当您的应用程序处于后台时,您将能够处理您的通知。
1.添加一个像这样的意图filter:
<activity android:name=".MainActivity"> <intent-filter> <action android:name=".MainActivity" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
到您想要处理通知数据的活动。
-
用下一个格式发送通知:
{ "notification" : { "click_action" : ".MainActivity", "body" : "new Symulti update !", "title" : "new Symulti update !", "icon" : "ic_notif_symulti" }, "data": { ... }, "to" : "c9Vaa3ReGdk:APA91bH-AuXgg3lDN2WMcBrNhJZoFtYF9" }
这里的关键是添加
"click_action" : ".MainActivity"
其中.MainActivity是您在步骤1中添加的意图filter的活动。
-
在“.MainActivity”的onCreate中从通知中获取“data”信息:
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 }}
而这应该是你需要做的一切。 我希望这有助于某人:)
根据文件
在后台应用程序中处理消息
当您的应用程序处于后台时,Android会将通知消息导向系统托盘。 用户点击通知会默认打开应用程序启动器。
这包括包含通知和数据负载的消息。 在这些情况下,通知将传递到设备的系统托盘,并且数据有效载荷以您启动程序活动的目的附加内容传递。
如果要打开应用并执行特定操作,请在通知负载中设置click_action,并将其映射到要启动的Activity中的intentfilter。 例如,将click_action设置为OPEN_ACTIVITY_1以触发一个意图filter,如下所示:
<intent-filter> <action android:name="OPEN_ACTIVITY_1" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
编辑:
基于这个线程 :
您无法使用Firebase控制台设置click_action负载。 您可以尝试使用curl命令或自定义http服务器进行testing
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\"}}"
根据Firebase下载的firebase文档,有两种有效载荷:
-
数据
该参数指定消息有效负载的自定义键值对。 客户端应用程序负责处理数据消息。 数据消息只有自定义的键值对。
-
通知
此参数指定通知有效负载的预定义的用户可见键值对。 FCM代表客户端应用程序自动向最终用户设备显示消息。 通知消息具有预定义的一组用户可见密钥。
当你在前台,你可以使用onMessageReceived()获取FCM中的数据,你可以从数据有效载荷中获取你的数据。
data = remoteMessage.getData(); String customData = (String) data.get("customData");
当您在后台时,FCM将根据通知有效负载中的信息在系统托盘中显示通知。 系统托盘上用于通知的标题,消息和图标是从通知负载中获取的。
{ "notification": { "title" : "title", "body" : "body text", "icon" : "ic_notification" } }
当您想在应用程序处于后台时自动显示系统托盘上的通知时使用此通知有效内容。 要在后台应用程序中获取通知数据,您应该在通知有效内容中添加click_action。
如果要打开应用程序并执行特定的操作,请在通知负载中设置click_action,并将其映射到要启动的Activity中的intentfilter。 例如,将click_action设置为OPEN_ACTIVITY_1以触发一个意图filter,如下所示:
<intent-filter> <action android:name="OPEN_ACTIVITY_1" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
将该意图filter放在应用程序标签内的清单上。 当您点击通知时,它会打开应用程序并直接转到您在click_action中定义的活动,在本例中为“OPEN_ACTIVTY_1”。 在这个活动中,你可以通过以下方式获得数据:
Bundle b = getIntent().getExtras(); String someData = b.getString("someData");
我使用FCM为我的Android应用程序,并使用两个有效载荷。 这里是我使用的示例JSON:
{ "to": "FCM registration ID", "notification": { "title" : "title", "body" : "body text", "icon" : "ic_notification" }, "data": { "someData" : "This is some data", "someData2" : "etc" } }
要在后台捕获邮件,您需要使用BroadcastReceiver
public class FirebaseDataReceiver extends WakefulBroadcastReceiver { private final String TAG = "FirebaseDataReceiver"; public void onReceive(Context context, Intent intent) { Log.d(TAG, "I'm in!!!"); Bundle dataBundle = intent.getBundleExtra("data"); Log.d(TAG, dataBundle.toString()); } }
并将其添加到您的清单:
<receiver android:name="MY_PACKAGE_NAME.FirebaseDataReceiver" 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>
由于只有您的应用位于前台,Firebase通知用户界面发送的display-messages
才有效。 对于data-messages
,需要对FCM进行POST调用
脚步
-
安装高级Rest客户端Google Chrome扩展程序
-
添加以下标题
键 :内容types, 值 :application / json
密钥 :授权, 值 :key =“您的服务器密钥”
-
添加正文
- 如果使用主题:
{ "to" : "/topics/topic_name", "data": { "key1" : "value1", "key2" : "value2", } }
- 如果使用注册ID:
{ "registration_ids" : "[{"id"},{id1}]", "data": { "key1" : "value1", "key2" : "value2", } }
而已!。 现在像往常一样收听onMessageReceived
callback。
@Override public void onMessageReceived(RemoteMessage remoteMessage) { Map<String, String> data = remoteMessage.getData(); String value1 = data.get("key1"); String value2 = data.get("key2"); }
这里是关于firebase消息的更清晰的概念。 我从他们的支持团队find了它。
Firebase有三种消息types :
通知消息 :通知消息在后台或前台工作。 当应用程序在后台时,通知消息被传递到系统托盘。 如果应用程序处于前台,则消息由onMessageReceived()
或didReceiveRemoteNotification
callback处理。 这些实质上就是所谓的显示消息。
数据信息 :在Android平台上,数据信息可以在后台和前台工作。 数据消息将由onMessageReceived()处理。 这里的平台特定的注意事项是:在Android上,数据有效载荷可以在用于启动您的活动的Intent中检索。 详细说明一下,如果你有"click_action":"launch_Activity_1"
,你可以通过只有Activity_1
getIntent()
来获取这个intent。
具有通知和数据有效载荷的消息 :在后台时,应用程序在通知托盘中接收通知有效内容,并且只在用户点击通知时处理数据有效载荷。 在前台时,您的应用程序会收到一个消息对象,其中都有可用的有效负载。 其次, click_action
参数通常用于通知有效载荷,而不是数据有效载荷。 如果在数据有效负载中使用,则此参数将被视为自定义键值对,因此您需要实现自定义逻辑才能按预期工作。
此外,我build议您使用onMessageReceived
方法(请参阅数据消息)来提取数据包。 从你的逻辑,我检查了捆绑对象,并没有find预期的数据内容。 这里提供一个类似的案例,可能会提供更多的清晰度。
更多信息请访问我的这个线程
@Override public void onMessageReceived(RemoteMessage remoteMessage) { }
每次仅在应用程序处于forground时才被调用
有一个覆盖方法每次都调用这个方法,不pipe前台或后台是什么app或者是杀了这个方法都可以用这个firebase api版本
这是你必须从gradle导入的版本
compile 'com.google.firebase:firebase-messaging:10.2.1'
这是方法
@Override public void handleIntent(Intent intent) { super.handleIntent(intent); // you can get ur data here //intent.getExtras().get("your_data_key") }
与以前的firebase api这种方法是不存在的,所以在这种情况下,当应用程序在背景中的消防基地处理自己….现在你有这个方法什么都想要做…你可以在这里做这个方法.. …
如果您使用的是以前的版本,那么默认的活动将会在这种情况下开始
if(getIntent().getExtras() != null && getIntent().getExtras().get("your_data_key") != null) { String strNotificaiton = getIntent().getExtras().get("your_data_key").toString();
//做你想做的事情….}
一般来说,这是我们从通知中得到的服务器的结构
{ "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": "......." } }
这取决于你如何给这个数据键或者你想给任何你可以给的通知…….你会用同样的关键你会得到这些数据…….. 。
有很less的情况下,如果你不发送点击动作的情况下,当你点击通知默认活动将打开,但如果你想打开你的具体活动,当应用程序在后台你可以调用你的活动,从这个handleIntent方法,因为这每次都被调用
这样简单的总结
-
如果你的应用程序运行;
onMessageReceived()
是触发器。
-
如果你的应用程序没有运行(通过刷卡杀死);
onMessageReceived()
没有被直接触发和传递。 如果你有任何特殊的键值对。 他们没有工作的onMessageReceived()不起作用。
我find了这个方法;
在你的发射器活动中,把这个逻辑,
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 } }
在这个if block中,根据firebase UIsearch你的密钥。
在这个例子中,我的关键和价值如上; (对于语言=抱歉))
当我的代码工作,我得到“com.rda.note”。
android.os.Process.killProcess(android.os.Process.myPid());
用这行代码,我closures了我的应用程序并打开了Google Play Market
开心编码=)
根据文档:2017年5月17日
当您的应用程序处于后台时 ,Android会将通知消息导向系统托盘。 用户点击通知会默认打开应用程序启动器 。
这包括包含通知和数据负载(以及通知控制台发送的所有消息)的消息。 在这些情况下,通知将传递到设备的系统托盘,并且数据有效载荷以您启动程序活动的目的附加内容传送。
所以,你应该使用有效载荷通知+数据:
{ "to": "FCM registration ID", "notification": { "title" : "title", "body" : "body text", "icon" : "ic_notification" }, "data": { "someData" : "This is some data", "someData2" : "etc" } }
没有必要使用click_action.You应该只是从意图的LAUNCHER活动获取的文件
<activity android:name=".MainActivity"> <intent-filter> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
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"); }
您可以从Firebase通知控制台testing有效负载通知+数据。 不要忘记在“高级选项”部分填写自定义数据字段
2017更新了答案
这里是关于这个文档的一个明确的答案:
从您的服务器请求中完全删除通知有效载 只发送数据并在onMessageReceived()
,否则当应用程序处于后台或被onMessageReceived
时, onMessageReceived
不会被触发。
这是我从服务器发送的内容:
{ "data":{ "id": 1, "missedRequests": 5 "addAnyDataHere": 123 }, "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......" }
所以你可以在onMessageReceived(RemoteMessage message)
接收你的数据,像这样:(假设我必须得到id)
Object obj = message.getData().get("id"); if (obj != null) { int id = Integer.valueOf(obj.toString()); }
同样,你可以从onMessageReceived()
获得你从服务器发送的任何数据。
即使应用程序位于后台和前台,发送消息的简单方法如下: – 要使用API发送消息,可以使用名为AdvancedREST Client的工具,其扩展名为Chrome,并使用以下参数发送消息。
Rest客户端工具链接: https : //chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo
使用此url: – https://fcm.googleapis.com/fcm/send内容types:应用程序/ JSON授权:密钥=您的服务器密钥来自或自动化密钥(见下文参考)
{ "data": { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", "message": "Firebase Push Message Using API" "AnotherActivity": "True" }, "to" : "device id Or Device token" }
授权密钥可以通过访问Google开发者控制台并点击项目左侧菜单上的Credentialsbutton来获得。 列出的API密钥中,服务器密钥将是您的授权密钥。
而且您需要将接收器的tokenID放在使用API发送的POST请求的“to”部分。
我想出了情景,
当应用程序处于前台时 ,将从FirebaseService调用onMessageReceived()方法。因此将调用服务类中定义的pendingIntent 。
而当应用程序在后台 , 第一个活动被调用。
现在,如果您使用的是splash活动 ,那么必须记住splashactivity将被调用,否则如果没有splashActivity,那么无论第一个活动是什么,都将被调用。
然后,您需要检查firstActivity的 getIntent()以查看它是否有任何捆绑。如果一切正常,您会看到捆绑有填充值。如果从服务器发送的数据标记中的值看起来像这样,
"data": { "user_name": "arefin sajib", "value": "user name notification" }
然后在第一个活动中,你会看到,有一个有效的意图( getIntent()不是null ),有效的捆绑和内部捆绑,将上面提到的整个JSON与数据作为关键 。
对于这种情况,提取值的代码将如下所示,
if(getIntent()!=null){ Bundle bundle = getIntent().getExtras(); if (bundle != null) { JSONObject jsonResponse = new JSONObject(); try { JSONObject object = new JSONObject(bundle.getStringExtra("data")); String user_name = object.optString("user_name"); } catch (JSONException e) { e.printStackTrace(); } } }
我遇到了同样的问题,重新编译了firebase库,并阻止它在应用程序处于后台时发送通知
*图书馆https://github.com/erdalceylan/com-google-firebase-messaging
dependencies { compile 'com.google.firebase:firebase-core:11.2.0' compile 'com.github.erdalceylan:com-google-firebase-messaging:v1-11.2.0' }
*
@WorkerThread public void onMessageReceived(RemoteMessage var1) { //your app is in background or foreground all time calling }
希望有帮助。 祝你好运