通信前の事前チェック処理に関する考察
はじめに
の <Retryしたい状況を考えてみる>
で圏外時の、通信の再トライに関して書いてみましたが、
それ以外でも必要なケースがあるかなと思い考察してみます
懸念点を洗い出してみると
圏外以外のケースだと
- Battery Saver
- Soft Doze/Deep Doze モード
- 上記モード時に通信遮断
- DataSaver
- アプリがバックグラウンド時に通信遮断
この条件が適応された時、IOException が飛ぶわけですが、*1
通常の通信失敗と判別かつかない わけです。
本来なら それ専用のExceptionをG様が飛ばしてくれれば対処が可能なんですけどね。。
上記新しめOSのエコモード的な新機能の情報の洗い出し
Battery Saver
Android5から入った、標準のエコモード?
バッテリが15%以下になると、有効にするかどうか聞いてくる感じ
Nexus系とかだと
- CPUクロックが低下する
- 画面が非常に暗くなる
- アカウントの同期機能等が無効になる
- Activity起動時などにアニメーションが行われないようになる
- バイブレーションが無効になる
- ステータス・バーとナビゲーション・バーがオレンジになる
- 通信も基本は遮断される*2
- 基本電話待受とか出来るモード?になる
らしいんだけど、
其のタイミングで、現在の状態を一時保存するのが多分良かとおもう
PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && powerManager.isPowerSaveMode()) { //処理 }
通信遮断時の対処案的な考察
Dozeモードの対処も含め
Firebaseのrealtime保存みたいな仕組みが一番いいパターンになるんだろうなと
- Firebase JobDispatcher にジョブ登録
- GooglePlay開発者サービスの方にJob登録されるそう
- 端末の電源が完全に落ちないかぎりは大丈夫
- ローカルに通信予定情報を保存(Jsonとかで)
- サーバー通信ができた時点で、通信済みのチェックをいれるか消すかする
Data Saver
Android7から入った、「(3G/LTEの)バックグラウンド通信を制限する」*3の強化版
Services等で、バックグラウンド通信が常時必須ならホワイトリストに入れるしかない
これウイジェットとかでもホワイトリスト対応は必要じゃないんだろうか?
一応ホワイトリストに入れる場合は
Intent intent = new Intent(Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS, Uri.parse("package:" + getPackageName())); startActivity(intent);
- 判定は下記のコード。
- ConnectivityManagerCompat::getRestrictBackgroundStatus がsuppot-libraryに追加されてはいますが、これ 25.X のバージョンから
//DataSaverが有効か否か private boolean isDataSaver(Context context){ ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); //現在モバイル通信で、かつバックグラウンドデータが制限されているか否か ◎ boolean bgData = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1){ bgData = connMgr.isActiveNetworkMetered(); } else{ bgData = connMgr.getBackgroundDataSetting(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && bgData) {//★ //アプリ単位の DataSavar ON/OFFチェック int restrictBackgroundStatus = connectivityManager.getRestrictBackgroundStatus(); switch (restrictBackgroundStatus) { case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED: Log.v("TAG", "RESTRICT_BACKGROUND_STATUS_DISABLED"); return false; case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED: Log.v("TAG", "RESTRICT_BACKGROUND_STATUS_ENABLED"); return true; case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED: Log.v("TAG", "RESTRICT_BACKGROUND_STATUS_WHITELISTED"); return false; } } return false; }
ネットのサンプルを見えていると★が入っていないコードが多くて、その状態だと正常に取得できない挙動。
でもまあ ◎の処理自体 Wifi通信だと意味がない判定ではあるんですけどね
DataSaverがONのままでのバックグラウンド判定
ActivityGroup での 判定が非推奨な状況だと 下記な判定は必要になるのかなと
基本ONにしてもらうっていうのは難しいと思うので
RuntimePermission のときのように設定を変更してもらうのではなく
<通信遮断時の対処案的な考察> で対処を逃げるしかないのですかね・・
DataSaver判定は3Gの時のみすべき(2017/7/6追記)
上記の判定を、 * 例えば起動時に入れると、毎回表示が出てしまう・・ * NW接続がない時 * Wifi運用の端末
正直、接続中で3G/LTEのときのみ表示すべき
public static boolean isNotWifiConnected(Context context) { ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo() if(networkInfo != null){ return false; } if(!networkInfo.isConnected()){ return false; } if(networkInfo.getType() != ConnectivityManager.TYPE_WIFI){ return false; } return true; }
ただ下記の例みたいにBroadcastReciverまでは必要ないと思うけど
というより OS7より
辺りの制限があるので、BroadcastReciver運用自体は、今後中々厳しいかも
Dozeモード
画面スクリーンOFFにしていても、バックグラウンド通信が走っていると電池の消耗が激しいため
- モード中は
- バックグラウンドの通信を止めましょう
- モードから復帰時には
- ペンディングになっていた SyncAdapter/JobScheduler/AlarmManager の処理はすべて実行
という仕様
正直動かしてみた感じ
- モードに入る前に登録されて再生されていない予約JOBは再生
- モード中は予約JOBが登録されていない?
というのが正確な挙動の気がする
一応、Intent経由で無効にはできますが
電池の最適化を無視しますか?
と表示されてイメージが悪くなるので、ユーザー同意はしない機能。詳細は下記ページが参考になる
浅いDoze(Soft Doze)
- 6系だと放置30分後から
7系だと放置5分後から
AlarmManager の Dozeで動く関数でも約10分に1回しか動かせなくなる*7
- setAndAllowWhileIdle
- setExactAndAllowWhileIdle
深いDeep(Deep Doze)
- 7系だと30分後から
- PCでいう Sleepモード*8
だからモードに入ったときの処理は完全に無理
公式に推奨されている対処法的には
- Firebase JobDispatcherの利用を推奨
- Jobの状態がちゃんと保存されているらしい
- 規程時間に処理させたい場合には
- 指定時間直前にFCM(high priority)で通知
- 通常モードにアプリを復帰させる
DOZE無効にするだけなら
id:sakura_bird1 先生が既に調べているんですよね。*9
ただこの権限つけるとマーケットリリース時に弾かれると言う話がTwitterで言及されていたかと