Android JNI与NDK学习(二)


实战演练 

      在我们实战JNI与NDK时,有两种方式在编译.so文件
      (1)一种是编译生成 .h头文件 编写C/C++文件、Android.mk文件 使用ndk命令来编译生成 .so文件
      (2)一种是使用AS下CMake编程自动生成 .so文件(这种比较方便)

      我们重点讲一下第一种 来共同的学习一下从JNI到NDK的过程

一、NDK编译 .so

(1)第一步我们新建一个项目 新建一个JniUtils类在JniUtils里面写native函数,写完函数重新build一下或者运行一下都ok

编写native函数

(2)将我们的工程目录从Android目录下切换到project目录下
在app的build/intermediates目录下有个classes有编译生成的class文件
(app-->build-->intermediates-->clsasses-->debug-->我们的包名-->JniUtils.class)
使用Terminal 命令工具 进入debug目录下 使用命令javah -jni com.hyperx.jnitestdemo.JniUtils 

编译生成的class文件

我们看到在debug目录下会生成com_hyperx_jnitestdemo_JniUtils.h头文件  这个名字比较长 可以改个短一点的

编译 .h 头文件

(3)在app的main目录下我们新建一个jni文件夹,将刚才的 .h头文件复制过来 接着要在jni目录下新建一个c或者c++文件 都可以
          ps.这里要注意一下:c/c++文件中要include我们刚才生成的 .h 头文件

jni.c文件

(4)接下来就是Android.mk文件  这里注意一下  命名一定要规范
LOCAL_MODULE:    指向的是你将要打包好的.so库的名字
LOCAL_SRC_FILES:指向的是你写好的C文件(我这里应该是jni.c文件)这个C文件你可以理解为是一个目录

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS :=-llog

LOCAL_MODULE := test

LOCAL_SRC_FILES := jni.c

include $(BUILD_SHARED_LIBRARY)

(5)还有一个就是Application.mk文件  这里可以指定你要打包so文件所对应的的平台,因为我这里只使用armeabi-v7a  所以只输出了一种
输出全部 改成 all 即可

APP_ABI := all

Application.mk

(6)接下来就是ndk编译打包.so文件了
         我们还是使用窗口命令进入main目录下的jni文件下使用 ndk-build命令即可
         ps: 1. 需要进入jni目录下使用ndk命令 
               2.我这里只输出了armeabi-v7a架构的so文件  大家在Application.mk文件中改成all 重新编译即可生成各个架构的.so文件
               3.这里有个警告————> ndk编译支持Android的最小版本是16 大家记得改一下

ndk-build

(7)大家重新切换到project视图下的main目录,我们可以看到多出来两个文件夹  (libs,obj),点开看一下  libs目录下已经有我们打包好的.so库了,我们把libs下对应架构目录的so拷贝出来就可以使用了,到此我们的ndk工作已经完成。(这两个文件夹都是编译产生的,拷贝完后 都可以删除  对项目没有影响 )

libs,obj

(8)关于jni的与java的调用以及return
          我们在main目录下新建一个jniLibs目录 将我们刚才打包好的armeabi-v7a版本的so库拷贝过去
          ps:在build.gradle中我们要指定一下需要使用的cpu架构

build.gradle

这里我要load一下so库   这里的 "test" 就是我们在Android.mk中指定的so的名字 

JniUtils

做一下小测验 给TextView重新复制

MainActivity

这里我们可能会报错

error

这个问题主要是因为Android studio以前使用ndkCompile后来废弃掉了,Android-Terminal-Emulator没有最近没有更新的缘故。
解决:在build.gradle中的buildTypes加如下几行代码  重新sync一下

sourceSets {
       main {
              jni.srcDirs = []
        }
}

解决


运行结果如下:

success.jpg

二、Android studio 之CMake编程

在我们使用cmake编译 .so 库时我们需要简单配置一下cmake环境
打开AS的SDK manager ——sdk tools 选中对应版本的cmake(注意这里没有cmake选项的同学,要选择AS的64位重新启动)

cmake

在cmake 下载完 同步以后我们就可以新建项目了
 之前我们在使用AS创建项目的时候一直没用过下面两个勾选项,也没做过深入了解 现在知道了 是用于Android开发NDK项目使用的

ndk

在向导的Customize C++ Support部分,您可以使用下列选项自定义项目:
C++ Standard:使用下拉列表选择您希望使用哪种 C++ 标准。选择Toolchain Default会使用默认的 CMake 设置。
Exceptions Support:如果您希望启用对 C++ 异常处理的支持,请选中此复选框。如果启用此复选框,Android Studio 会将 -fexceptions 标志添加到模块级 build.gradle文件的 cppFlags中,Gradle 会将其传递到 CMake。
Runtime Type Information Support:如果您希望支持 RTTI,请选中此复选框。如果启用此复选框,Android Studio 会将 -frtti 标志添加到模块级 build.gradle文件的 cppFlags中,Gradle 会将其传递到 CMake。

项目创建完成后我们运行一下  ,看到手机上面的文字就被修改了

我们还是切换到project视图下 可以看到cmake自动帮我们生成了.so文件
因为我这里是模拟器 所以他只生成了x86架构的so文件

cmake

CMake运转流程

1、Gradle 调用外部构建脚本CMakeLists.txt

2、CMake 按照构建脚本的命令将 C++ 源文件native-lib.cpp编译到共享的对象库中,并命名为libnative-lib.so,Gradle 随后会将其打包到APK中

3、运行时,应用的MainActivity会使用System.loadLibrary()加载原生库。应用就是可以使用库的原生函数stringFromJNI()。


至此我们jni实战Hello word 两种方式都已实现 接下来我们学习一下JNI函数与Java函数之间的相互传值 (基本数据类型,数组,结构体...)

感觉有用的同学,动动小手指给个赞,码字不易。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容