targetSdkVersion > 30 如何将下载的网络视频 保存到手机相册里更新

在 targetSdkVersion 31 中,将下载的网络视频保存到手机相册中涉及几个关键步骤。由于 Android 12(API 级别 31)引入了更多的隐私和安全限制,特别是作用域存储(Scoped Storage),因此你需要遵循这些限制来保存文件。

以下是将下载的网络视频保存到手机相册的步骤:

  1. 请求必要的权限 :
    • 对于网络下载,你可能需要 INTERNET 权限。
    • 对于保存到外部存储,你需要考虑作用域存储的限制。如果你的应用面向的是 Android 10(API 级别 29)及以上版本,并且你的应用没有声明 requestLegacyExternalStorage 属性为 true,则你需要使用 MediaStore API 来保存文件,并且不需要 WRITE_EXTERNAL_STORAGE 权限。
  2. 下载视频文件 :
    • 使用适当的网络库(如 OkHttp, Retrofit, Volley 等)从网络下载视频文件。
    • 将下载的视频文件保存到应用的私有目录(例如,使用 getExternalFilesDir(null) 或 getCacheDir())。
  3. 使用 MediaStore 保存视频到相册 :
    • 创建一个 ContentValues 对象来存储视频文件的元数据。
    • 使用 MediaStore.Video.Media.getExternalContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) 获取外部存储中视频内容的 URI。
    • 调用 ContentResolver.insert() 方法来创建一个新的视频条目。
    • 使用 ContentResolver.openOutputStream() 获取输出流,并将下载的视频文件数据写入该输出流。
  4. 更新媒体数据库 :
    • 在视频文件写入后,你可能需要通知媒体扫描器扫描该文件,以便它出现在相册中。这可以通过发送一个 Intent 来实现,使用 MediaScannerConnection.SCAN_FILE_ACTION。

下面是一个简化的代码示例,展示了如何实现这一过程:

java 复制代码
// 假设你已经从网络下载了视频,并且将其保存在了 privateDir 路径下  
File videoFile = new File(privateDir, "downloaded_video.mp4");  
  
// 使用 MediaStore API 保存视频到外部存储  
ContentValues values = new ContentValues();  
values.put(MediaStore.Video.Media.DISPLAY_NAME, videoFile.getName());  
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");  
values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES);  
  
Uri collection = MediaStore.Video.Media.getExternalContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);  
Uri videoUri = getContentResolver().insert(collection, values);  
  
try (OutputStream outputStream = getContentResolver().openOutputStream(videoUri)) {  
    Files.copy(videoFile.toPath(), outputStream);  
} catch (IOException e) {  
    e.printStackTrace();  
}  
  
// 通知媒体扫描器扫描新文件  
MediaScannerConnection.scanFile(this,  
        new String[]{videoFile.toString()},  
        new String[]{"video/*"},  
        null);

请注意,由于作用域存储的限制,你可能无法直接将文件保存到公共目录(如 Environment.DIRECTORY_MOVIES)。如果你的应用没有请求 MANAGE_EXTERNAL_STORAGE 权限,或者用户没有授予该权限,你可能需要将文件保存到应用的私有目录,并通过 MediaStore 创建一个指向该文件的引用。

此外,始终确保你的应用遵循最新的 Android 存储最佳实践,并考虑到用户隐私和数据安全。

另外

在 Android 10(API 级别 29)及以上版本,由于作用域存储(Scoped Storage)的引入,直接获取文件在外部存储的完整路径变得不再直接可行。相反,您应该使用 ContentResolver 和 ContentValues 将文件保存到 MediaStore,并通过返回的 Uri 来引用它。这样,视频文件就可以被其他应用(如相册)访问,而不需要知道其实际存储路径。

以下是一个示例,展示了如何将下载的视频保存到 MediaStore 并获取其 Uri:

java 复制代码
private Uri saveVideoToMediaStore(Context context, File videoFile) throws IOException {  
    // 创建一个 ContentValues 对象来存储视频文件的元数据  
    ContentValues values = new ContentValues();  
    values.put(MediaStore.Video.Media.DISPLAY_NAME, videoFile.getName());  
    values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");  
    values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_MOVIES);  
  
    // 获取外部存储中视频内容的 Uri  
    Uri collection = MediaStore.Video.Media.getExternalContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);  
  
    // 使用 ContentResolver 插入一个新的视频条目到 MediaStore  
    Uri videoUri = context.getContentResolver().insert(collection, values);  
  
    // 使用 ContentResolver 打开一个输出流来写入视频文件  
    try (OutputStream outputStream = context.getContentResolver().openOutputStream(videoUri)) {  
        Files.copy(videoFile.toPath(), outputStream);  
    }  
  
    // 通知媒体扫描器扫描新文件,使其出现在相册中  
    MediaScannerConnection.scanFile(context,  
            new String[]{videoFile.getAbsolutePath()},  
            new String[]{"video/*"},  
            null);  
  
    return videoUri;  
}

在这个示例中,videoUri 就是您需要的 Uri,它代表了保存在 MediaStore 中的视频文件。您可以使用这个 Uri 来在其他地方引用该视频,例如在一个 Intent 中传递给相册应用。

请注意,由于作用域存储的限制,您无法直接从这个 Uri 获取文件的完整路径。如果您需要这个路径用于某些特定的操作(比如在其他应用中分享文件),您可能需要使用 FileProvider 来创建一个临时访问权限的 Uri。

如果您确实需要获取视频文件的路径用于某些特殊情况(比如备份到云存储),您可以使用 ContentResolver 和 openFileDescriptor 方法来获取一个 ParcelFileDescriptor,然后从中获取文件描述符,并最终转换为 File 对象。但请注意,这样做可能会违反 Android 的隐私政策,因此应该谨慎使用,并确保您的应用遵循了所有的最佳实践和隐私指南。

如果您的应用需要兼容低版本的 Android(低于 API 级别 29),您可能需要采用不同的方法来保存视频到外部存储,因为作用域存储(Scoped Storage)在这些版本上不可用。在这种情况下,您可能需要请求 WRITE_EXTERNAL_STORAGE 权限,并将文件直接保存到公共目录(如 /sdcard/DCIM/Camera/)中。

以下是一个兼容低版本的示例,展示如何保存视频到外部存储并获取其路径:

java 复制代码
private String saveVideoToExternalStorage(Context context, File videoFile) {  
    // 确保有写入外部存储的权限  
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {  
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)  
                != PackageManager.PERMISSION_GRANTED) {  
            // 请求写入外部存储的权限  
            ActivityCompat.requestPermissions(  
                    (Activity) context,  
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},  
                    MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);  
            // 等待用户授权  
            return null;  
        }  
    } else {  
        // 对于低于 Android 10 的版本,您可以在 AndroidManifest.xml 中声明权限  
    }  
  
    // 获取外部存储的目录  
    File externalStorageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);  
    if (!externalStorageDir.exists()) {  
        if (!externalStorageDir.mkdirs()) {  
            Log.e("VideoSave", "Failed to create directory");  
            return null;  
        }  
    }  
  
    // 将视频文件复制到外部存储的目录  
    File destinationFile = new File(externalStorageDir, videoFile.getName());  
    try {  
        Files.copy(videoFile.toPath(), destinationFile.toPath());  
        return destinationFile.getAbsolutePath();  
    } catch (IOException e) {  
        e.printStackTrace();  
        return null;  
    }  
}

在这个示例中,我们首先检查应用是否有写入外部存储的权限。如果没有,我们会请求这个权限。一旦获得权限,我们就将视频文件复制到外部存储的 /sdcard/Movies/ 目录下,并返回文件的绝对路径。

请注意,从 Android 10(API 级别 29)开始,推荐的做法是使用 MediaStore API,因为它提供了更好的隐私控制和兼容性。如果您的应用需要支持 Android 10 及更高版本,强烈建议使用 MediaStore 方法。如果您的应用需要兼容低版本,并且您确定您的用户主要使用这些低版本设备,那么您可以使用上述方法。但请记住,随着时间的推移,低版本设备的用户群体可能会逐渐减少,因此最好尽可能使用最新的 API 和实践。

相关推荐
三少爷的鞋5 小时前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
Dovis(誓平步青云)8 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码10 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程13 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程15 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程15 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程15 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
事圆则缓15 小时前
Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程
android
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer