Xamarin.Android中SAF保存Tree URI的正确方法(目标SDK Marshmallow)
嘿,这个问题我之前也碰到过!在Xamarin.Android里用SAF持久化外部SD卡的访问权限,直接存Uri的字符串确实会在重启后失效,核心问题是你没正确获取并保存持久化的权限令牌。下面是具体的解决步骤:
1. 获取Tree URI时立即申请持久化权限
当用户通过ACTION_OPEN_DOCUMENT_TREE选择完目录后,你不能直接把Uri转成字符串就存起来,必须先调用ContentResolver.TakePersistableUriPermission来获取长期访问权限。这个方法会把权限和你的应用签名绑定,重启后依然有效(除非用户手动撤销权限)。
示例代码:
// 定义请求码常量 private const int ACTION_OPEN_DOCUMENT_TREE = 1001; protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (requestCode == ACTION_OPEN_DOCUMENT_TREE && resultCode == Result.Ok) { var treeUri = data.Data; if (treeUri != null) { // 申请读写的持久化权限 var permissionFlags = ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission; ContentResolver.TakePersistableUriPermission(treeUri, permissionFlags); // 把Uri字符串保存到SharedPreferences var prefs = GetSharedPreferences("AppStoragePrefs", FileCreationMode.Private); using (var editor = prefs.Edit()) { editor.PutString("SavedTreeUri", treeUri.ToString()); editor.Apply(); } } } }
2. 重启后恢复Uri并验证权限
从SharedPreferences取出Uri字符串解析成Android.Net.Uri后,一定要先检查系统是否还保留着这个Uri的持久化权限。如果权限失效,就得重新引导用户选择目录。
示例代码:
private Android.Net.Uri GetPersistedTreeUri() { var prefs = GetSharedPreferences("AppStoragePrefs", FileCreationMode.Private); var savedUriStr = prefs.GetString("SavedTreeUri", null); if (string.IsNullOrEmpty(savedUriStr)) return null; var treeUri = Android.Net.Uri.Parse(savedUriStr); // 检查是否还有有效的持久化权限 bool hasValidPermission = false; var persistedPermissions = ContentResolver.PersistedUriPermissions; foreach (var permission in persistedPermissions) { if (permission.Uri.Equals(treeUri) && (permission.Flags & (ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission)) != 0) { hasValidPermission = true; break; } } if (!hasValidPermission) { // 权限已失效,重新请求用户选择目录 var intent = new Intent(Intent.ActionOpenDocumentTree); StartActivityForResult(intent, ACTION_OPEN_DOCUMENT_TREE); return null; } return treeUri; }
关键注意事项
- 必须在首次获取Uri时调用
TakePersistableUriPermission:如果跳过这一步,即使保存了Uri字符串,重启后系统也不会认可你的访问权限。 - 权限和应用签名绑定:只要你的应用签名不变,持久化权限会一直保留,除非用户手动在应用设置里撤销权限,或者卸载重装应用。
- 不要尝试解析Uri为本地文件路径:SAF的Uri是内容提供者的标识,不是直接的文件系统路径,所有读写操作都要通过
ContentResolver来完成。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

