ページ

2014/09/19

[Android]KitKatと外部記憶領域とREAD_EXTERNAL_STORAGEとWRITE_EXTERNAL_STRAGEとmaxSdkVersion

KitKat で外部記憶領域の読み書きに関するパーミッションに変更がありました。
また、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_STORAGEWRITE_EXTERNAL_STRAGE
PreKitKat
PreKitKatRead
PreKitKatWrite
PreKitKatReadWrite
KitKat
KitKatRead
KitKatWrite
KitKatReadWrite
KitKatWriteCompat○(maxSdkVersion="18")
KitKatReadWriteCompat○(maxSdkVersion="18")
データ:Android - KitKatと外部記憶領域とREAD_EXTERNAL_STORAGEとWRITE_EXTERNAL_STRAGEとmaxSdkVersion - Qiita

結果

PreKitKatKitKat の結果から
getExternalCacheDir と getExternalFilesDir で取得できる外部記憶領域上のアプリケーションデータ領域は
KitKat からパーミッションなしでも読み書き可能であることが確認できます。

READ_EXTERNAL_STORAGE が正式対応となったため
KitKat 以降で READ_EXTERNAL_STORAGE なしでは
Environment.getExternalStorageDirectory で取得できる外部記憶領域は
読み込みできないことが確認できます。(PreKitKatKitKat)
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 Developers
Android:KitkatのREAD_EXTERNAL_STORAGEと外部記憶領域 | Taosoftware
WRITE_EXTERNAL_STRAGEと下位互換のためのmaxSdkVersion | Taosoftware