Androidのプッシュ通知。 熊手、松葉杖、自転車

この記事を書くために、作業中のプロジェクトの1つで自分の前に設定されたタスク:アプリケーションにプッシュ通知を実装するように促されました。 すべてが単純なように見えました。ドキュメント、例などを勉強します。 さらに、私はすでに通知の経験がありました。 しかし、ここにはありませんでした...



Androidアプリケーションが実装されているフレームワーク内のサービスは、プッシュ通知の操作に関してかなり厳しい要件を提示します。 ユーザーに何らかのアクションを通知するのに30〜60秒以内に必要です。 正常に通知されると、ユーザーのデバイスからサーバーに、対応するステータスでリクエストが送信されます。 ドキュメントから、GCMサービス(Google Cloud Messaging)はデバイスへのPUSH通知の配信を保証しないことがわかっているため、バックドアオプションとして、これらの時間枠に違反した場合、当社のサービスはSMSを介してユーザーに通知します。 SMSメッセージのコストはPUSH通知よりもかなり高いため、クライアントデバイスへのSMSメッセージのフローを最小限に抑える必要があります。



ドキュメントを調べてプッシュ通知を台無しにした後、テスト用のアプリケーションの最初のビルドを複数のクライアントに送信し、待ち始めました。 結果はおよそ次のとおりです。





一部のクライアントは、プッシュの配信で遅延が発生したか、PUSHとSMSの両方を受信したと書きましたが、これは実用的ではありません。 他の人は、通知をまったく受け取らず、SMSだけを受け取ったと書いています。 3番目のテストデバイスでは、すべてが大丈夫でした。 不満のある顧客から最大限の情報を収集すると、彼らは問題を理解し始め、次の制限リストを推測し始めました(このリストは後に完全なFAQに変わりました)。





このメモをすべての顧客に送信した後、再び結果を待ち始めました。 そして、彼らは再び「それほどではない」ことが判明しました。 彼らはさらに掘り始めました。



この段階で 、Mail.ruのメンバーが書いた記事が大いに役立ちました。 クライアント側でGCMを実装することの微妙な点と、モバイルネットワークでのプッシュ通知が機能しなくなる瞬間について詳しく説明します。 最終的に、GCMとともにサーバーへの接続を維持することが決定されました。



決定を進める前に、潜在的に「機能しない」デバイスの範囲を絞り込むことができるいくつかの非常に重要なポイントを強調する価値があります。





それでは、実装に移りましょう。



経験豊富なAndroid開発者は、問題に対して少なくとも2つの解決策があるとすぐに言います:ServiceまたはAlarmManagerを使用します。 両方のオプションを試しました。 最初のものを検討してください。



バックグラウンドで絶えずハングし、タスクを実行するシステムで壊れないサービスを作成するために、次のメソッドを使用しました。



startForeground(int notificationID, Notification notification);
      
      





どこで





この場合、前提条件はステータスバーに通知を表示することです。 このアプローチにより、デバイスのメモリ不足時にサービスの優先度が高くなり(システムのUI部分と対話するため)、システムは最後の1つをアンロードします。 この通知は必要ないため、次の自転車を使用しました。最初のサービスと同時に2番目のサービスを実行し、両方のサービスでnotificationIDと同じ値を使用するだけで十分です。 次に、2番目のサービスを強制終了します。 この場合、通知はステータスバーから消えますが、最初のサービスの機能および優先機能は残ります。



このアプローチを実装したら、アセンブリをテストに送りました。 結果によると、システムはまだサービスをアンロードしていることが判明し、ログによると、サーバーからバックグラウンドでデータを要求する際に一時的なギャップがどのように発生したかがわかりました。 そのため、2番目のオプションであるAlarmManagerの実装を開始しました。



AlarmManagerは、大まかに言って「目覚まし時計」で作業を提供するクラスです。 これにより、システムがブロードキャスト通知を送信する時間を指定できます。ブロードキャスト通知により、アプリケーションを起動し、必要なアクションを実行できるようになります。 このメソッドの操作にはいくつかの制限があり、それらを処理する必要があります。





最初に踏んだレーキはメソッドでした



 setRepeating()
      
      





これにより、一定の間隔で繰り返し目覚まし時計を設定できます。 この方法を台無しにして、彼らはテストを始めました、そして、テストは反対を示しま​​した-「アラーム」は繰り返されませんでした。 彼らは何が起こっているのかを理解し始め、文書を見ました。 そして、19 API lvl(Kitkat)から始まって、システムのすべての「アラーム」が一度きりになりました。 結論-常にドキュメントをお読みください。



このレーキはフラストレーションの原因ではありませんでした。問題の解決策は非常に単純であるためです。1回限りの「アラームクロック」を開始し、操作後にリセットするためです。 このアプローチを実装すると、次のレーキに出くわしました。APIの異なるレベルでは、ドキュメントには何も記載されていないものの、アラームを異なるように設定する必要があることがわかりました。 しかし、この問題は非常に簡単に解決されました-「タイピング」と「グーグル」の方法によって。 以下は、「アラーム」を正しく設定できるようにするコードの例です。



 private static void setUpAlarm(final Context context, final Intent intent, final int timeInterval) { final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); final PendingIntent pi = PendingIntent.getBroadcast(context, timeInterval, intent, 0); am.cancel(pi); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { final AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + timeInterval, pi); am.setAlarmClock(alarmClockInfo, pi); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeInterval, pi); else am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeInterval, pi); }
      
      





AlarmManager.RTC_WAKEUPフラグに注意を払いたいです。画面が非アクティブなとき、デバイスがロックされた状態のときに、システムがアプリケーションを「ウェイクアップ」できるようにするのは、それの助けを借りてです。



「アラーム」を使用したこのアプローチにより、望ましい結果が得られました。バックグラウンドのアプリケーションは、新しいデータを求めてサーバーを正しくポーリングします。 現在、アルゴリズムを完成させています。 現在、次の最適化を実装およびテストしています。これにより、デバイスの範囲が狭まり、サーバーの負荷が軽減されます。





すべてに良い。 そして、そのような松葉杖が少なくなります。



PS

テストプロセスでは、 ツールが非常に役立ちました。これにより、送信されたプッシュに関する情報を見ることができます。 このツールは、開発者が無料で利用できます。 誰もが使用することをお勧めします。



Pss

私はおそらくコメントにバッテリー消費に関する質問があるだろうと予測しています。 私はいくつかのテストを実施しましたが、モバイルインターネットをオンにして、夜は個人の電話を残しました。 結果は、8〜9時間で充電の20〜25%程度でした。 また、テストアセンブリを送信したクライアントは、バッテリー消費の増加に伴う問題について不満はありませんでした。



All Articles