Android 10(API29)下Qt+C++调用GDAL写应用目录文件崩溃求助
解决Android 10+下GDAL写入应用私有外部存储的问题
我之前在Qt+GDAL开发Android应用时也踩过Scoped Storage适配的坑,给你几个针对性的解决方案:
1. 优先确保使用正确的私有外部存储路径
Android 10及以上的Scoped Storage并没有限制应用私有外部存储(也就是Android/data/com.app.myapp/files)的直接读写,问题大概率出在硬编码路径的兼容性上:
- 绝对不要写死
/storage/emulated/0/Android/data/com.app.myapp/files,不同设备的外部存储根路径可能有差异(比如部分设备是/sdcard)。 - 在Qt里用标准路径API获取可靠路径:
QString outputDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QString outputPath = outputDir + "/your_output_raster.tif"; // 转成C字符串传给GDAL const char* cOutputPath = outputPath.toUtf8().constData(); - 如果Qt的路径获取有问题,也可以通过JNI调用Android原生API拿到路径:
再把这个路径传递回Qt层使用。// Java层代码 public static String getAppExternalFilesDir() { return getApplicationContext().getExternalFilesDir(null).getAbsolutePath(); }
2. 适配GDAL的VSI虚拟文件系统接口
如果直接传路径还是失败,可能是GDAL默认的文件访问逻辑在Android 10下有兼容性问题,可以试试用GDAL的虚拟文件系统包装路径:
- 在路径前加上
/vsifile/前缀,强制GDAL使用标准文件系统访问:std::string vsiPath = "/vsifile/" + std::string(outputPath.toUtf8().constData()); GDALDataset* dataset = GDALCreate(_driver, vsiPath.c_str(), xSize, ySize, rasterBandCount, _dataType, nullptr); - 同时要确认你使用的GDAL版本是适配Android的,编译时要开启
ANDROID相关选项(VSI文件系统默认是开启的)。
3. 必须用SAF时:通过文件描述符给GDAL提供访问
如果你的场景需要用户自定义存储位置(只能通过SAF获取Uri),可以把Uri转换成文件描述符,再让GDAL通过文件描述符操作:
- 在Android原生层将Uri转为可写的文件描述符:
// Java层代码 public static ParcelFileDescriptor getWritableFd(Uri uri) throws IOException { return getContentResolver().openFileDescriptor(uri, "w"); } - 将文件描述符传递给Qt层,用GDAL的VSI接口处理:
注:// 假设fd是从JNI拿到的文件描述符 VSILFILE* vsiFile = VSIFromFd(fd, "w", true); if (vsiFile != nullptr) { // 先在内存中创建数据集,再复制到文件 GDALDataset* memDataset = GDALCreate(_driver, "/vsimem/temp.tif", xSize, ySize, rasterBandCount, _dataType, nullptr); // 写入数据到memDataset... GDALDataset* fileDataset = GDALCreateCopy(_driver, "/vsifd/0", memDataset, FALSE, nullptr, nullptr, nullptr); GDALClose(memDataset); GDALClose(fileDataset); VSIFCloseL(vsiFile); }/vsifd/0表示使用文件描述符0,操作期间不要关闭这个描述符。
额外注意事项
- Android 10及以上,访问应用私有外部存储不需要申请
WRITE_EXTERNAL_STORAGE权限,如果Manifest里还保留这个权限,建议移除,避免系统权限策略干扰。 - 测试时可以先用Qt的
QFile::open测试路径是否可写,先排除GDAL之外的权限问题。
内容的提问来源于stack exchange,提问作者cosmarc
相关产品推荐
相关产品推荐

