Уведомления Android с Firebase Cloud Messaging не получены

Я много раз искал уведомления, когда приложение находится в фоновом режиме или закрыто. Кстати, я использую Firebase Cloud Messaging. Это не сработает для меня. Я использовал настройку Android и когда приложение находится на переднем плане или телефон не заблокирован, уведомление получено.

  • При установке маркер правильно напечатан и подписан на тему.
  • Когда я отправляю уведомление, когда приложение активно на переднем плане (так что экран разблокирован и отображается приложение), я получаю уведомление и заголовок, как указано в onMessageReceived.
  • Когда я отправляю уведомление, когда приложение не показано, но все еще находится в последних приложениях, а экран разблокирован. Я получаю уведомление с заголовком и сообщением, как указано в notification payload.
  • Когда я отправляю уведомление, когда приложение не показано, но все еще находится в последних приложениях, а экран заблокирован, ничего не получено.
  • Когда я отправляю уведомление, когда приложение * закрыто и удалено из последних приложений, ничего не получено.

Как я могу изменить это, чтобы приложение всегда получало уведомления, даже если оно закрыто или телефон заблокирован?

Ps. Я прочитал о модусе Doze с защищенными приложениями, даже когда я помещаю свое приложение в защищенные, я ничего не получаю. Я тестирую на Huawei 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 servers.
        sendRegistrationToServer(refreshedToken);
     }

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user 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"
     }
}

EDIT - добавьте код для 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);
    }
}

ОБНОВЛЕНИЕ PAYLOAD

Если я изменю свою полезную нагрузку на предлагаемый способ, в комментариях, подобных этому, он все еще не работает. Возможно, это имеет какое-то отношение к Huawei P8 Lite, который я тестирую с установленным Android 6.0.1.

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

ОБНОВЛЕНИЕ 2.0

Я тестировал несколько устройств и версий. На устройствах с Android 5 он работал нормально, также без приложения открыто и заблокировано. Только устройство, в котором он не работал, был моим собственным Huawei P8 Lite. Все еще не могу понять, почему он не работает над этим.

Ответ 1

У меня также были проблемы с устройствами, которые не получали уведомления, когда они были закрыты, как и после перезапуска.

Оказалось, что он не работал с версией решения DEBUG, поэтому его нужно было протестировать в РЕЛЕЙЕ РЕЖИМА. Для тех, кто использует Android Studio, нажмите кнопку зеленого воспроизведения рядом с кнопкой отладки.

Ответ 2

Когда приложение закрыто, он отключает службу. Необходимо перезапустить службу.

В вашем классе 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);
    }
}