Contents
はじめに
端末内のユーザーがアクセス可能な場所に画像を保存する。
前提としてiOSとAndroidで処理を分ける必要がある。(iOSは今回割愛)
特にAndroidはAPIレベルに応じて必要な権限が変わってくるので注意が必要。
Androidのファイルアクセス権限
Android9(API28)までは、READ_EXTERNAL_STORAGEとWRITE_EXTERNAL_STORAGEを追加することでファイルアクセスが可能。
Android10(API29)では、上記2つは非推奨になり、READ_MEDIA_IMAGESが推奨された。
そしてAndroid13(API33)では完全に無効化された。代わりにMANAGE_EXTERNAL_STORAGEを追加すればアクセス可能。
しかしこのMANAGE_EXTERNAL_STORAGEは、共有ストレージ内全ファイルへの読み取り・書き込み権となっていて、高リスク・センシティブな権限とされている。
使用には注意が必要で、ポリシー違反していたり、権限の申告をしていない場合GooglePlayからアプリが削除されることがある。
そのためなるべくこの権限を使わず実装する必要がある。
参考:https://support.google.com/googleplay/android-developer/answer/10467955?hl=ja
実装例
また画像の保存にmedia_store_plusと、photo_managerを使う。
photo_managerだけを使っていたが、Android13以上でメディアストアの更新ができず共有ストレージに保存できなかった。
しかしmedia_store_plusは逆にAndroid13未満で保存できていなかった。そのためOSバージョンで処理を分ける必要がありそう。
OSバージョン取得はdevice_info_plusを使う。
if (Platform.isAndroid) {
final androidInfo = await DeviceInfoPlugin().androidInfo;
final androidOsVersion = int.parse(androidInfo.version.release);
if (androidOsVersion < 13) {
//直接共有ストレージに保存
String externalPath =
await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_PICTURES);
final folderPath = "$externalPath/$myFolderName";
directory = await Directory(folderPath).create(recursive: true);
directoryPath = "${directory.path}/$fileName";
final saveFile = await writeImgToFile(directoryPath, url);
final assetEntity = await PhotoManager.editor.saveImageWithPath(
saveFile.path,
title: fileName,
relativePath: myFolderName,
);
} else {
//テンポラリファイル作成後コピー
final mediaStorePlugin = MediaStore();
MediaStore.appFolder = "MediaStorePlugin";
directory = await getTemporaryDirectory();
directoryPath = "${directory.path}/$fileName";
final saveFile = await writeImgToFile(directoryPath, url);
//media_store_plusで保存
//[xxx]:これがないとメディアストアが更新されない
int platformSDKVersion = await mediaStorePlugin.getPlatformSDKInt() ?? 0;
await mediaStorePlugin.saveFile(
tempFilePath: saveFile.path,
dirType: DirType.photo,
dirName: DirType.photo.defaults,
relativePath: myFolderName,
);
}
OSバージョンで処理分けする必要がないパッケージを探し中。
もっと良いやり方を見つけたら記事にします。