在NativeScript中读取图片EXIF数据遇JNI异常,求排查代码问题
解决NativeScript中读取图片EXIF时
openInputStream报错的问题 咱们先揪出核心问题:你直接把文件路径字符串传给openInputStream,但这个方法要求的是Uri对象,不是纯文本路径——这就是报错的根源!
下面一步步拆解修复方案,帮你搞定这个问题:
1. 把文件路径转换成合法的Uri
Android的ContentResolver.openInputStream()只接受Uri类型参数,直接传字符串路径会导致系统无法解析文件位置。针对相机文件夹的图片,有两种靠谱的转换方式:
方式一:从文件路径生成File对象再转Uri
这是最直接的方式,适合已知明确文件路径的场景:
import * as application from "application"; import { File } from "tns-core-modules/file-system"; async getExif(src) { // src是相机文件夹的文件路径字符串 // 先确保权限已获取(后面会讲权限问题) const hasPermission = await requestPermissions(); if (!hasPermission) return; try { const file = File.fromPath(src); const javaFile = new java.io.File(file.path); const uri = android.net.Uri.fromFile(javaFile); const contentResolver = application.android.nativeApp.getContentResolver(); const stream = contentResolver.openInputStream(uri); // 初始化ExifInterface并读取数据 const exif = new android.support.media.ExifInterface(stream); // 示例:读取图片拍摄方向 const orientation = exif.getAttributeInt( android.support.media.ExifInterface.TAG_ORIENTATION, android.support.media.ExifInterface.ORIENTATION_NORMAL ); // 务必关闭流,避免资源泄漏 stream.close(); return { orientation }; } catch (e) { console.error("读取EXIF失败:", e); } }
方式二:通过MediaStore查询Uri(适合系统媒体库中的图片)
如果图片是相机拍摄后存入系统媒体库的,用这种方式更稳定:
getExifFromMediaStore(imagePath) { try { const contentResolver = application.android.nativeApp.getContentResolver(); const projection = [android.provider.MediaStore.Images.Media._ID]; const selection = android.provider.MediaStore.Images.Media.DATA + " = ?"; const selectionArgs = [imagePath]; const cursor = contentResolver.query( android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null ); let uri = null; if (cursor != null && cursor.moveToFirst()) { const idColumn = cursor.getColumnIndex(android.provider.MediaStore.Images.Media._ID); const id = cursor.getLong(idColumn); uri = android.net.Uri.withAppendedPath( android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id.toString() ); cursor.close(); } if (uri) { const stream = contentResolver.openInputStream(uri); const exif = new android.support.media.ExifInterface(stream); // 这里可以读取你需要的EXIF标签,比如拍摄时间、光圈等 stream.close(); } } catch (e) { console.error("媒体库读取EXIF失败:", e); } }
2. 检查并申请存储权限
相机文件夹的图片属于外部存储,必须获取对应权限才能访问:
第一步:配置AndroidManifest.xml
在App_Resources/Android/src/main/AndroidManifest.xml中添加权限声明:
<!-- 适配Android 9及以下 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 适配Android 13及以上 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />
第二步:动态申请权限
NativeScript中需要主动请求权限,避免被系统拒绝:
import { Permissions } from "nativescript-permissions"; async function requestPermissions() { try { const permissions = android.os.Build.VERSION.SDK_INT >= 33 ? [android.Manifest.permission.READ_MEDIA_IMAGES] : [android.Manifest.permission.READ_EXTERNAL_STORAGE]; const result = await Permissions.requestPermissions(permissions); return result.every(status => status === "granted"); } catch (e) { console.error("权限申请失败:", e); return false; } }
3. 验证依赖版本兼容性
你在app.gradle中添加的com.android.support:exifinterface:25.1.0是旧版支持库,如果你的NativeScript项目已经迁移到AndroidX,建议改用AndroidX版本的依赖:
dependencies { implementation 'androidx.exifinterface:exifinterface:1.3.6' }
对应的代码中也要修改包名:
// 替换原来的android.support.media.ExifInterface const exif = new androidx.exifinterface.media.ExifInterface(stream);
最后:用adb logcat定位细节错误
如果还是报错,执行adb logcat命令查看完整的异常栈,重点关注AndroidRuntime开头的日志,比如是否是FileNotFoundException(文件不存在)或SecurityException(权限不足),这些细节能帮你快速定位剩余问题。
内容的提问来源于stack exchange,提问作者i.brod
相关产品推荐
相关产品推荐

