环境准备:
建立JNI项目:
上图中的Toolchain工具集就是由NDK包提供的一部分类,所以NDK是必须要安装的。
默认即可。如果上面的环境准备没有做的话,直接新建jni项目也是会有Gradle提示你安装的。
生成目录如下:
大致分析demo:
MainActivity做的第一件事:将要用的c++库先导入进来,这样我们才能调用这个库里面的c++方法.如果这个库不在内存中, 我们是没法调用的。
有了库之后。它调了一个方法:
来,我们瞅瞅这函数和我们android开发中常写的函数有何不同:
哦~~一般的函数没有native字样。为了调c/c++相关的方法的时候要标识native。也就是说,这个方法是由C/C++提供的,即这是一个本地方法,要加上一个标识。这样Java/kotlin就能知道要到系统的库里
System.loadLibrary("native-lib");
提供的这个库里去找相应的方法。
第二个不同的是:
因为现在最新的版本用的CMake进行编译.
以前这个不叫cpp目录,叫jni,现在新版androidstudio改成了cpp
关于CMakeLists.txt是CMake的东西,可以参考这篇老哥的文章:https://www.cnblogs.com/sddai/p/10328977.html
文末写了关于CMakeLists文件内容的分析。
然后看看native-lib.cpp:[典型的c++文件]
规律:包名_类名_方法名
这个名字可以自己创建,也可以通过javah工具产生。如果你对名字特别熟悉也可以自己写。
这样的一个命名规则 ,Java虚拟机就可以找到这个cpp方法.也就是说刚刚在mainactivity中的native函数
stringFromJNI. 它属于Java包下的。
通过这样去查找就可以在java虚拟机里去找到对应的c方法。。
再看这个c方法:“
这个方法并没有做什么事,就是生成了一个字符串。然后把这个字符串返回回去。
拿到这个方法过后,就把这个字符串从c层转化到了java层.然后java层拿到这个方法后就得到了字符串,然后设置给了TextView了。
所以,等会运行的时候,我们应该是能看到app启动后显示Hello from C++
来,让我们运行验证下我们的猜想:
使用JNI的时候总结:
- loadLibrary
- 实现相应的c层方法
- CMake,产生编译脚本。【CMakeLists.txt就可以产生编译脚本】
CMakeLists.txt是啥?
通过这个CMakeLists.txt就可以产生编译脚本。
CMakeLists实际上是给CMake使用的.CMake会通过CMakeLists去产生我们想要的编译脚本.在CMakeLists里有几个指令。
先看这个指令:
这个指令叫add_library,这指令的作用有2方面的作用,第一方面可以根据我们的c文件产生一个动态库,其中产生的是动态库还是静态库由第二个属性决定,即我们这里看到的SHARED。我们的库的名字叫做native-lib,它是一个动态库SHARED,如果是静态库就是STATIC.
这个动态库是由native-lib.cpp产生的。【其实CMakeLists.txt文件里面的英文注释已经写的很清楚了。】
即这个指令就是产生一个动态库。
如果您的库还需要依赖于其他的库,那么就看看这个指令:
通过这个指令去查找系统的库,那么这个系统的库必须是在CMake指定的路径下,像这里的log就在系统的库下。并起了个名字log-lib。
再看下一个指令:
通过这个名字就知道是链接的意思。即之前addlibrary指令找到的库和find_library指令找到的log库,将这2个库链接到一起最终形成一个库。怎么链接——通过target_link_libraries指令。将谁链接起来了,就是将上图中看到的native-lib和log-lib把这2个库链接到一起。
如果这里我有第3 个库,要将第3个库链接,就直接在后面加上xxx
还有一个额外问题:如果我们想要添加一个库,这个库并不在系统的CMake能找到的默认路径下,这怎么办才能引入呢?
add_library。给库起名字,指定共享库还是静态库, import在别的地方已经编译好的这个库引入。
编译FFmpeg好的库也是通过这个指令从外部引入进来的。
学习JNI的基础知识路线:
学习jni、FFmpeg等需要先掌握JNI的基础知识,
- JNI_C 语言基本类型
- 输出函数
- 输入函数
- 指针【认识与深入理解】
- 在单独方法中互换地址
- 函数返回一个以上的值
- 多级指针
- 数据
- 输入数组
- 数组的取值运算
- 静态内存分配
- 动态内存分配
- 动态创建数组
- 函数指针
- 联合体
- 枚举
- 结构体
- 结构体指针
- Java调用C代码执行运算
- c调用Java方法返回值
- 让c的输出能显示在Logcat中
- c调用java方法(String参数)
- c调用java(回调静态方法)
。。。。。。