studio中碰到的jni问题:java.lang.UnsatisfiedLinkError

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52606328

studio中碰到的jni问题

最近在做supervideo,解析youku视频地址,是加过密处理,须要用对应的key去解析,获取对应数据,在引用jni时,发现接二连三出问题,以前用eclipse时开发,直接把so文件放在libs/armeabi/下,就可以了,如果有有平台差异,也最多加个libs/armeabi-v7a之类的,在studio中,jni以前虽然写过相关工程,但是没有没有遇到相关问题,看来应了一句话:没有问题,可能以后才是最大的问题。那就总结下这两天这个接二连三的异常。

首先,在拼接好了url之后,接用把key和url去加密,调用jni方法。报出第一个错误,信息如下:

这里写图片描述

看了下,是说so文件没有打进apk中,于是开始在main目录下建立一个jniLibs,把so拷进去。(ps:之前是以引用的方式)
这下so应该拷贝进去了,一运行,又挂了,看下异常如下:

这里写图片描述

这个直接说是so文件没有相关方法,这有点说不过去了,又开始折腾了一会,还是这个错误,不合理啊,这不是什么技术上的难点。没理由这么。。。肯定是那里写的有问题。于是再review下代码。发现了,我在用调用native方法时,没有按规则来,想起很久以前调用aidl时,也有一个类似的情况,就是无法link里面的方法。我看了下引用native方法的包名和文件名,。。。。我自己改成我的package了,so文件声明却不是以我的命名开头的。好吧,明白了。改成对应的包名及文件名,问题解决。不是什么技术难点的时候,尤其多review下自己的代码。因为没理由让你耗费大量时间。

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

这里写图片描述

如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

<think>我们正在解决一个在Android应用`com.zrar.pjsipdemo`中遇到的`java.lang.UnsatisfiedLinkError`错误。错误信息是:`No implementation found for void org.pjsip.pjsua2.pjsua2JNI.sw`。这个错误通常发生在JNIJava Native Interface)调用本地方法时,系统找不到对应的本地库实现。根据用户提供的引用资料和之前的对话,我们特别关注PJSIP库在Android上的集成问题。 ### 错误原因分析 1. **本地库未正确加载**:应用启动时,Java层通过`System.loadLibrary`加载本地库(如`libpjsua2.so`),如果库文件缺失、路径错误或ABI不匹配,就会引发此错误。 2. **JNI方法签名不匹配**:Java中声明的native方法与C++实现的函数签名不一致,导致链接失败。但由于错误信息中提到了`org.pjsip.pjsua2.pjsua2JNI.sw`,这可能是SWIG生成的封装代码中的某个方法。 ### 重点排查方向 根据引用[1]中提到的映射关系问题,我们注意到XML配置和Java代码之间的映射必须正确。但在JNI场景中,我们需要检查: - **SWIG生成的Java封装代码**是否完整包含所有native方法(特别是`swig_module_init`这类初始化方法)。 - **本地库的编译选项**是否与Java层要求的ABI一致(如armeabi-v7a, arm64-v8a等)。 ### 解决方案步骤 #### 步骤1:确认本地库加载顺序 在调用任何PJSIP方法之前,必须先加载本地库。通常我们在静态块中加载: ```java public class MyApp extends Application { static { // 确保库名与编译生成的完全一致(去掉前缀lib和后缀.so) System.loadLibrary("pjsua2"); // 如果还有其他依赖库,按依赖顺序加载 } } ``` **注意**:如果库之间有依赖关系(如`pjsua2`依赖`pj`),需要先加载被依赖的库(可通过修改编译脚本将多个库合并解决依赖问题)[^1]。 #### 步骤2:检查ABI兼容性 1. **确认项目支持的ABI**:在`build.gradle`中设置: ```gradle android { defaultConfig { ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' // 根据实际编译的ABI添加 } } } ``` 2. **核对jniLibs目录结构**:确保`.so`文件放在正确的ABI子目录下: ``` app/ src/ main/ jniLibs/ ├── armeabi-v7a/ │ └── libpjsua2.so └── arm64-v8a/ └── libpjsua2.so ``` #### 步骤3:验证SWIG封装代码完整性 重新生成Java封装层(使用SWIG 4.0+)并检查是否有`swig_module_init`方法: 1. 进入PJSIP源码目录: ```bash cd pjsip-apps/src/swig make clean && make ``` 2. 检查生成的`pjsua2_wrap.cpp`中是否包含以下初始化函数(关键符号): ```cpp SWIGEXPORT void JNICALL Java_org_pjsip_pjsua2_pjsua2JNI_swig_1module_1init(JNIEnv *jenv, jclass jcls) { // ... 初始化代码 } ``` 3. 对比生成的Java类`pjsua2JNI.java`,确认存在对应的native声明: ```java public final static native void swig_module_init(); ``` #### 步骤4:处理ProGuard混淆(如果启用) 在`proguard-rules.pro`中添加保留规则: ```proguard -keep class org.pjsip.pjsua2.** { *; } ``` #### 步骤5:检查多线程初始化冲突 确保PJSIP的初始化(`libCreate()`和`libInit()`)在单一线程中完成,避免并发调用导致库加载状态异常。 ### 错误示例修正 若错误日志中明确提示缺失`swig_module_init`,则需要在加载库后立即调用它(通常在静态块中): ```java static { System.loadLibrary("pjsua2"); // 显式初始化SWIG模块 org.pjsip.pjsua2.pjsua2JNI.swig_module_init(); } ``` ### 调试技巧 - **使用`nm`工具检查符号**:验证`.so`文件中是否存在目标函数: ```bash arm-linux-androideabi-nm -gDC libpjsua2.so | grep swig_module_init ``` 输出应包含:`T Java_org_pjsip_pjsua2_pjsua2JNI_swig_1module_1init`。 ### 其他可能原因 - **NDK版本不一致**:编译库用的NDK版本与项目使用的NDK版本差异过大(建议统一用r21d)[^2]。 - **动态链接库缺失**:通过`adb shell ldd <app-path>/libpjsua2.so`检查运行时依赖(仅限调试)。 --- §§相关问题§§ 1. 如何解决Android StudioJNI方法签名不匹配的问题? 2. SWIG生成的JNI层初始化流程是怎样的? 3. 如何合并多个.so库以减少Android端的依赖问题? [^1]: PJSIP开发指南中文版详细架构说明 [^2]: NDK r15+编译问题解决方案 </think>针对 `com.zrar.pjsipdemo` 应用中出现的 **`java.lang.UnsatisfiedLinkError: No implementation found for void org.pjsip.pjsua2.pjsua2JNI.sw`** 错误,以下是完整的解决方案,结合 PJSIP 集成流程和常见问题排查: --- ### 一、错误原因分析 1. **本地库加载失败** - `.so` 文件未正确打包到 APK 或加载路径错误 - JNI 方法签名与 C++ 实现不匹配(通常由 SWIG 封装问题导致) 2. **ABI 不兼容** - 编译的 `.so` 文件 ABI(arm64-v8a/armeabi-v7a)与设备 CPU 架构不匹配 - NDK 版本不一致导致符号丢失 3. **SWIG 封装层问题** - Java 封装类与本地库的 JNI 绑定失败 - 缺少关键初始化方法(如 `swig_module_init`) --- ### 二、解决方案步骤 #### 步骤 1:检查本地库加载流程 在应用启动时显式加载库并初始化 SWIG 模块: ```java // 在 Application 或 MainActivity 的静态块中 static { System.loadLibrary("pjsua2"); // 核心库 System.loadLibrary("other_deps"); // 其他依赖库 // 显式初始化 SWIG 模块 org.pjsip.pjsua2.pjsua2JNI.swig_module_init(); // 关键修复! } ``` #### 步骤 2:验证 ABI 兼容性 1. **检查 `jniLibs` 目录结构** ``` app/src/main/jniLibs/ ├── arm64-v8a │ ├── libpjsua2.so │ └── libpj.so └── armeabi-v7a ├── libpjsua2.so └── libpj.so ``` 2. **在 `build.gradle` 中指定 ABI** ```gradle android { defaultConfig { ndk { abiFilters 'arm64-v8a', 'armeabi-v7a' // 按需添加 } } } ``` #### 步骤 3:重新生成 SWIG 封装层 1. 进入 PJSIP 源码目录: ```bash cd pjsip-apps/src/swig make clean # 使用 SWIG 4.0+ 重新生成 swig -java -package org.pjsip.pjsua2 -outdir java/pjsua2/src pjsua2.i make ``` 2. 检查生成的 Java 类 `pjsua2JNI.java` 是否包含以下关键方法: ```java public final static native void swig_module_init(); // 必须存在 ``` #### 步骤 4:验证 NDK 一致性 确保编译环境与项目配置使用 **相同 NDK 版本**(推荐 r21d): ```gradle android { ndkVersion "21.4.7075529" // 必须与编译时一致 } ``` #### 步骤 5:检查 ProGuard 规则 在 `proguard-rules.pro` 中添加保留规则: ```proguard -keep class org.pjsip.pjsua2.** { *; } -keepclasseswithmembernames class * { native <methods>; } ``` --- ### 三、调试技巧 1. **检查 `.so` 文件符号表** ```bash # 查看是否包含 swig_module_init 符号 arm-linux-androideabi-nm -gDC libpjsua2.so | grep swig_module_init ``` 正常输出应包含: `T Java_org_pjsip_pjsua2_pjsua2JNI_swig_1module_1init` 2. **运行时加载日志** 在 `adb logcat` 中过滤日志: ```bash adb logcat | grep -E "pjsua2|Linker" ``` 观察是否有 `dlopen failed` 或 `symbol not found` 错误。 --- ### 四、兼容性处理(Android 10+) 在 `AndroidManifest.xml` 中添加: ```xml <application android:extractNativeLibs="true" <!-- 关键!解决未解压 .so 问题 --> android:usesCleartextTraffic="true"> </application> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值