Android

~ was not granted either of these permissions: android.permission.CHANGE_NETWORK_STATE, android.permission.WRITE_SETTINGS. が出た!

android-marshmallow

先日、とあるAndroidアプリの試験中に表題のエラーに遭遇しました。
Androidの7系や8系では全く問題がないのに、Android6.0の端末でだけWifiの切り替えが動作しないのです。
一方で、Android6.0.1の端末ではWifiの切り替えがうまくいきます。

確認したところ、これはAndroid6.0固有のバグでした。
今回はこの件についてまとめていきますね。

CHANGE_NETWORK_STATEをリクエストするとPERMISSION_DENIEDとなる

Androidのバージョン(6.0以上)ごとにWifiの切り替えがうまく動作するか確認しました。

バージョンWifi切り替えの可否
6.0 失敗
6.0.1成功
7.0成功
8.0成功

保有する実機の数に限りがあったので、これだけしかデータがないのですが、6.0の時だけうまくいっていないように見受けられます。
ログを確認すると、この場合だけリクエストがPERMISSION_DENIEDとなっていました。

6.0だけWifi切り替えがうまくいかない原因は?

結論から言いますと、これはAndroid6.0固有のバグのようです。

Android 6.0でパーミッション周りの仕様が変更になりました。
アプリの操作中に時々現れる、権限ごとにユーザーに許可を求めるタイプのあれですね。

ネットワーク切り替え権限を取得する際はCHANGE_NETWORK_STATEをAndroidマニフェストに追加すると思うのですが、これを追加すると裏で勝手にConnectivityManagerのrequestNetwork()を呼んでくれます。

しかし、6.0の時だけは別のようです。
6.0の場合、ConnectivityManagerへの要求はすべてWRITE_SETTINGSによって管理されているようで、WRITE_SETTINGSが許可されていないとWifiの切り替えができないとのことです。
参考:ConnectivityManager.requestNetwork in Android 6.0

このバグは6.0.1で急遽修正されています。
以降のバージョンではCHANGE_NETWORK_STATEのみで大丈夫でした。

対応策は?

これは単純でした。
AndroidマニフェストにWRITE_SETTINGSを追加することで対応できます。

ちなみに、これは実機のバージョンが6.0の場合のみに必要な権限になります。

終わりに

Androidの試験で大変なのはバージョンごとの差異であると、改めて実感しました。
まだまだ古いバージョンを使われている方や企業さんも多いようですしね。
今日はここまでです。それでは。