Skip to content

Android 10 以降の外部ストレージ権限制約と対応策

問題の概要

Android 10(API レベル 29)以降をターゲットとするアプリケーションで、android.permission.WRITE_EXTERNAL_STORAGE 権限に関する lint 警告が表示されます。この警告は、Android 10 以降ではこの権限が従来のような書き込みアクセスを提供しなくなることを示しています。

重要な変更点

Android 10 で導入された Scoped Storage により、外部ストレージへのアクセス方法が大幅に変更されました。これにより、アプリは特定のディレクトリに制限されるようになり、従来の広範なストレージアクセス権限は段階的に廃止されています。

ソリューション

1. 権限宣言の最適化

最も推奨される方法は、maxSdkVersion 属性を使用して、権限が必要な Android バージョンを明示的に指定することです。

xml
<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"
    tools:ignore="ScopedStorage" />

ツール名前空間の追加

tools:ignore 属性を使用するには、マニフェストにツール名前空間を宣言する必要があります:

xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.app">

2. ランタイム権限の適切な処理

権限リクエストをAndroidバージョンに応じて条件分岐させます:

kotlin
private fun hasWriteStoragePermission(): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Android 10以上ではWRITE_EXTERNAL_STORAGE権限は不要
        return true
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // Android 6.0以上では権限の確認と要求が必要
        if (ActivityCompat.checkSelfPermission(activity!!, 
            Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(
                arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                REQUEST_PERMISSIONS_CODE_WRITE_STORAGE
            )
            return false
        }
    }
    return true
}

3. Android 11 以降の対応

Android 11(API レベル 30)以降では、すべてのファイルアクセス権限 MANAGE_EXTERNAL_STORAGE が必要ですが、Google Play ポリシーの制約があるため注意が必要です。

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

Google Play ポリシーへの注意

MANAGE_EXTERNAL_STORAGE 権限を使用するアプリは、Google Play での審査が厳しくなります。この権限はコア機能に本当に必要な場合のみ使用し、可能であれば MediaStore API を使用するようにアプリを更新することが推奨されます。

Android 11 で特別なアクセス権限を要求するコード:

kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && 
    !Environment.isExternalStorageManager()) {
    val uri = Uri.parse("package:${BuildConfig.APPLICATION_ID}")
    startActivity(Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri))
}

バージョン別対応表

以下の表に、Android バージョンごとの推奨設定を示します:

Android バージョンAPI レベル必要な権限設定
Android 5.1 以下22以下WRITE_EXTERNAL_STORAGE
Android 6.0-9.023-28WRITE_EXTERNAL_STORAGE(ランタイム権限)
Android 1029requestLegacyExternalStorage="true" + WRITE_EXTERNAL_STORAGE(オプション)
Android 11 以上30以上MANAGE_EXTERNAL_STORAGE(必要な場合のみ)

パフォーマンスに関する注意点

Android 11 以降では、従来の File API はラッパーとして再実装され、内部的に MediaStore に処理を委譲します。これにより、パフォーマンスに影響があることに注意してください:

パフォーマンス影響

Android チームによると、File API の使用は Android 11 以降で 2〜3 倍遅くなる可能性があります。可能な場合は直接 MediaStore API を使用することを検討してください。

まとめ

Android のストレージアクセス権限への対応は、アプリのターゲット SDK バージョンと最小 SDK バージョンの両方を考慮する必要があります。maxSdkVersion 属性を使用した権限宣言と、バージョンに応じた条件分岐処理を組み合わせることで、すべての Android バージョンで適切に動作するアプリを開発できます。

最新のベストプラクティスとして、可能な限りアプリ固有のストレージディレクトリを使用し、MediaStore API を活用することで、将来の Android バージョン変更にも対応できる堅牢なアプリ設計を目指しましょう。