【问题标题】:Capturing and Saving Videos in Android (API > 24) using File object?使用 File 对象在 Android(API > 24)中捕获和保存视频?
【发布时间】:2019-10-08 09:07:46
【问题描述】:

我想录制一个视频,然后在录制完成 5 秒后保存它。我有以下代码在 API 24 我得到了错误。

代码:

public void startRecording()
{
    File mediaFile = new
            File(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
            + "/myvideo.mp4");


    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT,5);
    fileUri = Uri.fromFile(mediaFile);

    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
    startActivityForResult(intent, VIDEO_CAPTURE);
}

protected void onActivityResult(int requestCode,
                                int resultCode, Intent data) {

    if (requestCode == VIDEO_CAPTURE) {
        if (resultCode == RESULT_OK) {
            Toast.makeText(this, "Video has been saved to:\n" +
                    data.getData(), Toast.LENGTH_LONG).show();
        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(this, "Video recording cancelled.",
                    Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(this, "Failed to record video",
                    Toast.LENGTH_LONG).show();
        }
    }
}

错误:

2019-10-08 01:15:43.483 21573-21573/com.mobilecomputing.learn2sign E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.mobilecomputing.learn2sign, PID: 21573
    android.os.FileUriExposedException: file:///storage/emulated/0/myvideo.mp4 exposed beyond app through ClipData.Item.getUri()
        at android.os.StrictMode.onFileUriExposed(StrictMode.java:1978)
        at android.net.Uri.checkFileUriExposed(Uri.java:2371)
        at android.content.ClipData.prepareToLeaveProcess(ClipData.java:963)
        at android.content.Intent.prepareToLeaveProcess(Intent.java:10228)
        at android.content.Intent.prepareToLeaveProcess(Intent.java:10213)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1854)
        at android.app.Activity.startActivityForResult(Activity.java:4599)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)
        at android.app.Activity.startActivityForResult(Activity.java:4557)
        at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:663)
        at com.mobilecomputing.learn2sign.PlayHelpVideo.startRecording(PlayHelpVideo.java:125)
        at com.mobilecomputing.learn2sign.PlayHelpVideo$1.onClick(PlayHelpVideo.java:46)
        at android.view.View.performClick(View.java:6669)
        at android.view.View.performClickInternal(View.java:6638)
        at android.view.View.access$3100(View.java:789)
        at android.view.View$PerformClick.run(View.java:26145)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6898)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

我检查了错误是因为文件对象的语法,并且 API > 24 不支持它。

虽然我可以找到其他正在运行的代码,但我很好奇这段代码是否有一个小的调整,可以使它也适用于 API > 24。也许在同一行。

谁能帮我解决这个问题?

编辑:

我尝试过:https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en,但这样做也会导致 API 22 上的应用程序崩溃。

更新:

根据回复的答案之一发布更改,代码适用于 API 24 上虽然没有崩溃,但是 createImageFile() 函数会抛出异常:

private File createImageFile() throws IOException {
    // Create an image file name
    String imageFileName = "myvideo";
    File storageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_DCIM), "Camera");
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".mp4",         /* suffix */
            storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    Log.v("myTag","FAB create image");
    mCurrentPhotoPath = "file:" + image.getAbsolutePath();
    return image;
}

这是从以下函数调用的:

public void startRecording()
{

    Log.v("myTag","FAB recording");
    File mediaFile = null;
    try {
        mediaFile = createImageFile();
    } catch (IOException ex) {
        Log.v("myTag","Exception");
        return;
    }


    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT,5);
    //fileUri = Uri.fromFile(mediaFile);
    fileUri = FileProvider.getUriForFile(PlayHelpVideo.this,
            BuildConfig.APPLICATION_ID + ".provider",
            mediaFile);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
    startActivityForResult(intent, VIDEO_CAPTURE);
}

【问题讨论】:

    标签: java android video-capture


    【解决方案1】:

    您可以使用FileProvider 类授予对特定文件或文件夹的访问权限,以便其他应用程序可以访问它们。创建您自己的继承 FileProvider 的类,以确保您的 FileProvider 不与此处所述的导入依赖项中声明的 FileProviders 冲突。

    file:// URI 替换为content:// URI 的步骤:

    添加一个扩展 FileProvider 的类

    public class GenericFileProvider extends FileProvider {}
    

    AndroidManifest.xml下添加一个FileProvider<provider>标签 <application> 标签。指定唯一权限 android:authorities 属性避免冲突,导入 依赖项可能会指定 ${applicationId}.provider 和其他 常用的权威。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        ...
        <application
            ...
            <provider
                android:name=".GenericFileProvider"
                android:authorities="${applicationId}.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
            </provider>
        </application>
    </manifest>
    

    然后在res/xml文件夹中创建provider_paths.xml文件。如果文件夹不存在,可能需要创建它。该文件的内容如下所示。它描述了我们希望共享对位于根文件夹 (path=".") 的外部存储的访问权限,名称为 external_files。

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

    最后一步是更改下面的代码行

    fileUri = Uri.fromFile(mediaFile);
    

    fileUri= FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".my.package.name.provider", mediaFile);
    

    【讨论】:

    • 发布此操作我的记录按钮停止在 api > 24 上工作。仍然适用于模拟器 API
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    相关资源
    最近更新 更多