web-dev-qa-db-ja.com

アプリがバックグラウンドで起動しているときにFirebase onMessageReceivedが呼び出されない

私はFirebaseを使用していて、アプリがバックグラウンドにある間にサーバーから自分のアプリに通知を送信することをテストしています。通知は正常に送信され、デバイスの通知センターにも表示されますが、通知が表示されたときやクリックしても、FCMessagingService内のonMessageReceivedメソッドは呼び出されません。

私のアプリがフォアグラウンドにある間にこれをテストしたとき、onMessageReceivedメソッドが呼び出され、すべてうまくいきました。アプリがバックグラウンドで実行されているときに問題が発生します。

これは意図した動作ですか?それとも修正できる方法はありますか?

これが私のFBMessagingServiceです:

import Android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class FBMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i("PVL", "MESSAGE RECEIVED!!");
        if (remoteMessage.getNotification().getBody() != null) {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
        } else {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
        }
    }
}
181
Cyogenos

これは意図したとおりに機能しています。通知メッセージは、アプリがフォアグラウンドにある場合にのみonMessageReceivedコールバックに配信されます。アプリがバックグラウンドまたは閉じている場合、通知メッセージが通知センターに表示され、そのメッセージからの データがインテントに渡されます ユーザーが通知をタップした結果として起動されます。

ユーザーが通知をタップしたときに起動する必要があることを示すclick_actionを指定できます。 click_actionが指定されていない場合は、メインアクティビティが使用されます。

インテントが起動されたら、あなたは

getIntent().getExtras();

通知メッセージとともに送信されたデータを含むSetを取得します。

通知メッセージの詳細については docs を参照してください。

111
Arthur Thompson

サーバー要求からnotificationフィールド を完全に削除します。 のみdataを送信してonMessageReceived()で処理すると、アプリがバックグラウンドまたは殺害されたときにonMessageReceived()はトリガーされません。

通知リクエストに"priority": "high"フィールドを含めることを忘れないでください。資料によると:データメッセージは通常の優先順位で送信されるので、それらは即座に到着しません。それはまた問題である可能性があります。

これは私がサーバーから送信しているものです

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......",
  "priority": "high"
}

だからあなたはこのようにonMessageReceived(RemoteMessage message)であなたのデータを受け取ることができます....私はidを取得する必要があるとしましょう

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }
87
Zohab Ali

このメソッドhandleIntent()は推奨されなくなったので、通知の処理は以下のように行うことができます。

  1. フォアグラウンド状態:通知をクリックすると、通知のデータペイロードを使用して一般的に作成されるように、通知をプログラム的に作成しながら、提供している保留中のIntentのアクティビティに移動します。

  2. Background/Killed State - ここでは、システム自体が通知ペイロードに基づいて通知を作成し、その通知をクリックするとアプリケーションのランチャーアクティビティに移動します。ここで、あらゆるライフサイクル方法でIntentデータを簡単に取得できます。

61
manas.abrol

私は同じ問題を抱えていました。 「通知」の代わりに「データメッセージ」を使用する方が簡単です。データメッセージは常にクラスonMessageReceivedをロードします。

そのクラスでは、notificationbuilderであなた自身の通知をすることができます。

例:

 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        sendNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
    }

    private void sendNotification(String messageTitle,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_UPDATE_CURRENT);

        long[] pattern = {500,500,500,500,500};

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setLights(Color.BLUE,1,1)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
25
Koot

Firebase Cloud Messagingのドキュメントに従って - Activityがフォアグラウンドにある場合、onMessageReceivedが呼び出されます。アクティビティがバックグラウンドであるか終了している場合、通知メッセージがアプリランチャーアクティビティの通知センターに表示されます。アプリがバックグラウンドで動作している場合は、Firebase Messagingのrest service apiを呼び出すことで、カスタマイズしたアクティビティを通知のクリックで呼び出すことができます。

URL - https://fcm.googleapis.com/fcm/send

メソッドの種類 - POST

Header- Content-Type:application/json
Authorization:key=your api key

ボディ/ペイロード:

{ "notification": {
    "title": "Your Title",
    "text": "Your Text",
     "click_action": "OPEN_ACTIVITY_1" // should match to your intent filter
  },
    "data": {
    "keyname": "any value " //you can get this data as extras in your activity and this data is optional
    },
  "to" : "to_id(firebase refreshedToken)"
} 

そしてあなたのアプリでこれを使ってあなたは呼ばれるためにあなたの活動に以下のコードを追加することができます:

<intent-filter>
                <action Android:name="OPEN_ACTIVITY_1" />
                <category Android:name="Android.intent.category.DEFAULT" />
            </intent-filter>
21
Ankit Adlakha

これがfirebaseメッセージに関するより明確な概念です。私は彼らのサポートチームからそれを見つけました。

Firebaseには3つのメッセージタイプがあります

通知メッセージ :通知メッセージは背景または前景で機能します。アプリがバックグラウンドにあるとき、通知メッセージはシステムトレイに配信されます。アプリがフォアグラウンドにある場合、メッセージはonMessageReceived()またはdidReceiveRemoteNotificationコールバックによって処理されます。これらは基本的に表示メッセージと呼ばれるものです。

データメッセージ :Androidプラットフォームでは、データメッセージは背景と前景で機能します。データメッセージはonMessageReceived()によって処理されます。プラットフォーム固有の注意事項は次のとおりです。Androidでは、データペイロードはアクティビティを起動するために使用されるIntentで取得できます。詳しくは、"click_action":"launch_Activity_1"がある場合は、Activity_1からgetIntent()を通してこの意図を取得できます。

通知ペイロードとデータペイロードの両方を持つメッセージ :バックグラウンドでは、アプリは通知トレイで通知ペイロードを受け取り、ユーザーが通知をタップしたときにのみデータペイロードを処理します。フォアグラウンドになると、アプリは両方のペイロードが利用可能なメッセージオブジェクトを受け取ります。次に、click_actionパラメータは、データペイロードではなく、通知ペイロードでよく使用されます。データペイロード内で使用された場合、このパラメータはカスタムのキーと値のペアとして扱われるため、意図したとおりに動作するようにカスタムロジックを実装する必要があります。

また、データバンドルを抽出するにはonMessageReceivedメソッド(データメッセージを参照)を使用することをお勧めします。あなたの論理から、私はバンドルオブジェクトをチェックしました、そして、期待されたデータ内容を見つけませんでした。これは、より明確にすることができる同様のケースへの参照です。

より多くの情報のために私の このスレッド そして このスレッドを訪問しなさい

21

アプリがバックグラウンドモードまたは非アクティブ(kill)になっていて、 click on Notification の場合、LaunchScreenでペイロードを確認する必要があります(私の場合は起動画面はMainActivity.Javaです)。 。

だから MainActivity.Java on onCreate Extras をチェックする:

    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("MainActivity: ", "Key: " + key + " Value: " + value);
        }
    }
11
Gent Berani

私は同じ問題を抱えています。アプリがフォアグラウンドの場合 - 通知の種類に基づいてデータベースを更新できるバックグラウンドサービスがトリガーされます。しかし、アプリはバックグラウンドになります - デフォルトの通知サービスは、ユーザーに通知を表示するように気をつけます。

これは、バックグラウンドでアプリを識別してバックグラウンドサービスをトリガーするための私の解決策です。

public class FirebaseBackgroundService extends WakefulBroadcastReceiver {

  private static final String TAG = "FirebaseService";

  @Override
  public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "I'm in!!!");

    if (intent.getExtras() != null) {
      for (String key : intent.getExtras().keySet()) {
        Object value = intent.getExtras().get(key);
        Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value);
        if(key.equalsIgnoreCase("gcm.notification.body") && value != null) {
          Bundle bundle = new Bundle();
          Intent backgroundIntent = new Intent(context, BackgroundSyncJobService.class);
          bundle.putString("Push_message", value + "");
          backgroundIntent.putExtras(bundle);
          context.startService(backgroundIntent);
        }
      }
    }
  }
}

Manifest.xmlで

<receiver Android:exported="true" Android:name=".FirebaseBackgroundService" Android:permission="com.google.Android.c2dm.permission.SEND">
            <intent-filter>
                <action Android:name="com.google.Android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </receiver>

最新のAndroid 8.0バージョンでこのソリューションをテストしました。ありがとう

8

handleIntentメソッドのFirebaseMessageServiceメソッドをオーバーライドしてください。

こちらのコードは C#(Xamarin)

public override void HandleIntent(Intent intent)
{
    try
    {
        if (intent.Extras != null)
        {
            var builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            foreach (string key in intent.Extras.KeySet())
            {
                builder.AddData(key, intent.Extras.Get(key).ToString());
            }

            this.OnMessageReceived(builder.Build());
        }
        else
        {
            base.HandleIntent(intent);
        }
    }
    catch (Exception)
    {
        base.HandleIntent(intent);
    }
}

そしてそれが Java のコードを意味します

public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }

            onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}
7
t3h Exi

デフォルトでは、 Launcher Activity inアプリは、アプリがバックグラウンドになっているときに通知をクリックすると起動されます。通知付きのデータ部分がある場合は、次のように同じアクティビティで処理できます。

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}
5
Uzair

アプリがバックグラウンドで起動している場合デフォルトで通知を処理しますが、カスタムデータを送信したい場合は、サーバー側を変更する必要があります。

サーバー要求から通知ペイロードを完全に削除します。データのみを送信し、onMessageReceived()で処理すると、アプリがバックグラウンドまたは殺害されたときにonMessageReceivedがトリガーされません。

今、あなたのサーバー側のコードフォーマットは次のようになります、

{
  "collapse_key": "CHAT_MESSAGE_CONTACT",
  "data": {
    "loc_key": "CHAT_MESSAGE_CONTACT",
    "loc_args": ["John Doe", "Contact Exchange"],
    "text": "John Doe shared a contact in the group Contact Exchange",
    "custom": {
      "chat_id": 241233,
      "msg_id": 123
    },
    "badge": 1,
    "sound": "sound1.mp3",
    "mute": true
  }
}

_ note _ :上記のコードのこの行を参照
"text": "John Doeはデータペイロードの" Contact Exchange "グループの連絡先を共有しましたメッセージの説明には" body "または" message "パラメータの代わりに" text "パラメータを使用してください。テキスト。

onMessageReceived()

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.e(TAG, "From: " + remoteMessage.getData().toString());

        if (remoteMessage == null)
            return;

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
           /* Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());*/
            Log.e(TAG, "Data Payload: " + remoteMessage);

            try {

                Map<String, String> params = remoteMessage.getData();
                JSONObject json = new JSONObject(params);
                Log.e("JSON_OBJECT", json.toString());


                Log.e(TAG, "onMessageReceived: " + json.toString());

                handleDataMessage(json);
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
        }
    }
3
Hiren

onMessageReceived(RemoteMessage remoteMessage)メソッドは、次の場合に基づいて呼び出されます。

  • FCM ResponseWithnotificationanddataブロック:

{"to": "デバイストークンリスト"、 "notification":{"body": "通知の本文" 、 "title": "通知のタイトル"}、 "data":{"body": "データ内の通知のボディ"、 "title": "タイトルタイトルの通知」、「key_1」:「key_1の値」、「image_url」:「www.abc.com/xyz.jpeg」、「key_2」:「key_2の値」}}

  1. フォアグラウンドのアプリ:

onMessageReceived(RemoteMessage remoteMessage)が呼び出され、通知バーにLargeIconとBigPictureが表示されます。 notificationdataブロックの両方からコンテンツを読み取ることができます

  1. バックグラウンドでのアプリ:

onMessageReceived(RemoteMessage remoteMessage)呼び出されない場合、システムトレイはメッセージを受信し、notificationブロックから本文とタイトルを読み取り、デフォルトのメッセージを表示します通知バーのタイトル。

  • FCM応答dataブロックのみの場合:

この場合、jsonからnotificationブロックを削除します

{"to": "デバイストークンリスト"、 "data":{"body": "通知の本文Data」、「title」:「タイトルの通知のタイトル」、「key_1」:「key_1の値」、,「image_url」:「www.abc.com/xyz.jpeg」、「key_2」:「key_2の値"}}

  1. フォアグラウンドのアプリ:

onMessageReceived(RemoteMessage remoteMessage)が呼び出され、通知バーにLargeIconとBigPictureが表示されます。 notificationdataブロックの両方からコンテンツを読み取ることができます

  1. バックグラウンドでのアプリ:

onMessageReceived(RemoteMessage remoteMessage)が呼び出されました。notificationキーが応答にないため、システムトレイはメッセージを受信しません。通知バーにLargeIconとBigPictureを表示します

コード

 private void sendNotification(Bitmap bitmap,  String title, String 
    message, PendingIntent resultPendingIntent) {

    NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
    style.bigPicture(bitmap);

    Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    String NOTIFICATION_CHANNEL_ID = mContext.getString(R.string.default_notification_channel_id);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);

        notificationManager.createNotificationChannel(notificationChannel);
    }
    Bitmap iconLarge = BitmapFactory.decodeResource(mContext.getResources(),
            R.drawable.mdmlogo);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.mdmlogo)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(defaultSound)
            .setContentText(message)
            .setContentIntent(resultPendingIntent)
            .setStyle(style)
            .setLargeIcon(iconLarge)
            .setWhen(System.currentTimeMillis())
            .setPriority(Notification.PRIORITY_MAX)
            .setChannelId(NOTIFICATION_CHANNEL_ID);


    notificationManager.notify(1, notificationBuilder.build());


}

参照リンク:

https://firebase.google.com/docs/cloud-messaging/Android/receive

3
vishnuc156

t3H Exiからの解決策によると、私はここにきれいなコードを投稿したいと思います。 MyFirebaseMessagingServiceに配置するだけで、アプリがバックグラウンドモードになっていればすべて正常に動作します。少なくともcom.google.firebase:firebase-messaging:10.2.1をコンパイルする必要があります。

 @Override
public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }



           onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}
2
Frank

MainActivityのonCreateメソッドでこれを呼び出すだけです。

if (getIntent().getExtras() != null) {
           // Call your NotificationActivity here..
            Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
            startActivity(intent);
        }
2
Shekhar

これを試して:

public void handleIntent(Intent intent) {
    try {
        if (intent.getExtras() != null) {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            for (String key : intent.getExtras().keySet()) {
            builder.addData(key, intent.getExtras().get(key).toString());
        }
            onMessageReceived(builder.build());
        } else {
            super.handleIntent(intent);
        }
    } catch (Exception e) {
        super.handleIntent(intent);
    }
}
2
user3587828

強調表示する価値があるのは、アプリがバックグラウンドで実行されている場合でもonMessageReceivedハンドラを呼び出すには、データメッセージ - データキーのみ - を使用する必要があるということです。ペイロードに他の通知メッセージキーを含めないでください。そうしないと、アプリがバックグラウンドで実行されている場合にハンドラが起動されません。

それはここで述べられています(しかしFCMドキュメンテーションでそれほど強調されません):

https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

アプリサーバーとFCMサーバーAPIを使用します。データキーのみを設定します。折りたたみ式または非折りたたみ式のいずれかになります。

1
n_y

あなたの問題がBig Imageの表示に関連している場合、つまりfirebase consoleからの画像とともにPush通知を送信している場合で、アプリがフォアグラウンドにある場合にのみ画像が表示されます。この問題を解決するには、データフィールドのみを指定してプッシュメッセージを送信します。このようなもの:

{ "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" }
1
Arun

私が働いているバックエンドは Notification messages を使っていてDataメッセージを使っていません。それで、すべての答えを読んだ後に、私は立ち上げられた活動に関する意図のバンドルからエクストラを検索しようとしました。しかし、どのキーをgetIntent().getExtras();から取得しようとしても、値は常にnullでした。

しかし、 通知メッセージ を使用してデータを送信し、意図からそれを取得する方法をついに見つけました。

ここで重要なのは、通知メッセージに データペイロード を追加することです。

例:

{
    "data": {
        "message": "message_body",
        "title": "message_title"
    },
    "notification": {
        "body": "test body",
        "title": "test title"
    },
    "to": "E4An.."
}

これをした後、あなたはこのようにあなたの情報を得ることができるでしょう:

intent.getExtras().getString("title")message_titleになります

そしてintent.getExtras().getString("message")message_bodyになります

参照

1
Vito Valov

メッセージが受信され、アプリがバックグラウンドになっていると、通知はメインアクティビティのエキストラインテントに送信されます。

追加の値は、メインアクティビティのoncreate()またはonresume()関数で確認できます。

あなたはデータ、テーブルなど(通知で指定されたもの)のようなフィールドをチェックすることができます

たとえば、データをキーとして送信した

public void onResume(){
    super.onResume();
    if (getIntent().getStringExtra("data")!=null){
            fromnotification=true;
            Intent i = new Intent(MainActivity.this, Activity2.class);
            i.putExtra("notification","notification");
            startActivity(i);
        }

}
0
Sanjeev S

Firebaseプッシュ通知には、2タイプがあります:

1-通知メッセージ(メッセージの表示)->-1.1このバリアントを選択すると、アプリがBackgroundの場合、OSが自己通知を作成しますそして、intentにデータを渡します。その後、このデータを処理するのはクライアント次第です。

-1.2アプリがForegroundにある場合、通知はFirebaseMessagingServicecallback-functionを介して受信され、クライアントに任されます扱う。

2-データメッセージ(最大4kデータ)->これらのメッセージは、データのみをクライアントに送信するために使用され(サイレント)、FirebaseMessagingServiceのコールバック関数を介してバックグラウンド/フォアグラウンドの両方のケースでそれを処理するのはクライアント次第です

これは公式ドキュメントによると: https://firebase.google.com/docs/cloud-messaging/concept-options

0
Balflear

私は同じ問題を抱えていたので、これについてもう少し掘り下げました。アプリがバックグラウンドで動作している場合は、 通知メッセージ がシステムトレイに送信されますが、 データメッセージ onMessageReceived()に送信されます。
https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3 を参照してください。
および https://github.com/firebase/quickstart-Android/blob/master/messaging/app/src/main/Java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.Java

あなたが送信しているメッセージを確実にするために、ドキュメントは「あなたのアプリケーションサーバーとFCMサーバーAPIを使用してください:データキーのみを設定してください。折りたたみ可能または折りたたみ不可のどちらでも可能です}
https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages を参照してください。

0
Eric B.

私はこの問題を抱えていました(アプリがバックグラウンドであるかクローズされている場合、アプリは通知クリックで開きたくありません)、問題は通知本体の無効なclick_actionでした。削除するか有効なものに変更してみてください。

0
Octavian Lari

メッセージには、通知メッセージとデータメッセージの2種類があります。データメッセージのみを送信する場合は、メッセージ文字列に通知オブジェクトがありません。アプリがバックグラウンドで起動したときに呼び出されます。

0
Shongsu