即使应用进程已死,如何确保Firebase Messaging示例实施得到通知? [英] How to ensure that the Firebase Messaging sample implementation is notified even if app process is dead?

查看:46
本文介绍了即使应用进程已死,如何确保Firebase Messaging示例实施得到通知?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我构建并运行Firebase Messaging Sample应用程序(如Android Studio中的向导所述,从Firebase控制台获取并安装了自定义的google-services.json文件之后)时,我可以发送一条简单的非通知消息用我的测试脚本来完成它,并且可以正常工作.

When I build and run the Firebase Messaging Sample app (after obtaining and installing a custom google-services.json file from my Firebase Console, as described by the wizard within Android Studio), I can send a simple non-notification message to it with my test script, and it works.

...,但前提是已在设备上启动了该应用程序.

... but only if the app has been started on the device.

如果我无法首先启动该应用程序,或者在启动后强制停止该应用程序(通过设置" |应用程序"),则该消息似乎并没有通过. (之所以这样说是因为我不再从onMessageReceived方法中看到任何日志记录输出).

If I fail to first start the app, or force-stop the app (from Settings | Apps) after it's been started, the message doesn't quite seem to get through. (I say that because I no longer see any logging output from my onMessageReceived method).

有些人报告说,发出消息后,即使他们的应用程序尚未首先启动,它们的应用程序也会唤醒-太好了!正是我想要的!

Some have reported that when a message is sent out, their app wakes up even if their app has not first been started -- which is great! Exactly what I want!

但是我无法弄清楚他们正在做些什么来实现这一目标.

But I haven't been able to figure out what they're doing to make that happen.

我想念什么?我应该如何更改此代码,以确保即使未启动应用程序或被强制停止应用程序后仍能收到消息?

What am I missing? How should I change this code to make sure that it receives the message even when the app has not been started, or after the app has been forcibly stopped?

注意:我正在运行的代码(下)非常紧密地基于Android的Firebase快速入门,可以从Android Studio中下载和构建(文件|新建|导入示例...,然后找到"Firebase填充列表中的"Android快速入门"). (我相信Google在GitHub上托管了相同的代码:github.com/firebase/quickstart-android/tree/master/messaging‌).我修改了日志输出和注释.

Note: the code I'm running (below) is based very closely upon the Firebase Quickstarts for Android code which can be downloaded and built from within Android Studio (File | New | Import Sample ... and then find "Firebase Quickstarts for Android" within the list it populates). (I believe that Google hosts that same code on GitHub here: github.com/firebase/quickstart-android/tree/master/messaging‌​). I modified the logging output and comments slightly.

AndroidManifest.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中引入的,在本部分的 中进行了描述在停止的应用程序上启动控件:

The behavior you are observing is the result of the app being in the "Stopped State". This behavior was introduced in Android 3.1 and is described here in the section Launch controls on stopped applications:

应用程序在首次安装时处于停止状态,但是 还没有启动,以及当用户手动停止它们时 (在管理应用程序"中)

Applications are in a stopped state when they are first installed but are not yet launched and when they are manually stopped by the user (in Manage Applications)

当应用程序处于已停止"状态时,系统将不会向其传递广播意图",这意味着它将不会接收Firebase消息.据我所知,你无法解决这个问题.用户必须首次启动该应用.这告诉系统用户希望该应用程序可运行,并且可以安全地向其传递广播意图.

When an app is in Stopped state, the system will not deliver Broadcast intents to it, which means it will not receive Firebase messages. As far as I know, you can't get around this; the user must start the app for the first time. This tells the system that the user wants the app to be operational and it is safe to deliver Broadcast intents to it.

以下是一些与停止状态有关的问题/答案.

这篇关于即使应用进程已死,如何确保Firebase Messaging示例实施得到通知?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆