web-dev-qa-db-ja.com

Dozeからデバイスを復帰させない優先度の高いFirebaseメッセージAndroid 6+

プロジェクトをGCMからFirebaseに移行しました。プッシュ通知は、デバイスが起きているか、最近スリープ状態になったときに正常に完了しますが、デバイスを1時間ほど放置すると、デバイスをウェイクアップするまでプッシュは送信されません。

Androidのドキュメントでは、メッセージを配信するためにデバイスをウェイクアップする必要がある場合、優先度を高く設定してFireBaseを使用します。アプリはデバイス管理アプリです。

プロジェクトをGCMからFCMに移行したときに、Firebase Consoleでパッケージ名のみを指定し、フィンガープリントは指定しなかったことに言及すると思いました。

私が試したもの。

  1. 優先度を高に設定します

    {
      "time_to_live": 300000,
      "delay_while_idle": false,
      "Android": {
        "priority": "high"
      },
      "data": {
        "message": "PING_DEVICE",
        "time": "21/01/2018 16:20:28",
        "pushguid": "10062"
      },
      "registration_ids": [
        "eOMT........"
      ]
    }
    

    メッセージが最終的に届くように、有効期間が設定されています。 delay_while_idleはfalseに設定され、2016年9月以降はFCMによって無視されます。

  2. デバイス管理アプリはDozeの対象ではありません。私のものはデバイス管理アプリですが、設定->バッテリー->最適化にあるDozeホワイトリストにも明示的に追加しました。これは、設定アプリを介して手動で行われ、コードでプログラム的に行われたものではありません。

デバイスを3時間スリープ状態のままにしましたが、プッシュが送信されません。また、adbを使用してデバイスをDozeに入れました。 adbがデバイスをDozeに入れると、プッシュは受信されず、adbがデバイスをDozeから取り出すと、プッシュが実行されます。

私が試したことのないさらなる考え。

私のプッシュはデータメッセージです。これは、Pushがデバイスの通知バーに来て、ユーザーにクリックさせて機能を実行させないようにするためです。ユーザーはデバイス管理アプリを操作しません。したがって、データメッセージは

onMessageReceived(RemoteMessage remoteMessage)

私は通知メッセージがデバイスをウェイクアップさせると信じています。これは必要なことですが、ユーザーではなくプッシュでアプリを処理したいです。通知とデータの両方であるが、onMessageRecieviedが機能を処理するメッセージを持つことはできますか?

誰かが同様のことを経験したか、これに対する解決策を持っていますか?

[EDIT1]通知とデータの両方であるメッセージを送信できるという次のリンクを見つけましたが、アプリがバックグラウンドにある場合、通知は表示されますが、データはユーザーが通知をクリックしたときにのみ実行されます。 onMessageRecivedでデータをすぐに実行したいので、これは私が望むものではありません。

データによる通知

[編集2]次のコードと許可をアプリに追加しました。アプリはDozeのアプリをホワイトリストに登録するようユーザーに要求するので、[はい]をクリックしました。その後、adb経由でデバイスをDozeに入れ、Pushを送信しました。デバイスを居眠りモードから戻すまで、何も起こりませんでした。したがって、残念ながら、これは機能しません。

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Intent intent = new Intent();
            String packageName = getPackageName();
            PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
            if (!pm.isIgnoringBatteryOptimizations(packageName)) {
                intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + packageName));
                startActivity(intent);
            }
        }

<uses-permission Android:name="Android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

[編集3]

さらにテストを行って、問題を特定し、Webアプリケーションコードを計算式から外そうとしました。デバイスをadb経由でDozeに配置し、代わりにFireBaseコンソールを使用してプッシュを送信します。 プッシュが正しく実行されましたこれは、すべてを送信するWebアプリケーションコードに問題があることを示していますfcmエンドポイントへのプッシュ情報。今晩コードを入手して、後で投稿します。

[編集4]さらにテストを行ったところです。デバイスを居眠りさせ、FireBaseコンソールを使用して、2つのキーと値のペアを含むデータメッセージを送信しました。デバイスがDozeにあり、アプリがフォアグラウンド(画面上)にある場合、プッシュが実行され、onMessageReceivedが実行されます。これは素晴らしい。ただし、アプリがBGにある場合は、通知のみが表示されます。ドキュメントから、データメッセージがIntentを介してランチャーアクティビティにディスパッチされることを理解していますが、ランチャーアプリはプッシュを処理しません。プッシュを処理するクラスはMyAndroidFirebaseMsgServiceと呼ばれ、FirebaseMessagingServiceを拡張します。

アプリがBGにある場合、このクラスにインテントをルーティングする必要がありますか?これをやらなければならないのは少し辛いようです。 GCMには当てはまりませんでした。

また、デバイスのユーザーが別のアプリを使用している可能性があるため、プッシュからアプリを起動することは非常に侵襲的です。私のアプリはデバイス管理アプリでもあるため、99%の時間、ユーザーとの対話はなく、デバイスでポリシーを実行するのはクライアントだけです。

[編集5]

internal static void SendNotification (  Dictionary<string, string> nameValues ,  List<string> theregIDs , string sPushName)
         {     
            string stringregIds =  string.Join("\",\"", theregIDs) ;

             JavaScriptSerializer js = new JavaScriptSerializer();
            string keyValueJson = js.Serialize(nameValues);

            string TIME_TO_LIVE = "604800";

            string DELAY_WHILE_IDLE = "false";

            string ENDPOINTADDRESS = @"https://fcm.googleapis.com/fcm/send";


            postData = String.Concat("{\"time_to_live\":", TIME_TO_LIVE,  ",\"delay_while_idle\": ", DELAY_WHILE_IDLE,  ",  \"Android\":{\"priority\":\"high\" } ,\"data\": { \"message\" : " + "\"" + sPushName + "\",\"time\": " + "\"" + System.DateTime.Now.ToString() + "\""
                , keyValueJson
               , "},\"registration_ids\":[\"" + stringregIds + "\"]}");


            WebRequest myWebRequest = null;
            WebResponse myWebResponse = null;
            try
            {
                myWebRequest = WebRequest.Create(ENDPOINTADDRESS);                         
                myWebRequest.Method = "post";
                myWebRequest.ContentType = "application/json";
                //  myWebRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
                myWebRequest.Headers.Add("Authorization: key=" + Our_Api_Key);
                myWebRequest.Headers.Add("Sender:id=" + Our_Sender_Id);

                Byte[] BA = Encoding.UTF8.GetBytes(postData);
                myWebRequest.ContentLength = BA.Length;

                using (Stream dataStreamOut = myWebRequest.GetRequestStream())
                {
                    dataStreamOut.Write(BA, 0, BA.Length);

                }

                using (myWebResponse = myWebRequest.GetResponse())
                {
                    using (Stream dataStream = myWebResponse.GetResponseStream())
                    {
                        using (StreamReader tReader = new StreamReader(dataStream))
                        {
                            strServerResponse = tReader.ReadToEnd(); 
                        }

                    }
                }


            }
            catch (WebException ex)
            {



            }

         }//

ありがとう

29
turtleboy

同様の問題に苦労した後、私はそれをうまく機能させることができました。

次のjsonデータをpostman経由で送信します。

{
  "data": {
    "body": "Test body from curl"
  },
  "registration_ids": ["Token"],
  "webpush": {
    "headers": {
      "Urgency": "high"
    }
  },
  "Android": {
    "priority": "high"
  },
  "priority": 10
}

最後の"priority":10は私のためにそれを修正しているものです。

Firebaseのドキュメントではこれを参照できませんでしたが、廃止されたGCMのドキュメントでは使用されています。 https://developers.google.com/cloud-messaging/concept-options

5
Patric Eriksson

できることは何もありません。

これは、一部のOEM(MeizuやAsusなど)によって実装されたバッテリー最適化が原因で発生する既知の問題です。アプリがアプリスイッチャーでスワイプされると、アプリケーションは強制停止されたものとして扱われます。これはデフォルトのAndroid behavoirではありません。これの不幸な副作用は、アプリのFCMサービスが実行を停止します。ドーズモードの優先度の高いメッセージにも同様の効果が生じる可能性があります。

Firebaseチームは、この動作を最後から改善するために取り組んでいますが、実際の修正はOEM側から行う必要があります。

アプリがOEMのバッテリー管理機能の影響を受けているかどうかを確認する1つの方法は、次のとおりです。

1)OEMデバイスをadbに接続します

2)デバイスでアプリを実行する

3)デバイスの最近の画面からアプリをスワイプします

4)次のコマンドを実行します:adb Shell dumpsys package MY-PACKAGE | grepが停止しました

Stopped = trueと表示されている場合は、OEMにそのようなメカニズムがあり、アプリが同じメカニズムの影響を受けていると想定しても安全です。

5
Kuva

アプリケーションの作業中、私はこの時点で立ち往生しています。それから、Githubでそれに関する問題を見つけ、私の問題を解決しました。あれは、

Android 6.0+では、Dozeモードは、電話機がアイドル状態で充電されていない場合、Pushyへのバックグラウンド接続を含む、すべてのバックグラウンド接続を終了します。

ユーザーがデバイスを移動または目覚めさせるとすぐに、バックグラウンド接続が復元され、保留中の通知は数秒以内に配信されます。

Dozeモードでデバイスに通知を送信するには、アプリでREQUEST_IGNORE_BATTERY_OPTIMIZATIONSそのAndroidManifest.xmlそして、アプリを終了せずにバッテリーの最適化からアプリをホワイトリストに登録するようユーザーに求めるシステムダイアログを表示します。

これにより、Pushyへのバックグラウンド接続が効果的に維持され、デバイスはDozeモードでも通知を受信できます。

この問題はここで確認できます https://github.com/ToothlessGear/node-gcm/issues/231

それがあなたを助けることを願っています!

2
Heisenberg

通知なしでデータフィールドのみを送信している間、高い優先度を設定することは不可能のようです。 ドキュメント からの引用です:

一般に、優先度の高いメッセージは、ユーザーがアプリまたはその通知を操作する必要があります。 FCMが検出し​​ないパターンを検出した場合、メッセージの優先順位が下がる可能性があります。

1
Wojtek

「Android」:{「priority」:「high」}を使用する代わりに、次のように使用します

    {
      "time_to_live": 300000,
      "delay_while_idle": false,
      "data": {
               "message": "PING_DEVICE",
               "time": "21/01/2018 16:20:28",
               "pushguid": "10062"
               },
      "priority": "high"  
}
0
imodeGowas

time_to_live of 0で問題が解決しました。

とても小さいtime_to_liveはFCMに、このメッセージは今すぐ配信するだけの価値があることを伝えます。したがって、できるだけ早く配信しようとすると、Android Pの「アプリスタンバイバケット」のようなバッテリーの最適化を無視します。ただし、小さなtime_to_liveを設定すると、通知をまったく配信しないことになります。場合によっては、あらゆる種類のプッシュ通知に適用すべきではないと思います。

Time_to_liveの詳細: https://firebase.google.com/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message

0
user11567387