1)安装和下载Cygwin,下载 AndroidNDK
2)在ndk项目中JNI接口的设计
3)使用C/C++实现本地方法
4)JNI生成动态链接库.so文件
5)将动态链接库复制到Java工程,在java工程中调用,运行java工程即可
studio下的NDK操作流程:
NDK开发思路:1、下载NDK
2、创建一个native方法,
3、通过javah生成头文件,
4、改cpp类的代码,
5、编辑c语言 ,
6、添加application.mk文件,
7、运行
按照上述的思路开始一步一步执行
studio配置环境:
Android Studio 2.2
又重新加入了jni
的支持,并且使用的是CMake
,所以现在写jni
不需要配置mk
文件了。
eclipse找那个的 所以就不像以前那样还要安装什么cygwin。
SDK | 软件开发工具包;英语全称:Software Development Kit |
---|---|
JDK | Java语言的软件开发工具包;英语全称:Java Development Kit |
NDK | 原生软件开发工具包;英语全称:Native Development Kit;被Google称为NDK |
由此可见,其实不管什么XDK
,都可以叫SDK
,可能为了有很好的区分,便有了JDK
、NDK
,所以我们有的时候常说的SDK
并不是特指安卓开发工具包
,
而只是我们都是同行,交流的时候都知道指的是什么,其实你们会发现,我们常常接三方平台的时候,那些工具包也是叫SDK
,但可能我们在交流的时候就会加个前缀,比如:微信分享SDK、支付宝SDK、xxSDK。
NDK的下载地址:
https://developer.android.com/ndk/index.html#Revisions
如果出现如下错误: NDK integration is deprecated in the current plugin. gradle.properties中添加如下配置
使用AndroidStudio开发前我们也要做点额外工作,我们需要在项目根目录下local.properties中添加编译NDK的路径:ndk.dir=/Users/liangqi/android-ndk
//javah -d jni -classpath E:\NdkDemo\app\build\intermediates\classes\debug ndkdemo.peng.cx.com.myapplication.JNIUtils public class JNIUtils { static { System.loadLibrary("huazict"); } public native String getString(); }
输入命令:javah -d jni -classpath 自己编译后的class文件的绝对路径
.h文件生成的目录是更加你的javah指令。
javah -d jni -classpath E:\NdkTest\app\build\intermediates\classes\debug ndkdemo.peng.cx.com.myapplication.JniDemo(注意debug后的空格)
找到类所在的路径:
输入指令之后就自动生成了.h的文件.
把生成的jni目录拷贝到程序的根目录:
<五> 拷贝JNI在正确的目录下 我们在工程中创建一个文件夹jni
,此目录与工程中的java
目录同级,并把生成的*.h
文件放置到jni
文件夹中。
<六>写C语言文件
现在我们来写一个test的C文件huazict.c同.h文件一样放到jni文件夹下,代码如下:
C包含里面的头文件.h文件,就是上面生成的.h文件
#include "ndkdemo_peng_cx_com_myapplication_JNIUtils.h" JNIEXPORT jstring JNICALL Java_ndkdemo_peng_cx_com_myapplication_JNIUtils_getString (JNIEnv *env , jobject obj) { return (*env)->NewStringUTF(env, "这是我测试的jni"); }
最后在构建文件中的默认配置中加上:
ndk { moduleName "huazict" //生成的so名字 abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。 }
.so文件的区别
armeabi、armeabi-v7a和x86都表示CPU的类型。一般的手机或平板都是用arm的cpu。
不同的cpu的特性不一样,armeabi就是针对普通的或旧的
arm v5 cpu,armeabi-v7a是针对有浮点运算或高级扩展功能的arm v7 cpu。
mips、armeabi、armeabi-v7a和x86到底是什么
armeabi:默认选项,将创建以基于
ARM* v5TE 的设备为目标的库。 具有这种目标的浮点运算使用软件浮点运算。 使用此 ABI (二进制接口)
创建的二进制代码将可以在所有 ARM*设备上运行。所以armeabi通用性很强。但是速度慢
armeabi-v7a:创建支持基于 ARM* v7 的设备的库,并将使用硬件 FPU 指令。armeabi-v7a是针对有浮点运算或高级扩展功能的arm v7 cpu。
x86:支持基于硬件的浮点运算的
总结:
不同的CPU不用的芯片,armeabi是最基本的,有不同的运算指令,如浮点运算,所以需要生成不同的.so文件
如果项目只包含了 armeabi,那么在所有android设备都可以运行;如果项目只包含了 armeabi-v7a,除armeabi架构的设备外都可以运行;
如果项目只包含了 x86,那么armeabi架构和armeabi-v7a的Android设备是无法运行的;
如果同时包含了 armeabi, armeabi-v7a和x86,
所有设备都可以运行,程序在运行的时候去加载不同平台对应的so,这是较为完美的一种解决方案,同时也会导致包变大。
<七>编译生成SO库
Android Studio
的菜单build > Rebuild Project
clean 一下,然后rebuild一下,就会生成.so文件,在build/intermediates.ndk下
不是eclipse还要配置android.mk这么文件吗?android studio不用,
你还真猜对了,不过不是说不用就代表他没有,只不过这个配置过程不过你来做,你要做的就是配置上图的代码。那android.mk
<八>建立一个jniLib目录,把so库拷贝进来
运行程序,可以看到效果
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.sample_text); tv.setText(new JNIUtils().getString()); } }
总结一下流程:
编写静态方法(用java声明)-->编译生成class文件--->编译生成h文件---->编写C文件(用C/C++实现)
---->配置NDK---->配置so库---->在Activity调用(Java调用C/C++)。
自己总结的流程:
1.下载NDK
2.配置NDK
3.写JAVA类调用C
4.把JAVA生成Class
5.生成.h文件
6.写C语言
7.配置so库并编译so库
=================================================================================
知识拓展
C语言和.h文件解析
.h文件详细解析:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include/* Header for class ndkdemo_peng_cx_com_myapplication_JNIUtils */ #ifndef _Included_ndkdemo_peng_cx_com_myapplication_JNIUtils #define _Included_ndkdemo_peng_cx_com_myapplication_JNIUtils #ifdef __cplusplus extern "C" { #endif /* * Class: ndkdemo_peng_cx_com_myapplication_JNIUtils * Method: getString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_ndkdemo_peng_cx_com_myapplication_JNIUtils_getString (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
其实 ,我们不用javah
命令 , 也能写出头文件
命名都是有规律 :函数名称规则:Java_完整类名_方法名 , 包名的.号 , 以`_`表示
Java Type | Native Type | Description |
---|---|---|
boolean | jboolean | unsigned 8 bits |
byte | jbyte | signed 8 bits |
char | jchar | unsigned 16 bits |
short | jshort | signed 16 bits |
int | jint | signed 32 bits |
long | jlong | signed 64 bits |
float | jfloat | 32 bits |
double | jdouble | 64 bits |
void | void | not applicable |
java文件如何编译生成Class文件,先到了.java的目录羡慕,然后用命令 javac 类名 javac JNIUtils.java
javah -jni com.example.binbin.testjni.myJNI
生成头文件;Javah ndktest.peng.cx.com.myapplication.JNIUtils