### jni开发中的常见错误
#### 错误一 :java.lang.UnsatisfiedLinkError: Native method not found:(本地方法没有找到原因)
- java.lang.UnsatisfiedLinkError: Native method not found:
- 1. 本地函数名写错,如果本地方法名中有下划线“_”,则声明时,.c文件中在最后一个下划线后面加1,如以下代码所示
如果不加1会出现以下错误
```
07-20 23:00:15.542: E/AndroidRuntime(1307): Caused by: java.lang.UnsatisfiedLinkError: Native method not found: com.wsc.jnihelloworld.MainActivity.hello_FromC:()Ljava/lang/String;
```
![](http://i.imgur.com/Q1w9GRH.png)
如果后面加1,如下图所示
MainActivity.class中修改如下
![](http://i.imgur.com/H0oZAG5.png)
hello.c中修改如下
![](http://i.imgur.com/MXgicX1.png)
再重新编译生成.so文件,运行到模拟器上,正常运行
**虐心2**
如果遇到这种情况,方法名命名及其脑残如下图所示:
![](http://i.imgur.com/ee36h88.png)
这时,人工修改本地函数名,很麻烦,这时可以使用javah -jni命令,生成头文件
如果是jdk1.7版本则来到项目的src目录下运行javah命令,如果是jdk1.6版本,则到项目的bin目录下的class目录下运行javah命令
![](http://i.imgur.com/Jpko7XP.png)
尽管报了GBK错误,但是那是编码格式的问题,不影响
本地方法声明在哪一个类中,就把这个类的全类名拿来,复制粘贴到DOS中 javah 后面,在项目文件鼠标移动到该处,按住F5刷新一下,就会出现头文件,打开可以看到
![](http://i.imgur.com/rqImKmB.png)
打开头文件可以看到javah命令生成的头文件
![](http://i.imgur.com/QsDSTJj.png)
这样就可以直接拿到本地函数名,不用人工修改本地函数名
- 2.忘记加载.so文件,没有调用System.loadlibrary()
- System.loadlibrary()一般并不是调用它的时候才加载这个函数,可以在MainActivity中写一个静态代码块,MainActivity实例已创建,就加载.so文件
####错误二 : findLibrary returned null ####
- findLibrary returned null
- 1.加载动态链接库时,动态链接库名字写错
System.loadLibrary("libhello");//动态链接库名字错了
报错如下
07-21 04:59:47.232: E/AndroidRuntime(1475): java.lang.UnsatisfiedLinkError: Couldn't load libhello from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.wsc.jnihelloworld-2.apk"],nativeLibraryDirectories=[/data/app-lib/com.wsc.jnihelloworld-2, /system/lib]]]: findLibrary returned null
- 2.平台类型错误,把只支持arm平台的.so文件部署到了x86CPU的设备上
报错如下
07-21 09:08:13.872: E/AndroidRuntime(1917): Caused by: java.lang.UnsatisfiedLinkError: Couldn't load hello from loader dalvik.system.PathClassLoader[dexPath=/data/app/com.wsc.jnihelloworld-1.apk,libraryPath=/data/app-lib/com.wsc.jnihelloworld-1]: findLibrary returned null
Application.mk 中有这样一段话
By default, the NDK build system will generate machine code for the 'armeabi' ABI. This corresponds to an ARMv5TE based CPU with software floating point operations. You can use APP_ABI to select a different ABI.
默认情况下,NDK 生成系统将生成 'armeabi' ABI 的机器代码。这对应于 ARMv5TE 基于 CPU 浮点运算的软件。您可以使用 APP_ABI 来选择不同的 ABI。
没有指定APP_ABI,则它只去编译支持armeabi这种CPU的机器代码,想支持其他平台,就要添加APP_ABI指定想要支持的平台,支持多个平台时,用空格隔开,比如:
APP_ABI := armeabi x86
**注意:genymotion模拟器应该都是支持x86CPU平台,所以APP安装到这些模拟器,应该注意指定APP_ABI**
重新ndk-build生成x86平台下的.so文件如图,然后运行到x86模拟器
![](http://i.imgur.com/BRSSsFj.png)
### cpu平台 ###
* arm :指令集,精简指令集,简单的事情,效率特别高,
* 优点:移动平台,执行简单的指令操作,效率高,资源消耗低,功耗低。
* 缺点:复杂逻辑的时候,就有缺陷。
* 发展:arm平台的服务器
* x86:复杂指令集,SSE,SSE3
* 优点:执行复杂业务逻辑的时候,性能非常强大,这种性能远超arm平台
* 缺点:耗电,功耗高。
* 发展:x86 平台手机cpu,x86:联想的k900,拉拢一些山寨厂商使用x86 cpu
* mips:cpu 类型
* 龙芯:用mips
* sigma:机顶盒
### javah ###
- jdk 1.7项目 src目录下运行 javah
- jdk 1.6项目 bin目录下classes文件夹
- javah native方法声明的java类的全类名
从上图可以看到在ndk-build时,出现一个warning,说APP_PLATFORM ,Android-19比最小版本14大,解决这个warning可以在Application.mk中添加
APP_PLATFORM := android-14
![](http://i.imgur.com/eder0Dh.png)
可以看到,不再报这个warning
####错误三: 使用javah生成头文件报找不到类文件 ####
很有可能是由你的JDK环境变量配置出错,记住CLASSPATH这个系统变量,前面应该加上“.;”,如图所示
![](http://i.imgur.com/X3oPrFk.png)
- 前言
- JNI基础知识
- C语言知识点总结
- ①基本语法
- ②数据类型
- 枚举类型
- 自定义类型(类型定义)
- ③格式化输入输出
- printf函数
- scanf函数
- 编程规范
- ④变量和常量
- 局部变量和外部变量
- ⑤类型转换
- ⑥运算符
- ⑦结构语句
- 1、分支结构(选择语句)
- 2、循环结构
- 退出循环
- break语句
- continue语句
- goto语句
- ⑧函数
- 函数的定义和调用
- 参数
- 函数的返回值
- 递归函数
- 零起点学通C语言摘要
- 内部函数和外部函数
- 变量存储类别
- ⑨数组
- 指针
- 结构体
- 联合体(共用体)
- 预处理器
- 预处理器的工作原理
- 预处理指令
- 宏定义
- 简单的宏
- 带参数的宏
- 预定义宏
- 文件包含
- 条件编译
- 内存中的数据
- C语言读文件和写文件
- JNI知识点总结
- 前情回顾
- JNI规范
- jni开发
- jni开发中常见的错误
- JNI实战演练
- C++(CPP)在Android开发中的应用
- 掘金网友总结的音视频开发知识
- 音视频学习一、C 语言入门
- 1.程序结构
- 2. 基本语法
- 3. 数据类型
- 4. 变量
- 5. 常量
- 6. 存储类型关键字
- 7. 运算符
- 8. 判断
- 9. 循环
- 10. 函数
- 11. 作用域规则
- 12. 数组
- 13. 枚举
- 14. 指针
- 15. 函数指针与回调函数
- 16. 字符串
- 17. 结构体
- 18. 共用体
- 19. typedef
- 20. 输入 & 输出
- 21.文件读写
- 22. 预处理器
- 23.头文件
- 24. 强制类型转换
- 25. 错误处理
- 26. 递归
- 27. 可变参数
- 28. 内存管理
- 29. 命令行参数
- 总结
- 音视频学习二 、C++ 语言入门
- 1. 基本语法
- 2. C++ 关键字
- 3. 数据类型
- 4. 变量类型
- 5. 变量作用域
- 6. 常量
- 7. 修饰符类型
- 8. 存储类
- 9. 运算符
- 10. 循环
- 11. 判断
- 12. 函数
- 13. 数学运算
- 14. 数组
- 15. 字符串
- 16. 指针
- 17. 引用
- 18. 日期 & 时间
- 19. 输入输出
- 20. 数据结构
- 21. 类 & 对象
- 22. 继承
- 23. 重载运算符和重载函数
- 24. 多态
- 25. 数据封装
- 26. 接口(抽象类)
- 27. 文件和流
- 28. 异常处理
- 29. 动态内存
- 30. 命名空间
- 31. 预处理器
- 32. 多线程
- 总结
- 音视频学习 (三) JNI 从入门到掌握
- 音视频学习 (四) 交叉编译动态库、静态库的入门学习
- 音视频学习 (五) Shell 脚本入门
- 音视频学习 (六) 一键编译 32/64 位 FFmpeg 4.2.2
- 音视频学习 (七) 掌握音频基础知识并使用 AudioTrack、OpenSL ES 渲染 PCM 数据
- 音视频学习 (八) 掌握视频基础知识并使用 OpenGL ES 2.0 渲染 YUV 数据
- 音视频学习 (九) 从 0 ~ 1 开发一款 Android 端播放器(支持多协议网络拉流/本地文件)
- 音视频学习 (十) 基于 Nginx 搭建(rtmp、http)直播服务器
- 音视频学习 (十一) Android 端实现 rtmp 推流
- 音视频学习 (十二) 基于 FFmpeg + OpenSLES 实现音频万能播放器
- 音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源)