Android11 アプリから外部MicorSDカードへ画像を保存する方法
カテゴリー: 総合
2023-10-28
タイトル
Android11は仕様がかわり
画像は 各ストレージ直下の[ DICM と Pictures ]フォルダ内(その子フォルダ)でしか保存できません。
アプリの権限は、[ READ_EXTERNAL_STORAGE , WRITE_EXTERNAL_STORAGE ]が必要です。
またすべてのフォルダで画像を保存できるようにするには、'android.permission.MANAGE_EXTERNAL_STORAGE'権限を取得する必要があります。
マニフェストとコード(権限リクエスト)と両方記述が必要です
ContentResolver.insert
に渡す Uri は、
.getContentUri([定義済み定数|ボリューム名]) から取得します。
定義済みの Uri 変数定数を使うと メインストレージにしか書き込めません。(ここが皆がわからずに SDcradに書き込めないと はまっている箇所です)
使える 外部 volumeは、
"external_primary" , MediaStore.VOLUME_EXTERNAL_PRIMARY
"xxxx-xxxx"; // SDカードの場合は数値に置き換える
です。
MediaStore.VOLUME_EXTERNAL_PRIMARYの値は "external_primary" です。
DelphiなどJAVA以外から操作する場合は、定数は定義されていないので 文字列を使ったほうがいいでしょう。
'xxxx-xxxx'は MediaStore.getExternalVolumeNames(context)で一覧を取得できます。
uri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
uri = MediaStore.Images.Media.getContentUri("external_primary");
uri = MediaStore.Images.Media.getContentUri("xxxx-xxxx");
uri = MediaStore.Files.getContentUri(volume);
のようになります。
SDCardは ファイルパスが
/strage/xxxx-xxxx/
になっています。
xxxx-xxxxは、メディアごとの識別子なので、別のカードやフォーマットすると変わってしまいます
ファイルパスは
メインストレージ: /strage/emulated/[ユーザーID:通常は0]/相対パス(可視領域)
外付けメディア: /strage/xxxx-xxxx/相対パス(可視領域)
ファイル名から取得する場合は、正規表現で ^/strage/([^/]+)/ にファイル名がマッチするか確認すればいいと思います
MediaStore.getExternalVolumeNames(context)のリスト値にないなら、メインストレージとか仮想メディアとか。
仕様が規格外の端末は相手にする必要はないと思います。
マッチしたらそれが ファイルの volumeです。getContentUriに渡す値になります!
ContentResolver.insert関数の結果で得た URIを
ContentResolver.openOutputStream関数に渡してオープンすると パスとファイルが作成されるので
存在しないフォルダの準備はしなくていいです。
フォルダを指定したい場合は、
ContentResolverに渡す値に, "relative_path" の項目で 相対パス(可視領域) を追加します
Pictures/子フォルダ/テスト.jpg に保存したい場合は
"relative_path"の値は "Pictures/子フォルダ" になります
執筆:2023.10.28
編集:2023.10.28
編集:2023.10.28
Android11は仕様がかわり
画像は 各ストレージ直下の[ DICM と Pictures ]フォルダ内(その子フォルダ)でしか保存できません。
アプリの権限は、[ READ_EXTERNAL_STORAGE , WRITE_EXTERNAL_STORAGE ]が必要です。
またすべてのフォルダで画像を保存できるようにするには、'android.permission.MANAGE_EXTERNAL_STORAGE'権限を取得する必要があります。
マニフェストとコード(権限リクエスト)と両方記述が必要です
ContentResolver.insert
に渡す Uri は、
.getContentUri([定義済み定数|ボリューム名]) から取得します。
定義済みの Uri 変数定数を使うと メインストレージにしか書き込めません。(ここが皆がわからずに SDcradに書き込めないと はまっている箇所です)
使える 外部 volumeは、
"external_primary" , MediaStore.VOLUME_EXTERNAL_PRIMARY
"xxxx-xxxx"; // SDカードの場合は数値に置き換える
です。
MediaStore.VOLUME_EXTERNAL_PRIMARYの値は "external_primary" です。
DelphiなどJAVA以外から操作する場合は、定数は定義されていないので 文字列を使ったほうがいいでしょう。
'xxxx-xxxx'は MediaStore.getExternalVolumeNames(context)で一覧を取得できます。
uri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
uri = MediaStore.Images.Media.getContentUri("external_primary");
uri = MediaStore.Images.Media.getContentUri("xxxx-xxxx");
uri = MediaStore.Files.getContentUri(volume);
のようになります。
SDCardは ファイルパスが
/strage/xxxx-xxxx/
になっています。
xxxx-xxxxは、メディアごとの識別子なので、別のカードやフォーマットすると変わってしまいます
ファイルパスは
メインストレージ: /strage/emulated/[ユーザーID:通常は0]/相対パス(可視領域)
外付けメディア: /strage/xxxx-xxxx/相対パス(可視領域)
ファイル名から取得する場合は、正規表現で ^/strage/([^/]+)/ にファイル名がマッチするか確認すればいいと思います
MediaStore.getExternalVolumeNames(context)のリスト値にないなら、メインストレージとか仮想メディアとか。
仕様が規格外の端末は相手にする必要はないと思います。
マッチしたらそれが ファイルの volumeです。getContentUriに渡す値になります!
ContentResolver.insert関数の結果で得た URIを
ContentResolver.openOutputStream関数に渡してオープンすると パスとファイルが作成されるので
存在しないフォルダの準備はしなくていいです。
フォルダを指定したい場合は、
ContentResolverに渡す値に, "relative_path" の項目で 相対パス(可視領域) を追加します
Pictures/子フォルダ/テスト.jpg に保存したい場合は
"relative_path"の値は "Pictures/子フォルダ" になります