web-dev-qa-db-ja.com

Firebaseでアプリがバックグラウンドで動作しているときの通知の処理方法

これが私のマニフェストです

    <service Android:name=".fcm.PshycoFirebaseMessagingServices">
        <intent-filter>
            <action Android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <service Android:name=".fcm.PshycoFirebaseInstanceIDService">
        <intent-filter>
            <action Android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

アプリがバックグラウンドで通知が届くと、デフォルトの通知が届き、私のonMessageReceivedのコードは実行されません。

これが私のonMessageReceivedコードです。これは、アプリがバックグラウンドで実行されているときではなく、私のアプリがフォアグラウンドで実行されている場合に呼び出されます。アプリがバックグラウンドで動作しているときにこのコードを実行する方法

// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): 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. See sendNotification method below.
    data = remoteMessage.getData();
    String title = remoteMessage.getNotification().getTitle();
    String message = remoteMessage.getNotification().getBody();
    String imageUrl = (String) data.get("image");
    String action = (String) data.get("action");
    Log.i(TAG, "onMessageReceived: title : "+title);
    Log.i(TAG, "onMessageReceived: message : "+message);
    Log.i(TAG, "onMessageReceived: imageUrl : "+imageUrl);
    Log.i(TAG, "onMessageReceived: action : "+action);

    if (imageUrl == null) {
        sendNotification(title,message,action);
    } else {
        new BigPictureNotification(this,title,message,imageUrl,action);
    }
}
// [END receive_message]
311
Parth Patel

1.なぜこれが起こっているのですか?

FCM(Firebase Cloud Messaging)には2種類のメッセージがあります。

  1. メッセージの表示:これらのメッセージは、アプリが起動しているときにのみonMessageReceived()コールバックをトリガーしますforeground
  2. データメッセージ:これらのメッセージはonMessageReceived()コールバックをトリガーしますevenアプリがforeground/background/killedの場合

Firebaseチームは、data-messagesをデバイスに送信するためのUIをまだ開発していません。

2.方法は?

これを実現するには、次のURLに対してPOSTリクエストを実行する必要があります。

POSThttps://fcm.googleapis.com/fcm/send

ヘッダー

  • キー:Content-Type値:application/json
  • キー:Authorization値:key=<your-server-key>

トピックを使用する本文

{
    "to": "/topics/my_topic",
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     }
}

または、特定のデバイスに送信する場合

{
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     },
    "registration_ids": ["{device-token}","{device2-token}","{device3-token}"]
}


注:必ず確認してください追加しない JSONキーnotification
注:サーバーキーを取得するには、firebaseコンソールで見つけることができます:Your project -> settings -> Project settings -> Cloud messaging -> Server Key

3.プッシュ通知メッセージの処理方法

これは、受信したメッセージの処理方法です。

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String myCustomKey = data.get("my_custom_key");

     // Manage data
}
574
Antonio

以下の場合にfirebaseライブラリが onMessageReceived() を呼び出すようにします。

  1. フォアグラウンドのアプリ
  2. バックグラウンドでのアプリ
  3. アプリは殺されました

jSONキーの 'notification'をfirebase APIへのリクエストに入れてはいけませんが、代わりに 'data'を使ってください。下記参照。

次のメッセージでは、アプリがバックグラウンドにあるか強制終了されたときに onMessageReceived() は呼び出されません。通知をカスタマイズすることはできません。

{
   "to": "/topics/journal",
   "notification": {
   "title" : "title",
   "text": "data!",
   "icon": "ic_notification"
    }
}

しかし代わりにこれを使うとうまくいくでしょう

{
  "to": "/topics/dev_journal",
   "data": {
       "text":"text",
       "title":"",
       "line1":"Journal",
       "line2":"刊物"
   }
} 

基本的に、メッセージはMapとしてあなたのデータオブジェクトと一緒に引数RemoteMessageで送られます、そしてあなたはここでスニペットのようにonMessageReceivedで通知を管理することができます

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();

     //you can get your text message here.
     String text= data.get("text");


     NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
        // optional, this is to make beautiful icon
             .setLargeIcon(BitmapFactory.decodeResource(
                                    getResources(), R.mipmap.ic_launcher))  
        .setSmallIcon(smallIcon)  //mandatory
      .......
    /*You can read more on notification here:
    https://developer.Android.com/training/notify-user/build-notification.html
    https://www.youtube.com/watch?v=-iog_fmm6mE
    */
}

すべての応答が不完全であるように感じますが、すべての応答には、アプリがバックグラウンドにあるときにデータを含む通知を処理するために必要なものがあります。

次の手順に従うと、アプリがバックグラウンドにあるときに通知を処理できます。

1.このようなインテントフィルタを追加します。

<activity Android:name=".MainActivity">
      <intent-filter>
           <action Android:name=".MainActivity" />
           <category Android:name="Android.intent.category.DEFAULT" />
      </intent-filter>
</activity>

通知データを処理する活動に.

  1. 次の形式で通知を送信します。

    { 
     "notification" : {
            "click_action" : ".MainActivity", 
            "body" : "new Symulti update !", 
            "title" : "new Symulti update !", 
            "icon" : "ic_notif_symulti" }, 
     "data": { ... },
     "to" : "c9Vaa3ReGdk:APA91bH-AuXgg3lDN2WMcBrNhJZoFtYF9" }
    

ここで重要なのはaddです。 

"click_action" : ".MainActivity"

ここで、.MainActivityは、手順1で追加したインテントフィルタを使用したアクティビティです。

  1. ".MainActivity"のonCreateの通知から "data"情報を取得します。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //get notification data info
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
           //bundle must contain all info sent in "data" field of the notification
        }
    }
    

そしてそれはあなたがする必要があるすべてであるべきです。これが誰かに役立つことを願っています:)

74
Daniel S.

docs によると

バックグラウンドのアプリでメッセージを処理する

アプリがバックグラウンドで動作している場合、Androidは通知メッセージをシステムトレイに送信します。ユーザーが通知をタップすると、デフォルトでアプリランチャーが開きます。

これは通知とデータペイロードの両方を含むメッセージを含みます。このような場合、通知はデバイスのシステムトレイに配信され、データペイロードはランチャーアクティビティの意図を超えて配信されます。

アプリを開いて特定のアクションを実行したい場合は、通知ペイロードに click_actionを設定し、起動したいアクティビティのインテントフィルタにマッピングします。たとえば、 click_actionをOPEN_ACTIVITY_1に設定すると、のようなインテントフィルタがトリガーされます。

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

編集する

これに基づく スレッド : 

Firebase Consoleを使用してclick_actionペイロードを設定することはできません。 curlコマンドかカスタムのhttpサーバでテストしてみてください。

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" 
     --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  
     -d "{\"to\":\"/topics/news\",\"notification\": 
         {\"title\": \"Click Action Message\",\"text\": \"Sample message\",
            \"click_action\":\"OPEN_ACTIVITY_1\"}}"
31
Shubhank

firebaseを使用してダウンストリームに送信 のfirebaseドキュメントによると、ペイロードには2つのタイプがあります。

  1. データ

    このパラメータは、メッセージのペイロードのカスタムキーと値のペアを指定します。クライアントアプリはデータメッセージの処理を担当します。データメッセージにはカスタムのキーと値のペアしかありません。

  2. 通知

    このパラメータは、通知ペイロードの事前定義された、ユーザーに見えるキーと値のペアを指定します。 FCMは、クライアントアプリに代わってエンドユーザーのデバイスにメッセージを自動的に表示します。通知メッセージには、定義済みの一連のユーザーに表示されるキーがあります。

前景にいるときは、 onMessageReceived() を使用してFCM内部のデータを取得できます。 data payloadからデータを取得できます。

data = remoteMessage.getData();
String customData = (String) data.get("customData");

あなたがバックグラウンドにいるとき、FCMは notification payloadからの情報に基づいてシステムトレイに通知を表示します。システムトレイ上の通知に使用されるタイトル、メッセージ、およびアイコンは、 notification ペイロードから取得されます。

{
  "notification": {
        "title" : "title",
        "body"  : "body text",
        "icon"  : "ic_notification",
        "click_action" : "OPEN_ACTIVITY_1"
       }
}

この notification payloadは、アプリがバックグラウンドにあるときに自動的にシステムトレイに通知を表示したい場合に使用されます。バックグラウンドにあるときに通知データを取得するには、click_actionを追加します。 inside notification ペイロード。

アプリを開いて[バックグラウンド中に]特定のアクションを実行する場合は、通知ペイロードにclick_actionを設定し、起動するアクティビティのインテントフィルタにマッピングします。たとえば、click_actionをOPEN_ACTIVITY_1に設定すると、次のようなインテントフィルタが起動されます。

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

その目的フィルタをマニフェストのapplicationタグ内に置きます。通知をクリックすると、アプリが開き、click_actionで定義したアクティビティ、この場合は "OPEN_ACTIVTY_1"に直接移動します。そのアクティビティ内では、次の方法でデータを取得できます。

Bundle b = getIntent().getExtras();
String someData = b.getString("someData");

私は自分のAndroidアプリにFCMを使用しており、両方のペイロードを使用しています。これが私が使用しているJSONの例です。

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification", "click_action" : "OPEN_ACTIVITY_1"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}
25
Hendy Evan

Firebase Notification UIから送信されるdisplay-messagesは、アプリがフォアグラウンドにある場合にのみ機能します。 data-messagesについては、 _ fcm _ にPOSTを呼び出す必要があります

ステップ

  1. アドバンストレストクライアントのインストールGoogle Chrome拡張機能 enter image description here

  2. 以下のヘッダを追加してください 

    キー :Content-Type、:application/json

    キー :認証、:キー= "あなたのサーバーキー" enter image description here

  3. ボディを追加

    • トピックを使用している場合

      {
          "to" : "/topics/topic_name",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
          }
      }
      
    • 登録IDを使用している場合:

      {
          "registration_ids" : "[{"id"},{id1}]",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
           }
      }
      

それでおしまい!。今度はいつものようにonMessageReceivedコールバックを聞いてください。

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String value1 = data.get("key1");
     String value2 = data.get("key2");
}
19
Anirudh Ramanan

バックグラウンドでメッセージを捉えるにはBroadcastReceiverを使う必要があります。

public class FirebaseDataReceiver extends WakefulBroadcastReceiver {

    private final String TAG = "FirebaseDataReceiver";

    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "I'm in!!!");
        Bundle dataBundle = intent.getBundleExtra("data");
        Log.d(TAG, dataBundle.toString());
    }
}

そしてこれをあなたのマニフェストに追加してください:

<receiver
      Android:name="MY_PACKAGE_NAME.FirebaseDataReceiver"
      Android:exported="true"
      Android:permission="com.google.Android.c2dm.permission.SEND">
        <intent-filter>
            <action Android:name="com.google.Android.c2dm.intent.RECEIVE" />
        </intent-filter>
</receiver>
15
Romulano
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}

アプリがforgroundにある場合にのみ呼び出されるたびに呼び出されるわけではありません

このメソッドは毎回呼び出されるオーバーライドメソッドが1つあります。フォアグラウンド、バックグラウンド、キルのいずれのアプリであっても、このFirebase APIバージョンで使用できます。 

これは、gradleからインポートする必要があるバージョンです。

compile 'com.google.firebase:firebase-messaging:10.2.1'

これが方法です

@Override
public void handleIntent(Intent intent) {
    super.handleIntent(intent);

    // you can get ur data here 
    //intent.getExtras().get("your_data_key") 


}

以前のfirebase apiでは、この方法はありませんでした。 appがバックグラウンドにあるときは fire base自体が処理されます。あなたはここでこの方法でそれをすることができます..... 

あなたがデフォルトのアクティビティより前のバージョンを使用している場合はが起動します。その場合、uは同じ方法でデータを取得できます。 

if(getIntent().getExtras() != null && getIntent().getExtras().get("your_data_key") != null) {
String strNotificaiton = getIntent().getExtras().get("your_data_key").toString();

//欲しいものをやる…}

一般的にこれは私達が通知を受けるサーバーからの構造です 

{
    "notification": {
        "body": "Cool offers. Get them before expiring!",
        "title": "Flat 80% discount",
        "icon": "appicon",
        "click_action": "activity name" //optional if required.....
    },
    "data": {
        "product_id": 11,
        "product_details": "details.....",
        "other_info": "......."
    }
}

それはどのようにあなたがそのデータキーを与えることを望むか、またはuあなたが与えることができる何かを通知したい....... これまでuが同じキーでここで与えるものuはそのデータを得るでしょう... ...... 

あなたがクリックアクションを送っていない場合、あなたがデフォルトのアクティビティをクリックするときにあなたがあなたの特定のアクティビティを開きたい場合、あなたがあなたのアクティビティを呼び出すことができます。毎回呼ばれる 

15
Avinash Jadaun

ドキュメントによると:2017年5月17日

アプリが background の場合、Android は通知メッセージをシステムトレイに送ります。ユーザーが通知をタップすると、デフォルトで アプリランチャーが開きます

これには、 notificationとdata payload (およびNotificationsコンソールから送信されたすべてのメッセージ)の両方を含むメッセージが含まれます。このような場合、通知はデバイスのシステムトレイに配信され、データペイロードはランチャーアクティビティの目的を超えて配信されます。

そのため、ペイロード通知とデータの両方を使用する必要があります。

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}

Click_actionを使用する必要はありません。 LAUNCHERアクティビティ の意図からexrasを取得するだけです。 

<activity Android:name=".MainActivity">
        <intent-filter>
            <category Android:name="Android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

JavaコードはMainActivityのonCreateメソッドにあります。

Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
    Bundle extras = intent.getExtras();
    String someData= extras.getString("someData");
    String someData2 = extras.getString("someData2");
}

ペイロード通知とデータの両方を Firebase Notifications Console からテストできます。 [詳細オプション]セクションのカスタムデータフィールドに入力することを忘れないでください

9
Mihuilk

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

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

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

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

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

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

詳細については私の/ このスレッドを参照してください

9

2017年の回答を更新

これに関して docs からの明確な答えがあります。

enter image description here

8
pulp_fiction

シナリオを考え出した、

Appが foreground にあるときは、[{。on] =FirebaseServiceから onMessageReceived()メソッドが呼び出されるので、 pendingIntent で定義します。サービスクラスが呼び出されます。

そしてappが background にあるとき、first activityが呼ばれます。

さて、あなたがsplash activityを使うなら、 must splashactivityを呼び出すことを覚えておいてください。です、と呼ばれます。

それからfirstActivitygetIntent()をチェックして、bundle。があるかどうかを確認する必要があります。サーバーから送信された data tag の値が次のようになっていれば、 

"data": {
    "user_name": "arefin sajib",
    "value": "user name notification"
  }

最初のアクティビティでは、有効な意図がある( getIntent()がnull ではない)、有効なバンドル、および内部のバンドルがあることを確認します。data as key

このシナリオでは、値を抽出するためのコードは次のようになります。

    if(getIntent()!=null){
            Bundle bundle = getIntent().getExtras();
            if (bundle != null) {
                try {
                   JSONObject object = new JSONObject(bundle.getStringExtra("data"));
String user_name = object.optString("user_name");

                } catch (JSONException e) {
                    e.printStackTrace();
                }


            }
        }

こんな簡単なまとめ

  • アプリが実行中の場合

    onMessageReceived()
    

トリガーです。

  • アプリが実行されていない(スワイプで強制終了された)場合

    onMessageReceived()
    

direcltyによって起動され配信されることはありません。特殊なキーと値のペアがある場合onMessageReceived()が機能していないために動作しません。 

私はこのようにして見つけました。

あなたのランチャーの活動において、この論理を置きなさい、

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState, R.layout.activity_splash);

    if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("PACKAGE_NAME")) {

        // do what you want

        // and this for killing app if we dont want to start
        Android.os.Process.killProcess(Android.os.Process.myPid());

    } else {

        //continue to app
    }
}

このifブロックでは、firebase UIに従ってあなたのキーを検索してください。

この例では、私のキーと値は上記のようになっています。 (language =ごめんなさい)) enter image description here

私のコードが動作すると、私は "com.rda.note"を得ます。 

Android.os.Process.killProcess(Android.os.Process.myPid());

このコードで、私は自分のアプリケーションを閉じて、Google Play Marketを開いた。

ハッピーコーディング=)

6
Arda

ご回答ありがとうございました。しかし、私はこれを送信することで解決しました データメッセージ 送信する代わりに お知らせ。サーバーコード

<?php
$url = "https://fcm.googleapis.com/fcm/send";
$token = "C-l6T_a7HouUK****";
$serverKey = "AAAAaOcKS00:********";
define( 'API_ACCESS_KEY', $serverKey );
$registrationIds = array($token);
// prep the bundle

$msg = array

(
 'message'  => 'here is a message. message',
 'title'        => 'This is a title. title',
 'subtitle' => 'This is a subtitle. subtitle',
 'tickerText'   => 'Ticker text here...Ticker text here...Ticker text 
 here',
 'vibrate'  => 1,
 'sound'        => 1,
 'largeIcon'    => 'large_icon',
 'smallIcon'    => 'small_icon'

);

$fields = array

(
  'registration_ids'    => $registrationIds,
  'data'            => $msg

);
$headers = array

(
  'Authorization: key=' . API_ACCESS_KEY,
 'Content-Type: application/json'

);


$ch = curl_init();

curl_setopt( $ch,CURLOPT_URL, 'https://Android.googleapis.com/gcm/send' 
);

curl_setopt( $ch,CURLOPT_POST, true );

curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );

curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );

curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );

$result = curl_exec($ch );

curl_close( $ch );

echo $result;

?>

そしてonMessageReceivedのデータをキャッチしました

public class MyFirebaseMessagingService extends FirebaseMessagingService     {

  private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

      sendNotification(remoteMessage.getData().get("message"));
     }
   // Check if message contains a notification payload.
    else if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    sendNotification(remoteMessage.getNotification().getBody());
    }


}
   private void sendNotification(String messageBody) {
    Intent intent = new Intent(this, Notify.class).putExtra("msg",messageBody);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);

    String channelId = "idddd";
    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(MyFirebaseMessagingService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .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());
}
}
3

アプリがバックグラウンドでフォアグラウンドになっている場合でもメッセージを送信する簡単な方法は次のとおりです。 - APIを使用してメッセージを送信するには、AdvancedREST Clientというツールを使用します。以下のパラメータ.

休息クライアントツールリンク: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

このURLを使用します。 - https://fcm.googleapis.com/fcm/send Content-Type:application/json Authorization:key =あなたのサーバーキーFromまたは認証キー(下記参照)

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

認証キーは、Google開発者コンソールにアクセスし、プロジェクトの左側のメニューにある[認証情報]ボタンをクリックして取得できます。リストされているAPIキーの中で、サーバーキーが認証キーになります。

また、APIを使用して送信されたPOSTリクエストの「to」セクションに、受信者のtokenIDを入れる必要があります。

2

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

これが私がサーバーから送っているものです:

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

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

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

そして同様にあなたはonMessageReceived()の中でサーバーからあなたが送ったどんなデータでも得ることができます。

2
Zohab Ali

バックグラウンドでonMessageReceived(RemoteMessage remoteMessage)を処理したい場合は、データ部分通知部分のみを送信してください。 

"data":    "image": "",    "message": "Firebase Push Message Using API", 

"AnotherActivity": "True"、 "to": "デバイスIDまたはデバイストークン" 

これによってonMessageReciviedはバックグラウンドおよびフォアグラウンドで呼び出され、ランチャーアクティビティの通知トレイを使用して通知を処理する必要はありません。 これを使用する際にデータペイロードを処理します。
[void] public void onMessageReceived(RemoteMessage remoteMessage)[if](remoteMessage.getData()。size()> 0) Log.d(TAG、 "メッセージデータペイロード:" + remoteMessage .getData()); 

1
user3385125

2018年6月答え -

メッセージのどこにも "notification"キーワードがないことを確認する必要があります。 「data」のみを含めると、アプリは、バックグラウンドまたは殺害されている場合でも、onMessageReceivedでメッセージを処理できます。

クラウド機能を使う:

const message = {
    token: token_id,   // obtain device token id by querying data in firebase
    data: {
       title: "my_custom_title",
       body:  "my_custom_body_message"
       }
    }


return admin.messaging().send(message).then(response => {
    // handle response
});

次に、onMessageReceived()内で、クラス内でcom.google.firebase.messaging.FirebaseMessagingServiceを拡張します。

if (data != null) {
  Log.d(TAG, "data title is: " + data.get("title");
  Log.d(TAG, "data body is: " + data.get("body");
}

// build notification using the body, title, and whatever else you want.
1
Jeff Padgett

OAUTH 2.0に従って回答を更新しました。  

受け付けられた回答は機能しなくなりました(エラー401).. この場合OAUTH 2を使用しているのでFCMが原因でAuth問題が発生します

だから私はfirebaseのドキュメントを読み、ドキュメントによればデータメッセージを投稿するための新しい方法は以下の通りです。

POST: https://fcm.googleapis.com/v1/projects/YOUR_FIREBASEDB_ID/messages:send

ヘッダ

Key: Content-Type, Value: application/json

認証

Bearer YOUR_TOKEN 

ボディの例

{
   "message":{
    "topic" : "xxx",
    "data" : {
         "body" : "This is a Firebase Cloud Messaging Topic Message!",
         "title" : "FCM Message"
          }
      }
 }

URLにはデータベースIDがあり、これをFirebase Consoleで見つけることができます。 (プロジェクトの解決を行ってください)

そして今、私たちのトークンを取りましょう(それは1時間だけ有効です):

まずFirebaseコンソールで、 設定>サービスアカウント を開きます。 新しい秘密鍵を生成 をクリックして、鍵を含むJSONファイルを安全に保存します。サーバー要求を手動で承認するためにこのJSONファイルが必要でした。ダウンロードしました。

それから、node.jsプロジェクトを作成し、この関数を使ってトークンを取得しました。

var PROJECT_ID = 'YOUR_PROJECT_ID';
var Host = 'fcm.googleapis.com';
var PATH = '/v1/projects/' + PROJECT_ID + '/messages:send';
var MESSAGING_SCOPE = 'https://www.googleapis.com/auth/firebase.messaging';
var SCOPES = [MESSAGING_SCOPE];

  router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });
      getAccessToken().then(function(accessToken) {
        console.log("TOKEN: "+accessToken)
      })

    });

function getAccessToken() {
return new Promise(function(resolve, reject) {
    var key = require('./YOUR_DOWNLOADED_JSON_FILE.json');
    var jwtClient = new google.auth.JWT(
        key.client_email,
        null,
        key.private_key,
        SCOPES,
        null
    );
    jwtClient.authorize(function(err, tokens) {
        if (err) {
            reject(err);
            return;
        }
        resolve(tokens.access_token);
    });
});
}

これで私は自分の投稿リクエストでこのトークンを使うことができます。それから私は自分のデータメッセージを投稿します、そしてそれは今私のアプリのonMessageReceived関数によって処理されます。

0
Ozan

2019年以降、Google FirebaseのAPIには大きな変化があります。つまり、'com.google.firebase:firebase-messaging:18.0.0'

18.0.0でMyFirebaseInstanceIDServiceが削除され、MyFirebaseMessagingServiceでトークンを取得する必要があるため、次のように記述するだけです。

@Override
public void onNewToken(String token) {
    Log.d(TAG, "Refreshed token: " + token);

}

また、AndroidManifest.xmlで次を削除する必要があります。

<service Android:name=".service.MyFirebaseInstanceIDService">
        <intent-filter>
            <action Android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

また、デフォルト値を設定して通知の外観をカスタマイズすることをお勧めします。同等の値が通知ペイロードに設定されていない場合に適用されるカスタムデフォルトアイコンとカスタムデフォルト色を指定できます。

アプリケーションタグ内に次の行を追加して、カスタムデフォルトアイコンとカスタムカラーを設定します。

    <meta-data
        Android:name="com.google.firebase.messaging.default_notification_icon"
        Android:resource="@drawable/ic_notification" />

    <meta-data
        Android:name="com.google.firebase.messaging.default_notification_color"
        Android:resource="@color/colorAccent" />

    <meta-data
        Android:name="com.google.firebase.messaging.default_notification_channel_id"
        Android:value="@string/Push_channel" />

バックグラウンドアプリで通知メッセージを処理するには、SplashScreenであっても最初のアクティビティでインテントを定義する必要があります。アプリがバックグラウンドにある場合、Androidはシステムトレイに通知メッセージを送ります。ユーザーが通知をタップすると、デフォルトでアプリランチャーが開きます。

たとえば、Jsonが次のような場合:

 "data": {
"message": "2",
"title": "1",
"pushType" : "banner",
"bannerLink": "http://www.google.com",
"image" : "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"}

これらの値を取得するための単純なインテントを作成するだけです。

        Bundle extras = intent.getExtras();
        String bannerLink = extras.getString("bannerLink");
        ...
        String channelId = extras.getString("channelId");
0

2019年7月現在

Android compileSdkVersion 28、buildToolsVersion 28.0.3およびfirebase-messaging:19.0.1

他のすべてのStackOverflowの質問と回答を何時間も調査し、無数の古いソリューションを試した後、このソリューションは次の3つのシナリオで通知を表示することができました。

-アプリはフォアグラウンドにあります:
MyFirebaseMessagingServiceクラスのonMessageReceivedメソッドによって通知が受信されます

-アプリは強制終了されました(バックグラウンドで実行されていません):通知はFCMによって通知トレイに自動的に送信されます。ユーザーが通知に触れると、マニフェストにAndroid.intent.category.LAUNCHERが含まれるアクティビティを呼び出してアプリが起動します。 onCreate()メソッドでgetIntent()。getExtras()を使用して、通知のデータ部分を取得できます。

-アプリはバックグラウンドにあります:通知はFCMによって通知トレイに自動的に送信されます。ユーザーが通知に触れると、マニフェストにAndroid.intent.category.LAUNCHERが含まれるアクティビティを起動して、アプリがフォアグラウンドに移動します。私のアプリはそのアクティビティにlaunchMode = "singleTop"を持っているので、同じクラスの1つのアクティビティが既に作成されているため、onCreate()メソッドは呼び出されず、代わりにそのクラスのonNewIntent()メソッドが呼び出され、 intent.getExtras()を使用して、そこに通知します。

手順:1-アプリのメインアクティビティを次のように定義する場合:

<activity
    Android:name=".MainActivity"
    Android:label="@string/app_name"
    Android:largeHeap="true"
    Android:screenOrientation="portrait"
    Android:launchMode="singleTop">
    <intent-filter>
        <action Android:name=".MainActivity" />
        <action Android:name="Android.intent.action.MAIN" />
        <category Android:name="Android.intent.category.LAUNCHER" />
        <category Android:name="Android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

2- MainActivity.classのonCreate()メソッドでこれらの行を追加します

Intent i = getIntent();
Bundle extras = i.getExtras();
if (extras != null) {
    for (String key : extras.keySet()) {
        Object value = extras.get(key);
        Log.d(Application.APPTAG, "Extras received at onCreate:  Key: " + key + " Value: " + value);
    }
    String title = extras.getString("title");
    String message = extras.getString("body");
    if (message!=null && message.length()>0) {
        getIntent().removeExtra("body");
        showNotificationInADialog(title, message);
    }
}

同じMainActivity.classに対するこれらのメソッド:

@Override
public void onNewIntent(Intent intent){
    //called when a new intent for this class is created.
    // The main case is when the app was in background, a notification arrives to the tray, and the user touches the notification

    super.onNewIntent(intent);

    Log.d(Application.APPTAG, "onNewIntent - starting");
    Bundle extras = intent.getExtras();
    if (extras != null) {
        for (String key : extras.keySet()) {
            Object value = extras.get(key);
            Log.d(Application.APPTAG, "Extras received at onNewIntent:  Key: " + key + " Value: " + value);
        }
        String title = extras.getString("title");
        String message = extras.getString("body");
        if (message!=null && message.length()>0) {
            getIntent().removeExtra("body");
            showNotificationInADialog(title, message);
        }
    }
}


private void showNotificationInADialog(String title, String message) {

    // show a dialog with the provided title and message
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title);
    builder.setMessage(message);
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();
}

3-次のようなクラスMyFirebaseを作成します。

package com.yourcompany.app;

import Android.content.Intent;
import Android.util.Log;

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

public class MyFirebaseMessagingService extends FirebaseMessagingService {


    public MyFirebaseMessagingService() {
        super();
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        Log.d(Application.APPTAG, "myFirebaseMessagingService - onMessageReceived - message: " + remoteMessage);

        Intent dialogIntent = new Intent(this, NotificationActivity.class);
        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        dialogIntent.putExtra("msg", remoteMessage);
        startActivity(dialogIntent);

    }

}

4-次のような新しいクラスNotificationActivity.classを作成します。

package com.yourcompany.app;

import Android.app.Activity;
import Android.app.AlertDialog;
import Android.content.DialogInterface;
import Android.os.Bundle;
import Android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;

import com.google.firebase.messaging.RemoteMessage;

public class NotificationActivity extends AppCompatActivity {

private Activity context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    context = this;
    Bundle extras = getIntent().getExtras();

    Log.d(Application.APPTAG, "NotificationActivity - onCreate - extras: " + extras);

    if (extras == null) {
        context.finish();
        return;
    }

    RemoteMessage msg = (RemoteMessage) extras.get("msg");

    if (msg == null) {
        context.finish();
        return;
    }

    RemoteMessage.Notification notification = msg.getNotification();

    if (notification == null) {
        context.finish();
        return;
    }

    String dialogMessage;
    try {
        dialogMessage = notification.getBody();
    } catch (Exception e){
        context.finish();
        return;
    }
    String dialogTitle = notification.getTitle();
    if (dialogTitle == null || dialogTitle.length() == 0) {
        dialogTitle = "";
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(context, R.style.myDialog));
    builder.setTitle(dialogTitle);
    builder.setMessage(dialogMessage);
    builder.setPositiveButton(getResources().getString(R.string.accept), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();

}

}

5-これらの行をアプリマニフェストのタグ内に追加します

    <service
        Android:name=".MyFirebaseMessagingService"
        Android:exported="false">
        <intent-filter>
            <action Android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <meta-data Android:name="com.google.firebase.messaging.default_notification_channel_id" Android:value="@string/default_notification_channel_id"/>

    <activity Android:name=".NotificationActivity"
        Android:theme="@style/myDialog"> </activity>

    <meta-data
        Android:name="com.google.firebase.messaging.default_notification_icon"
        Android:resource="@drawable/notification_icon"/>

    <meta-data
        Android:name="com.google.firebase.messaging.default_notification_color"
        Android:resource="@color/color_accent" />

6- Application.JavaのonCreate()メソッドまたはMainActivity.class onCreate()メソッドに次の行を追加します。

      // notifications channel creation
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      // Create channel to show notifications.
      String channelId = getResources().getString("default_channel_id");
      String channelName = getResources().getString("General announcements");
      NotificationManager notificationManager = getSystemService(NotificationManager.class);
      notificationManager.createNotificationChannel(new NotificationChannel(channelId,
              channelName, NotificationManager.IMPORTANCE_LOW));
  }

できた.

これが上記の3つのシナリオで適切に機能するためには、次の方法でFirebase Webコンソールから通知を送信する必要があります。

通知セクション:通知タイトル=通知ダイアログに表示するタイトル(オプション)通知テキスト=ユーザーに表示するメッセージ(必須)次に、ターゲットセクション:アプリ= Androidアプリおよび追加オプションセクション:Android通知チャネル= default_channel_idカスタムデータキー:タイトル値:(通知セクションの[タイトル]フィールドと同じテキスト)キー:ボディ値:([メッセージ]フィールドと同じテキスト通知セクション)key:click_action value:.MainActivity Sound = Disabled
Expires = 4週間

Google PlayのAPI 28を使用してエミュレータでデバッグできます。

ハッピーコーディング!

0
alvaro

このコードを使用すると、通知をバックグラウンド/フォアグラウンドで取得したり、アクションを実行したりできます。

//Data should come in this format from the notification
{
  "to": "/xyz/Notifications",
  "data": {
      "key1": "title notification",
      "key2": "description notification"
  }
}

アプリ内でこのコードを使用します。

  @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
      String key1Data = remoteMessage.getData().get("key1");
      // use key1Data to according to your need
    }
0
Ashish Kumar
  // Place this code on your MainActivity,then you will get your payload
  // Handle possible data accompanying notification message.
    // [START handle_data_extras]
    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d(TAG, "Key: " + key + " Value: " + value);
        }
    }
0
baderkhane

上記の回答に加えて、FCMコンソールを使用してプッシュ通知をテストしている場合、 'data'キーとオブジェクトはnotプッシュ通知バンドルに追加されます。そのため、アプリがバックグラウンドまたは強制終了された場合、詳細なプッシュ通知を受信しません。

この場合、アプリのバックグラウンドシナリオをテストするには、バックエンド管理コンソールを選択する必要があります。

ここで、プッシュバンドルに「データ」キーを追加します。そのため、期待どおりに詳細なプッシュが表示されます。これがほとんど役に立たないことを願っています。

0
Max Droid