在某些设备中使用作用域存储的SecurityException



我在谷歌上看到一些设备崩溃,比如三星和诺基亚,api 29和30。

日志:

Caused by: java.lang.SecurityException: 
at android.os.Parcel.createExceptionOrNull (Parcel.java:2385)
at android.os.Parcel.createException (Parcel.java:2369)
at android.os.Parcel.readException (Parcel.java:2352)
at android.os.Parcel.readException (Parcel.java:2294)
at android.app.IActivityManager$Stub$Proxy.getContentProvider (IActivityManager.java:6680)
at android.app.ActivityThread.acquireProvider (ActivityThread.java:7643)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider (ContextImpl.java:3090)
at android.content.ContentResolver.acquireUnstableProvider (ContentResolver.java:2484)
at android.content.ContentResolver.query (ContentResolver.java:1170)
at android.content.ContentResolver.query (ContentResolver.java:1118)
at android.content.ContentResolver.query (ContentResolver.java:1074)
at FileUtils.getFileName (FileUtils.java:69)
at MainActivity.onCreate (MainActivity.java:88)
at android.app.Activity.performCreate (Activity.java:8198)
at android.app.Activity.performCreate (Activity.java:8182)
at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3765)
Caused by: android.os.RemoteException: 
at com.android.server.am.ActivityManagerService.getContentProviderImpl (ActivityManagerService.java:8965)
at com.android.server.am.ActivityManagerService.getContentProviderImpl (ActivityManagerService.java:8804)
at com.android.server.am.ActivityManagerService.getContentProvider (ActivityManagerService.java:9505)
at android.app.IActivityManager$Stub.onTransact (IActivityManager.java:2840)
at com.android.server.am.ActivityManagerService.onTransact (ActivityManagerService.java:3617)

权限仅适用于android<28:

<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />

崩溃代码:

public static String getFileName(Context context, Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
cursor.close();
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}

清单:

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
<activity
android:name=".presentation.MainActivity"
android:exported="true"
android:theme="@style/Theme.MaterialComponents.Light.NoActionBar">
<intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/pdf"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/pdf"/>
</intent-filter>
</activity>

provider_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
<cache-path name="cache" path="." />
</paths>

这在90%的设备中运行良好。知道为什么会崩溃吗?我认为这可以用于在没有权限的情况下打开一些文件,但我无法复制

拥有触发打开文档意图的文件的应用程序可能未授予READ权限。例如

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // user's app may not have specified this

您的应用程序需要为Android 10及以上版本执行以下操作:

  1. 按照"请求应用程序权限"中列出的最佳做法,请求READ_EXTERNAL_STORAGE权限。

  2. 如果URI指向Android/dataAndroid/obb等受限制位置的文件,则即使您的应用程序具有READ_EXTERNAL_STORAGE权限,也无法读取该URI。在这种情况下,您的应用程序应该捕获Exception并向用户显示适当的错误消息。

因此,在MainActivityonCreate中,执行类似以下的操作

protected void onCreate(Bundle savedInstanceState) {
// on Android 10+ request READ_EXTERNAL_STORAGE permission
if (hasPermissions(READ_EXTERNAL_STORAGE)) {
try {
String name = FileUtils.getFileName(this, URI);
} catch (Exception e) {
showToast("Error loading file");
}
} else {
requestPermission(READ_EXTERNAL_STORAGE);
}
}

最新更新