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」
関連記事:
