Android 13下Qt QML视频播放器如何访问USB存储播放视频?
解决Android 13下Qt视频播放器无法播放USB存储视频的问题
你遇到的核心问题是Android 13(API 33)对可移动存储访问权限的限制变更,以及Qt访问USB存储的特殊处理要求,以下是具体的解决步骤:
一、权限配置与申请调整
Android 13对存储权限做了大幅调整,原有的READ_EXTERNAL_STORAGE权限已无法覆盖USB可移动存储的访问需求,需要补充以下配置:
1. 更新AndroidManifest.xml权限
添加针对可移动存储的管理权限及USB相关权限:
<!-- 管理所有外部存储权限,适用于API 30+ --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" /> <!-- USB主机权限,用于识别USB设备 --> <uses-feature android:name="android.hardware.usb.host" android:required="false" /> <uses-permission android:name="android.permission.USB_PERMISSION" /> <!-- 保留媒体权限用于兼容媒体库索引的视频 --> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
2. 处理MANAGE_EXTERNAL_STORAGE权限
该权限无法通过常规运行时请求直接获取,必须引导用户到应用设置页面手动开启:
#include <QAndroidJniObject> #include <QAndroidIntent> // 检查是否已获取管理外部存储权限 bool hasManageStoragePermission() { return QAndroidJniObject::callStaticMethod<jboolean>( "android/os/Environment", "isExternalStorageManager" ); } // 引导用户到设置页面开启权限 void requestManageStoragePermission() { QAndroidJniObject activity = QtAndroidPrivate::activity(); QAndroidJniObject intentAction = QAndroidJniObject::getStaticObjectField( "android/provider/Settings", "ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION", "Ljava/lang/String;" ); QAndroidJniObject packageName = activity.callObjectMethod( "getPackageName", "()Ljava/lang/String;" ); QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod( "android/net/Uri", "fromParts", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/net/Uri;", QAndroidJniObject::fromString("package").object(), packageName.object(), nullptr ); QAndroidJniObject intent = QAndroidJniObject("android/content/Intent", "(Ljava/lang/String;)V", intentAction.object()); intent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object()); QtAndroidPrivate::startActivity(intent.object(), 1001); }
二、使用存储访问框架(SAF)访问USB视频
Android 13推荐使用SAF让用户主动选择文件,避免权限限制问题,同时Qt 6.4支持直接播放Content URI格式的视频:
1. 调用系统文件选择器
#include <QAndroidJniObject> #include <QAndroidIntent> #include <QString> // 打开文件选择器,指定视频类型 void openVideoPicker() { QAndroidJniObject intent = QAndroidJniObject("android/content/Intent", "(Ljava/lang/String;)V", QAndroidJniObject::fromString("android.intent.action.GET_CONTENT").object()); intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("video/*").object()); intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("android.intent.category.OPENABLE").object()); QtAndroidPrivate::startActivity(intent.object(), 1002); } // 处理文件选择结果(需重写Activity结果回调) void onActivityResult(int requestCode, int resultCode, const QAndroidJniObject &data) { if (requestCode == 1002 && resultCode == -1) { // RESULT_OK = -1 QAndroidJniObject uriObj = data.callObjectMethod("getData", "()Landroid/net/Uri;"); QString videoUri = uriObj.callObjectMethod("toString", "()Ljava/lang/String;").toString(); // 将URI传递给QML的Video组件 emit videoFileSelected(videoUri); } }
2. QML中播放Content URI
直接将获取到的content://开头的URI设置给Video组件:
Video { id: videoPlayer anchors.fill: parent source: "" onSourceChanged: { if (source) play() } } Connections { target: backend // 对应你的C++后端对象 function onVideoFileSelected(uri) { videoPlayer.source = uri } }
三、直接访问USB挂载路径的注意事项
如果需要直接访问USB的挂载路径(如/storage/XXXX-XXXX),需确保:
- 已获取
MANAGE_EXTERNAL_STORAGE权限 - 验证Qt能否识别该路径:
#include <QDir> #include <QDebug> void checkUSBMounts() { QDir storageDir("/storage"); QStringList dirs = storageDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); qDebug() << "已挂载的存储目录:" << dirs; // 遍历目录尝试打开视频文件,验证权限 for (const QString &dir : dirs) { QDir usbDir("/storage/" + dir); QStringList videos = usbDir.entryList({"*.mp4", "*.mkv"}, QDir::Files); if (!videos.isEmpty()) { QFile testFile(usbDir.filePath(videos.first())); qDebug() << "能否访问" << testFile.fileName() << ":" << testFile.open(QIODevice::ReadOnly); } } }
四、原代码的问题点
你原本的权限检查仅针对READ_EXTERNAL_STORAGE,但在Android 13中:
- 该权限仅能访问媒体库中的文件,无法覆盖USB存储的非索引文件
QtAndroidPrivate::Storage对应的权限已不符合Android 13的权限模型,需替换为MANAGE_EXTERNAL_STORAGE的检查逻辑
内容的提问来源于stack exchange,提问作者Elakiya
相关产品推荐
相关产品推荐

