また、READ_EXTERNAL_STORAGE パーミッションも正式対応となりました。
この変更についてまとめたいと思います。
まずは言葉の説明から。
外部記憶領域(primary external storage)
以前は外部記憶領域といえば SD カード(外部ストレージ、外部SDなどと呼ばれる)のことを指しましたが、最近はストレージ内部の仮想的な記憶領域(内部ストレージ、内部SDなどと呼ばれる)のことを主に指します。
そのため、内部ストレージと呼ばれるのに外部記憶領域であり、
READ_EXTERNAL_STORAGE や WRITE_EXTERNAL_STRAGE が必要となるという少々混乱する状況でした。
(Environment#getExternalStorageDirectory()が内部SDを返すようになったり)
primary external storage などについては以下のサイトを読んでください。
External Storage Technical Information | Android Developers
KitKat での変更
KitKat からは EXTERNAL_STORAGE パーミッションの対象ディレクトリが変更となり、外部記憶領域上のアプリケーションデータ領域はパーミッションが不要となりました。
アプリケーションデータ領域の外部については EXTERNAL_STORAGE パーミッションが必要となっています。
アプリケーションデータ領域
- 本体メモリのアプリケーションデータ領域(アプリ内領域などと呼ばれる)
- /data/data/<パッケージ名>/
- 外部記憶領域上のアプリケーションデータ領域
- /<外部記憶領域>/Android/data/<パッケージ名>
本題
READ_EXTERNAL_STORAGE と WRITE_EXTERNAL_STRAGE が必要なのはどのディレクトリなのか、どのメソッドなのか調べました。
wada811/Android-StorageReadWriteChecker
BuildVariants と パーミッション | READ_EXTERNAL_STORAGE | WRITE_EXTERNAL_STRAGE |
---|---|---|
PreKitKat | ||
PreKitKatRead | ○ | |
PreKitKatWrite | ○ | |
PreKitKatReadWrite | ○ | ○ |
KitKat | ||
KitKatRead | ○ | |
KitKatWrite | ○ | |
KitKatReadWrite | ○ | ○ |
KitKatWriteCompat | ○(maxSdkVersion="18") | |
KitKatReadWriteCompat | ○ | ○(maxSdkVersion="18") |
結果
PreKitKat と KitKat の結果からgetExternalCacheDir と getExternalFilesDir で取得できる外部記憶領域上のアプリケーションデータ領域は
KitKat からパーミッションなしでも読み書き可能であることが確認できます。
READ_EXTERNAL_STORAGE が正式対応となったため
KitKat 以降で READ_EXTERNAL_STORAGE なしでは
Environment.getExternalStorageDirectory で取得できる外部記憶領域は
読み込みできないことが確認できます。(PreKitKat と KitKat)
KitKatRead から READ_EXTERNAL_STORAGE があれば
外部記憶領域の読み込みができることが確認できますね。
本題の本題
さて、getExternal~Dir で取得できる外部記憶領域上のアプリケーションデータ領域はKitKat からパーミッションなしでも読み書き可能ということが確認できましたが、
PreKitKat ではパーミッションが必要です。
KitKat では必要でないパーミッションを PreKitKat のために宣言すると
KitKat ユーザーに対して不要なパーミッションを取得することになります。
結局パーミッションは減らせないのかとなりそうですが、
KitKat で追加された Uses-Permission の maxSdkVersion 属性によって対応が可能です。
以下のように記述することで PreKitKat では WRITE_EXTERNAL_STORAGE を宣言し、KitKat ではパーミッションを宣言しないことができます。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />アプリ情報画面のパーミッションの欄を見ると PreKitKat では WRITE_EXTERNAL_STORAGE があり、
KitKat では WRITE_EXTERNAL_STORAGE はないことがわかります。
KitKatWriteCompat | KitKatReadWriteCompat | |
---|---|---|
PreKitKat | ||
KitKat |
結論
- Environment への書き込みがあるなら WRITE_EXTERNAL_STORAGE が必要
- getExternal~Dir への書き込みだけなら WRITE_EXTERNAL_STORAGE に maxSdkVersion="18" を付けておく
- 外部記憶領域への読み込みがあるなら READ_EXTERNAL_STORAGE が必要
参考
External storage access | Android 4.4 APIs | Android DevelopersAndroid:KitkatのREAD_EXTERNAL_STORAGEと外部記憶領域 | Taosoftware
WRITE_EXTERNAL_STRAGEと下位互換のためのmaxSdkVersion | Taosoftware