FlutterのAndroidとiOSでのファイルアクセス

# はじめに
FlutterでAndroidとiOSでファイルアクセスしたくなったので、動かしながら調べてみました。
まだしっかりと調べてないところもあるので内容を更新するかも。


# パスの取得方法

## アプリケーション用のパスを利用する場合は path_provider 

[path_provider](https://pub.dev/packages/path_provider) で取得されるパスはアプリケーション専用のパスを取得できます。
ほかのアプリケーションから参照することはできません。
ただし、パーミッションをAndroidManifest.xmlに設定する必要はありません。

以下のコマンドでプラグインを導入します。

```terminal
flutter pub add path_provider
```

使い方は簡単で、以下のように利用します。
```dart
var appDocDir = await getApplicationDocumentsDirectory();
File targetPath = File("${appDocDir.path}/test.txt");
```

|Method|Android|iOS|
|---|---|---|
|getApplicationDocumentsDirectory()|/data/user/0/<パッケージ名>/app_flutter/|/var/mobile/Containers/Data/Application/[UUID]/Documents/|
|getApplicationSupportDirectory()|/data/user/0/<パッケージ名>/files/|/var/mobile/Containers/Data/Application/[UUID]/Library/Application Support/|
|getDownloadsDirectory()|Androidは未対応|/var/mobile/Containers/Data/Application/[UUID]/Downloads|
|getExternalCacheDirectories()|/storage/emulated/0/Android/data/<パッケージ名>/cache/|iOSは未対応|
|getExternalStorageDirectory|/storage/emulated/0/Android/data/<パッケージ名>/files/|iOSは未対応|

getExternalStorageDirectories({StorageDirectory? type})
|type|Android|iOS|
|---|---|---|
|StorageDirectory.alarms|/storage/emulated/0/Android/data/<パッケージ名>/files/alarms/|iOSは未対応|
|StorageDirectory.dcim|/storage/emulated/0/Android/data/<パッケージ名>/files/dcim/|iOSは未対応|
|StorageDirectory.documents|/storage/emulated/0/Android/data/<パッケージ名>/files/documents/|iOSは未対応|
|StorageDirectory.downloads|/storage/emulated/0/Android/data/<パッケージ名>/files/downloads/|iOSは未対応|
|StorageDirectory.movies|/storage/emulated/0/Android/data/<パッケージ名>/files/movies/|iOSは未対応|
|StorageDirectory.music|/storage/emulated/0/Android/data/<パッケージ名>/files/music/|iOSは未対応|
|StorageDirectory.notifications|/storage/emulated/0/Android/data/<パッケージ名>/files/notifications/|iOSは未対応|
|StorageDirectory.pictures|/storage/emulated/0/Android/data/<パッケージ名>/files/pictures/|iOSは未対応|
|StorageDirectory.podcasts|/storage/emulated/0/Android/data/<パッケージ名>/files/podcasts/|iOSは未対応|
|StorageDirectory.ringtones|/storage/emulated/0/Android/data/<パッケージ名>/files/ringtones/|iOSは未対応|


## ユーザーがアクセス可能なパスを取得するなら external_path

このライブラリで取得できるパスはAndroid 13では android.permission.MANAGE_EXTERNAL_STORAGE を指定しないとアクセスできないっぽいです。
Android 9ではandroid.permission.READ_EXTERNAL_STORAGE、android.permission.WRITE_EXTERNAL_STORAGEアクセス可能。
ちなみにAndroid専用なのでiOSでは使えないです。
iOSで動かすと
```
MissingPluginException(No implementation found for method getExternalStoragePublicDirectory on channel external_path)
```
ってエラーになります。

以下のコマンドでプラグインを導入します。

```terminal
flutter pub add permission_handler
flutter pub add external_path
```

AndroidManifest.xmlに以下を追加
```xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>

<uses-permission android:name="android.permission.READ_MEDIA_IMAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>

<uses-permission android:name="android.permission.WRITE_MEDIA_IMAGE"/>
<uses-permission android:name="android.permission.WRITE_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.WRITE_MEDIA_AUDIO"/>

<application
・・・略・・・
android:requestLegacyExternalStorage="true"/>
```

|Parameter|Android|iOS|
|---|---|---|
|ExternalPath.DIRECTORY_ALARMS|/storage/emulated/0/Alarms/|iOSは未対応|
|ExternalPath.DIRECTORY_AUDIOBOOKS|/storage/emulated/0/Audiobooks/|iOSは未対応|
|ExternalPath.DIRECTORY_DCIM|/storage/emulated/0/DCIM/|iOSは未対応|
|ExternalPath.DIRECTORY_DOCUMENTS|/storage/emulated/0/Documents/|iOSは未対応|
|ExternalPath.DIRECTORY_DOWNLOADS|/storage/emulated/0/Download/|iOSは未対応|
|ExternalPath.DIRECTORY_MOVIES|/storage/emulated/0/Movies/|iOSは未対応|
|ExternalPath.DIRECTORY_MUSIC|/storage/emulated/0/Music/|iOSは未対応|
|ExternalPath.DIRECTORY_NOTIFICATIONS|/storage/emulated/0/Notifications/|iOSは未対応|
|ExternalPath.DIRECTORY_PICTURES|/storage/emulated/0/Pictures/|iOSは未対応|
|ExternalPath.DIRECTORY_PODCASTS|/storage/emulated/0/Podcasts/|iOSは未対応|
|ExternalPath.DIRECTORY_RINGTONES|/storage/emulated/0/Ringtones/|iOSは未対応|
|ExternalPath.DIRECTORY_SCREENSHOTS|/storage/emulated/0/Screenshots/|iOSは未対応|

## 画像の保存は image_gallery_saver

gallery_saver もあるが、image_gallery_saver のほうが融通が利くのでこちらを使うのがよさそう。
とりあえず、これで保存はできる。


# 参考
[Flutter　 端末内のユーザーがアクセス可能な場所にファイルを保存する方法（バックアップ機能の実装）](https://halzoblog.com/flutter-backup-in-device/#toc15)