使用Firebase Cloud Messaging的Android后台通知未收到

4
我在寻找关于应用程序在后台或关闭时通知的信息。我顺便使用 Firebase Cloud Messaging。但是它对我没有用,我已经使用了 Android 设置,当应用程序在前台或手机未锁定时,通知能够收到。
  • 当安装时,令牌被正确打印,并订阅了主题。
  • 当我在应用程序在前台活动时发送通知(因此屏幕已解锁并显示应用程序),我将按照onMessageReceived中指定的通知和标题接收到通知。
  • 当我在应用程序未显示但仍在最近的应用程序中,屏幕已解锁时发送通知,我将按照notification payload中指定的标题和消息接收到通知。
  • 当我在应用程序未显示但仍在最近的应用程序中,屏幕已锁定时发送通知,将无法接收任何内容。
  • 当应用程序*已关闭并从最近的应用程序中删除时,将无法接收任何内容。

我该如何更改设置以便应用程序始终能够在关闭或锁定手机时接收通知?

附:我了解受保护应用程序的Doze模式,但即使我将我的应用程序与受保护的应用程序放在一起,我仍然无法接收到通知。我正在华为P8 Lite上进行测试。

AndroidManifest

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >
    <activity android:name=".activities.MainActivity"
        android:configChanges="orientation"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service
        android:name=".services.MyAppFirebaseMessagingService"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
    </service>
    <service
        android:name=".services.FirebaseIDService"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
        </intent-filter>
    </service>
    <receiver android:name=".services.NotificationReceiver" />
</application>

Gradle

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.google.firebase:firebase-core:9.2.0'
    compile 'com.google.firebase:firebase-messaging:9.2.0'
}

apply plugin: 'com.google.gms.google-services'

FirebaseMessagingService

public class MyAppFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "FCM Service";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // TODO: 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.
        Log.d(TAG, "From: " + remoteMessage.getFrom());
        Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());

        showNotification(getApplicationContext());
    }

    public static void showNotification(Context context){
        Intent intent = new Intent(context, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentTitle("FCM Message")
            .setContentText("FCM Body")
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setPriority(Notification.PRIORITY_MAX)
            .setContentIntent(pendingIntent);

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

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

FirebaseInstanceIDService

public class FirebaseIDService extends FirebaseInstanceIdService {

    private static final String TAG = "FirebaseIDService";

    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);

        System.out.println("Devicetoken: " + refreshedToken);

        FirebaseMessaging.getInstance().subscribeToTopic("/topics/myapp");

        // TODO: Implement this method to send any registration to your app's servers.
        sendRegistrationToServer(refreshedToken);
     }

    /**
     * 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) {
         // Add custom implementation, as needed.
    }
}

通知负载

{
    "to": "/topics/mytopic",
    "priority": "high",
    "notification": {
        "sound": "default",
        "badge": "1",
        "body": "the body text",
        "title": "title text"
     },
     "data": {
         "id": "id",
         "channel": "channel"
     }
}

编辑 - 添加WakeFulBroadcastReceiver的代码

public class NotificationReceiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // cancel any further alarms
        AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        alarmMgr.cancel(alarmIntent);
        completeWakefulIntent(intent);

        // start the GcmTaskService
        MyAppFirebaseMessagingService.showNotification(context);
    }
}

更新负载

如果我按照评论中建议的方式更改了负载,像这样,它仍然无法工作。也许这与我正在测试的安装有Android 6.0.1的华为P8 Lite有关。

{
    "to": "/topics/mytopic",
    "priority": "high",
    "data": {
        "sound": "default",
        "badge": "1",
        "body": "the body text",
        "title": "title text"
    }
}

更新 2.0

我已在多个设备和版本上进行了测试。在安卓5系统的设备上,它运行良好,即使没有打开应用程序并锁定屏幕也可以正常工作。唯一不能工作的是我的华为P8 Lite手机。我仍然无法弄清楚为什么它在这部手机上无法工作。


可能(重复)(我从未使用过新的Firebase Cloud Messaging,但在GCM中,您需要一个WakefulBroadcastReceiver,具有WakeLock权限并在清单中声明的接收器才能在应用关闭时接收) - Lucas Queiroz Ribeiro
3
耶稣,为什么你会给一个接收器取名“Service”?祝你能够顺利维护自己的代码。 - Eugen Pechanec
如果通知负载包含“notification”,则仅当您的应用程序在前台时,onMessageReceived将被调用。当它在后台时,Google Play服务将根据“notification”负载为您创建并发布通知。 - Eugen Pechanec
如果我将我的有效载荷更改为{"to": "/topics/mytopic","priority": "high","data": {"sound": "default","badge": "1","body": "the body text","title": "title text"}},它仍然无法工作。或者这个有效载荷不是正确的格式吗? - Tom Spee
从您的有效载荷中移除通知标记。 - tyczj
显示剩余7条评论
4个回答

8
当应用程序关闭时,它会关闭服务。您必须重新启动服务。
在您的Application类中,实现ActivityLifecycleCallbacks,并在onActivityDestroyed中使用闹钟重新启动服务。
public class YourApplication extends Application implements Application.ActivityLifecycleCallbacks {
    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(this);
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
            Intent restartService = new Intent(getApplicationContext(), MyAppFirebaseMessagingService.class);
            PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(),1,restartService,PendingIntent.FLAG_ONE_SHOT);
            AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
            alarmManager.set(AlarmManager.ELAPSED_REALTIME,5000,pendingIntent);
    }
}

5

我也遇到了设备在关闭后(例如重新启动后)没有收到通知的问题。

后来发现,这是由于解决方案使用 DEBUG 版本而导致的,因此必须在 RELEASE 模式下进行测试。如果您使用的是 Android Studio,请按照调试按钮旁边的绿色播放按钮。


0

Firebase有不同类型的通知,每种都有特殊的处理方式。

  • 假设您正在使用数据推送,则不需要特殊处理或WakefulBroadcastReceiver。
  • 如果您正在使用通知推送,则通知将自动显示在系统托盘中。您无法在那里进行任何特殊处理。

请在此处查看官方文档:https://firebase.google.com/docs/cloud-messaging/android/receive


0

尝试进行设置

"priority" : "high"

在从后端推送通知时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接