当我构建并运行 Firebase 消息示例应用时(从我的 Firebase 控制台获取并安装自定义 google-services.json 文件后,如 Android Studio 中的向导所述),我可以使用我的测试脚本向其发送一条简单的非通知消息,并且它可以工作。
。但前提是应用已在设备上启动。
如果我无法先启动应用程序,或强制停止应用程序(从"设置"|"应用程序)启动后,消息似乎没有完全通过。(我这么说是因为我不再看到我的 onMessageReceived 方法的任何日志记录输出)。
有些人报告说,当发送消息时,即使他们的应用程序没有首先启动,他们的应用程序也会唤醒- 这很棒!正是我想要的!
但我无法弄清楚他们正在做什么来实现这一目标。
我错过了什么?我应该如何更改此代码以确保即使在应用尚未启动或应用被强制停止后也能收到消息?
注意:我运行的代码(如下)非常接近地基于 Firebase Quickstarts for Android 代码,可以从 Android Studio 中下载和构建(文件 |新品 |导入样品...,然后在填充的列表中找到"适用于 Android 的 Firebase 快速入门")。(我相信谷歌在GitHub上托管相同的代码:github.com/firebase/quickstart-android/tree/master/messaging)。我稍微修改了日志记录输出和注释。
安卓清单.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.firebase.quickstart.fcm">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- [START fcm_default_icon] -->
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
notification message. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
<!-- [END fcm_default_icon] -->
<activity
android:name="com.google.firebase.quickstart.fcm.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- [START firebase_service] -->
<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<!-- [END firebase_service] -->
<!-- [START firebase_iid_service] -->
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<!-- [END firebase_iid_service] -->
<service android:name=".MyJobService"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
</intent-filter>
</service>
</application>
MyFirebaseInstanceIDService.java
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
// [START refresh_token]
@Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(refreshedToken);
}
// [END refresh_token]
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* @param token The new token.
*/
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}
}
MyFirebaseMessagingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
// [END_EXCLUDE]
// TODO(developer): Handle FCM messages here.
Log.d(TAG, "onMessageReceived: From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "onMessageReceived: Message data payload: " + remoteMessage.getData());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
scheduleJob();
} else {
// Handle message within 10 seconds
handleNow();
}
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "onMessageReceived: Message Notification Body: " + remoteMessage.getNotification().getBody());
}
// 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.
}
// [END receive_message]
/**
* Schedule a job using FirebaseJobDispatcher.
*/
private void scheduleJob() {
// [START dispatch_job]
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));
Job myJob = dispatcher.newJobBuilder()
.setService(MyJobService.class)
.setTag("my-job-tag")
.build();
dispatcher.schedule(myJob);
// [END dispatch_job]
}
/**
* Handle time allotted to BroadcastReceivers.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
/**
* Create and show a simple notification containing the received FCM message.
*
* @param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.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());
}
}
bash 测试脚本
curl -X POST
--Header "Authorization: key=<server key from Firebase Console>“
--Header "Content-Type: application/json"
https://fcm.googleapis.com/fcm/send
-d "
{
"to”:”<token returned by FirebaseInstanceId.getInstance().getToken()>”,
"priority": "high"
}"
echo
您观察到的行为是应用处于"停止状态"的结果。 此行为是在 Android 3.1 中引入的,在已停止的应用程序上启动控件部分中进行了介绍:
首次安装应用程序时处于停止状态,但 尚未启动,并且当用户手动停止它们时 (在"管理应用程序"中)
当应用处于"已停止"状态时,系统不会向其发送广播意图,这意味着它不会收到 Firebase 消息。 据我所知,你无法解决这个问题;用户必须首次启动应用。 这会告诉系统用户希望应用正常运行,并且可以安全地向其传递广播意向。
以下是一些与停止状态相关的 SO 问题/答案。