我有一个生成视频文件的应用程序,可以将其放置在内部存储器或SD卡中,并且需要由用户的首选视频播放器应用程序通过Intent.ACTION_VIEW打开。定位API 22时,该应用程序可以按预期工作,但尝试将其升级到27时出现问题。
该应用会根据存储位置生成不同类型的URI。对于内部存储,它使用文件URI,如下所示:
file:///storage/emulated/0/VideoRecorder/2018_06_22_12_25_50.mp4
对于放置在SD卡中的视频,它使用内容URI:
content://com.android.externalstorage.documents/tree/72D1-C625%3Avideostest%2Ftest2/document/72D1-C625%3Avideostest%2Ftest2%2F2018_06_22_12_41_27.mp4
Nougat不喜欢file:// URI,因此我使用FileProvider(下面的代码)来解决此问题,将文件URI转换为其他ACTION_VIEW可以打开的内容URI。我以为SD卡URI不需要进行任何更改,因为它已经是内容URI,但是似乎只有默认的Photos应用才能以ACTION_VIEW意图打开该URI,而用户安装的应用(如VLC Player)则不需要,失败,出现以下异常:
java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/tree/72D1-C625:videostest/test2/document/72D1-C625:videostest/test2/2018_06_22_12_27_45.mp4 from pid=7809, uid=10022 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()
检查了FileProvider生成的URI之后,我认为我理解了这个问题。它生成的内容URI的格式与我为SD卡视频提供的内容URI的格式完全不同:
content://io.github.androidtests.videorecorder.videosfileprovider/external_files/VideoRecorder/2018_06_22_12_25_50.mp4
我的问题是,是否还需要通过FileProvider共享SD卡视频?鉴于我只有内容URI,没有文件,而FileProvider似乎是专门设计用来将文件转换为URI的,我该怎么做?
编辑:在测试了更多的视频播放器应用程序之后,其中一些似乎可以使用内容URI,与“照片”应用程序相同。这只是某些应用尚不支持内容URI的情况吗?
代码:
Uri uri = adapter.mDataset.get(position).videoUri;
if (uri.toString().contains("file://")) {
try {
ParcelFileDescriptor pFD = ctx.getContentResolver().openFileDescriptor(uri, "r");
String truePath = Utils.getFdPath(pFD);
uri = FileProvider.getUriForFile(ctx, "io.github.androidtests.videorecorder.videosfileprovider", new File(truePath));
} catch (FileNotFoundException e) {
StaticMethodsAndValues.launchFabricException("RecyclerViewFragment caught FileNotFoundException when opening video.", e);
return;
}
}
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setDataAndType(uri, "video/mp4");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
ctx.startActivity(intent);
}
catch (ActivityNotFoundException e) {
Toast.makeText(mContext.get(), mContext.get().getString(R.string.toast_no_video_player_found), Toast.LENGTH_LONG).show();
StaticMethodsAndValues.launchFabricException("Device does not have app to handle intent action.VIEW for video/mp4.", e);
}
提供商清单定义:
<provider
android:name=".VideosFileProvider"
android:authorities="io.github.androidtests.videorecorder.videosfileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
提供者路径:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>