Android

「ContextCompat.checkSelfPermission()が常にPERMISSION_DENIEDになってしまう」の記事が間違ってた話

もう削除したのですが、当初こんな記事を書いた。


概要

Androidでパーミッションを取得する際は、ContextCompat.checkSelfPermission()を使って、すでにユーザーがそのパーミッションを許可しているかどうかを確認する必要があります。
許可非許可は、Android 6.0 (API Level 23)以上の端末のみで可能になっていて、それ以下の端末の場合は、「AndroidManifest.xmlに該当のパーミッションをuses-permissionを使って記載をしているか」が許可非許可の代わりとなっています。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

ただ、今回HTC J ISW13HTにてテストを行っていた所、READ_EXTERNAL_STORAGEに関して、AndroidManifest.xmlに記載があるのに、checkSelfPermissionが常に非許可(PERMISSION_DENIED)になってしまっておりその解決方法を探りました。

結論

AndroidManifest.xml上でREAD_EXTERNAL_STORAGEをWRITE_EXTERNAL_STORAGEの前に書かないといけない


が、しかし・・・

その後、色々別の箇所を修正してやってみたところ、なんと同じ状態に・・・。戻して、上記の所を色々やってみた結果どうやら全く関係ないらしい。

ということで再度色々調べることにしました。

結論2

READ_EXTERNAL_STORAGEなんてなかった

正しくはあるにはあるのですが、APIドキュメントを見ていて気づいた。

Added in API Level 16
https://developer.android.com/reference/android/Manifest.permission.html#READ_EXTERNAL_STORAGE

ISW13HTはAndroid 4.0.2。Android Studio上でもAPI Level 16以上だよ!と出ている箇所と出ていない箇所があり、完全に見落としていました。

ただ、なんか色々おかしく、デバッグモードでブレークポイントを置き、「Manifest.permission.READ_EXTERNAL_STORAGE」をVariablesのところで見てみると「No such static field: 'READ_EXTERNAL_STORAGE'」と出ているのですが、

String permission = Manifest.permission.READ_EXTERNAL_STORAGE;

としてpermissionの値を見ると、android.permission.READ_EXTERNAL_STORAGEと値が入っている・・・。本来ならそのままExceptionなりで落ちてもいいものですが、そういうことではないらしい。

また、ちょっとどこのStackoverflowで見たのか定かじゃないのですが、

ContextCompat.checkSelfPermission()は存在しないパーミッションは許可しない

という実装になっているそうです。まぁこれはそうでしょうね。

ということで、android.permission.READ_EXTERNAL_STORAGEはAndroid 4.0には存在しないので許可されないというのが真相のようです(今度こそ。たぶん)。

上記を踏まえ、最終的にはこんな感じに修正しました。

String permission = Manifest.permission.READ_EXTERNAL_STORAGE;
if (Build.VERSION.SDK_INT <= VERSION_CODES.JELLY_BEAN) {
  permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
}
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
}

削除する前の記事には書いたのですが、ドキュメントを見ると、READ_EXTERNAL_STORAGEはWRITE_EXTERNAL_STORAGEを書いていれば権限が渡されているのと同じ状態となるようです。

Any app that declares the WRITE_EXTERNAL_STORAGE permission is implicitly granted this permission.
https://developer.android.com/reference/android/Manifest.permission.html#READ_EXTERNAL_STORAGE

そのため、今回はWRITE_EXTERNAL_STORAGEの権限があればOKということにしました。実際には無い権限なので、16以下はそもそもパーミッションのチェックをしない方が正なのかもしれないです。