You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
}

额外提醒

  1. 如果用户拒绝权限并勾选了「不再询问」,下次调用requestPermissions会直接返回拒绝,这时候你需要弹出提示,引导用户去应用的系统设置里手动开启权限。
  2. 对于Android 10及以上,还需要考虑MANAGE_EXTERNAL_STORAGE权限,但你现在是Android 9,暂时不用管这个。
  3. 记得在Qt项目的.pro文件里添加Android模块:QT += androidextras,否则JNI相关的头文件会找不到。

这样改完之后,你的应用启动时会自动弹出存储权限申请框,用户同意后就能自动创建文件啦,不用手动去设置里开权限了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 12:09:51