Storage Access Framework(SAF)は、ファイルピッカーでアクセス対処のファイル(またはフォルダ)を指定する仕組みです。
指定されたURI(ファイル、フォルダ)は、アプリがアクセスする許可を付与したものになります。
そのまま、そのURIを使って読み書きが可能です。
ただし、このアクセス許可には期限があります。期限を過ぎれば失効します。
失効したら、再びファイルピッカーで指定すれば良いですが、ユーザーの操作を伴います。ユーザーのエクスペリエンス(使い易さ)は下がるでしょう!
そのような場合に、URIに対するアクセス許可を永続化できます。
※環境:Android Studio Narwhal Feature Drop | 2025.1.2 Patch 2
androidx.datastore:datastore-preferences:1.1.7
アクセス許可の期限
アクセス許可は、アプリのプロセスがOS内で稼働している間、有効です。
無効になるのは、次の操作を行った場合です。
無効になる操作- ・端末を再起動した後、アプリを起動
- ・Recentリストからアプリをクリアした後、アプリを起動
- ・アプリのストレージをクリアした後、アプリを起動
これらの操作は、アプリをプロセスごと停止し、新たなプロセスでアプリを起動するためです。
アクセス許可の永続化
takePersistableUriPermissionを使い、永続化します。
// Uriへアクセスする許可を永続化 val _takeFlags: Int = FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION this@Activity.contentResolver.takePersistableUriPermission(uri, _takeFlags) //
永続化の例
Storage Access Framework(SAF)でピッカーにより指定したフォルダを、アプリのワークフォルダにする例です。
ワークフォルダは、アプリの使い初めに一度だけ指定し、その後は同じフォルダを使い続けたいので、永続化します。
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings") val WORK_FOLDER = stringPreferencesKey("work_folder") class MainActivity : ComponentActivity() { private var workFolderUri: Uri? = null private val workFolderPicker = SafPicker { uri -> // Uriへアクセスする許可を永続化 val _takeFlags: Int = FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION contentResolver.takePersistableUriPermission(uri, _takeFlags) // UriをDataStoreへ書き込み lifecycleScope.launch(Dispatchers.IO) { dataStore.edit { settings -> settings[WORK_FOLDER] = uri.toString() } } // Uriの保持 workFolderUri = uri } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val _workFolderFlow: Flow<Uri?> = dataStore.data .map { preferences -> val _workFolder = preferences[WORK_FOLDER] _workFolder?.let { it.toUri() } } lifecycleScope.launch(Dispatchers.IO) { // UriをDataStoreから読み出し workFolderUri = _workFolderFlow.first() // Uri未定義ならば取得処理 if(workFolderUri == null) { workFolderPicker.launch(TreeOpenIntent()) } } enableEdgeToEdge() setContent { ... } } }
アプリの設定をDataStoreで管理しています。
アプリは起動すると、アプリの設定(ワークフォルダ)をDataStoreから読み出します。※Flowを使った非同期処理になっています。
ワークフォルダのURIが未定義(null)ならば、ファイルピッカーを起動して、フォルダの指定をユーザに求めます。
そして、ピッカーの結果として受け取ったURI(フォルダ)を永続化し、DataStoreに書き込みます。
※SAFの詳細は以下を参照(例は同じ関数を利用している)
「外部ストレージへStorage Access Frameworkでアクセス」
「SAFのACTION_OPEN_DOCUMENT_TREEでフォルダを指定」
※DataStoreの詳細は以下を参照
「DataStore」
関連記事: