Qt 6.9 Android应用如何自动获取存储权限以写入Documents文件夹
Qt 6.9 Android应用如何自动获取存储权限以写入Documents文件夹
嘿,这个存储权限的问题我之前也折腾过,Qt的QPermission确实没覆盖存储这类基础权限,得用Android原生的权限请求逻辑来搞,我给你一步步说怎么实现:
首先,你已经在Manifest里加了android.permission.READ_EXTERNAL_STORAGE和android.permission.WRITE_EXTERNAL_STORAGE,这步是对的,但Android 6.0及以上的危险权限(存储就属于这类)必须动态申请,不能只靠Manifest声明。
步骤1:检查当前权限状态
先写个工具函数,用Qt的JNI接口调用Android原生方法,判断存储权限是否已经授予:
#include <QAndroidJniObject> #include <QNativeInterface> bool hasStoragePermission() { const QString writePerm = "android.permission.WRITE_EXTERNAL_STORAGE"; QAndroidJniObject context = QNativeInterface::QAndroidApplication::context(); if (!context.isValid()) return false; jint result = context.callMethod<jint>( "checkSelfPermission", "(Ljava/lang/String;)I", QAndroidJniObject::fromString(writePerm).object<jstring>() ); // Android里PERMISSION_GRANTED的值是0 return result == 0; }
步骤2:动态请求权限
如果权限没被授予,就调用Android的requestPermissions方法弹出权限申请框:
void requestStoragePermission(int requestCode = 100) { const QString writePerm = "android.permission.WRITE_EXTERNAL_STORAGE"; QAndroidJniObject context = QNativeInterface::QAndroidApplication::context(); if (!context.isValid()) return; // 把权限字符串转成Java数组 QAndroidJniArray<jstring> permissions(1); permissions.set(0, QAndroidJniObject::fromString(writePerm).object<jstring>()); context.callMethod<void>( "requestPermissions", "([Ljava/lang/String;I)V", permissions.object<jobjectArray>(), requestCode ); }
步骤3:处理权限申请结果
权限申请的结果需要用QAndroidActivityResultReceiver来接收,我们可以写个接收器类:
#include <QAndroidActivityResultReceiver> #include <QDebug> class StoragePermissionReceiver : public QAndroidActivityResultReceiver { public: // 定义一个回调函数,方便通知主逻辑权限结果 std::function<void(bool)> onPermissionResult; void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override { if (receiverRequestCode != 100) return; // 只处理我们的请求码 jintArray results = data.callObjectMethod<jintArray>("getResult"); jint* result = QAndroidJniEnvironment::current()->GetIntArrayElements(results, nullptr); bool granted = (result[0] == 0); if (onPermissionResult) { onPermissionResult(granted); } // 释放JNI资源 QAndroidJniEnvironment::current()->ReleaseIntArrayElements(results, result, 0); } };
步骤4:整合到你的主逻辑里
现在把这些逻辑加到你的main函数里,替换原来直接创建文件的代码:
#include <QApplication> #include <QMainWindow> #include <QLabel> #include <QFile> #include <QStandardPaths> #include <fstream> // 把前面的hasStoragePermission、requestStoragePermission、StoragePermissionReceiver定义放这里 void createFile(QString &status) { auto folder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); auto fileName = folder + "/file.txt"; std::fstream file; file.open(fileName.toStdString().c_str(), std::ios_base::out); file << "Hello World!" << std::endl; file.close(); if (QFile(fileName).exists()) { status += "Could create new file " + fileName + "\n"; } else { status += "Could not create new file " + fileName + "\n"; } } int main(int argc, char* argv[]) { QApplication app(argc, argv); QMainWindow frame; QString status; QLabel* statusLabel = new QLabel(); frame.setCentralWidget(statusLabel); StoragePermissionReceiver permissionReceiver; permissionReceiver.onPermissionResult = [&](bool granted) { if (granted) { createFile(status); statusLabel->setText(status); } else { statusLabel->setText("Storage permission denied! Can't create file."); // 如果用户拒绝且勾选了"不再询问",这里可以引导用户去设置页开启权限 } // 记得注销接收器,避免内存泄漏 QNativeInterface::QAndroidApplication::unregisterActivityResultReceiver(&permissionReceiver); }; if (hasStoragePermission()) { // 已有权限,直接创建文件 createFile(status); statusLabel->setText(status); } else { // 无权限,申请权限 statusLabel->setText("Requesting storage permission..."); QNativeInterface::QAndroidApplication::registerActivityResultReceiver(&permissionReceiver); requestStoragePermission(100); } frame.show(); return app.exec(); }
额外提醒
- 如果用户拒绝权限并勾选了「不再询问」,下次调用
requestPermissions会直接返回拒绝,这时候你需要弹出提示,引导用户去应用的系统设置里手动开启权限。 - 对于Android 10及以上,还需要考虑
MANAGE_EXTERNAL_STORAGE权限,但你现在是Android 9,暂时不用管这个。 - 记得在Qt项目的
.pro文件里添加Android模块:QT += androidextras,否则JNI相关的头文件会找不到。
这样改完之后,你的应用启动时会自动弹出存储权限申请框,用户同意后就能自动创建文件啦,不用手动去设置里开权限了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

