1.简介


NDK:

  • Native Development Kit , Android的一个工具开发包,NDK是属于 Android 的,与java并无直接关系

    作用:

  • 快速开发C、 C++的动态库,并自动将.so和应用一起打包成 APK 
  • 通过 NDK在 Android中 使用 JNI与本地代码(如C、C++)交互

NDK与JNI的关系:

jni是实现最终目的 , 而 ndk 是实现 jni的功能调用。

JNI

是java native interface , java本地接口。如果java代码需要调用底层的c/c++代码,就需要通过jni来实现。android的底层是linux,linux之上是c/c++代码,而我们app是java代码。有些需要高效率的事情,比如音视频编解码,比如3d绘图等就需要用c/c++来实现了。

JNI实现步骤

  1. 在Java代码中声明Native方法(即需要调用的本地方法)
  2. 编译上述 Java源文件javac(得到 .class文件)
  3. 通过 javah 命令对.class文件导出JNI的头文件(.h文件)
  4. 使用.c文件引入.h头文件 并且实现在 Java代码中声明的Native方法 
  5. 如 Java 需要与 C++ 交互,那么就用C++实现 Java的Native方法
  6. 配置app模块的 build.gradle (ndk配置产生的.so的名字,不同的系统) 
  7. sync project
  8. 运行程序

 

2.步骤详解

以下操作都是在AndroidStudio中进行。


1.首先要准备一个ndk,不要从androidstudio里面直接下载,具体怎么下载配置看另一篇文章:

https://blog.csdn.net/qq_38261174/article/details/83210458 这里讲了如何下载及配置ndk。

然后在androidstudio中配置ndk:

2.androidstudio新建一个工程,不引入c++ Support。

我建的工程名字是 MyJniStudy

包名是 com.liuyan.myjnistudy

3.没有在androidstudio中配置ndk的先按照上面图片配置ndk。

4.在 main 目录下新建一个JNI目录。

上面图片中没有打钩的,别慌,可以在 build.gralde中配置:

apply plugin: 'com.android.application'android {    ...    defaultConfig {        ...    }    buildTypes {       ...    }//这里配置    sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jni/'] } }}dependencies {    ...}

5. 在java目录下,新建一个包

我的包名是 my

6. 在 my包下面,新建一个java文件,在java文件中写一个 native方法。

我的java文件名字是 NdkJniTest

方法名字是 mytest

package my;public class NdkJniTest {    //要先加载so库,才能调用native方法    //so库的名字(NdkJniSoName)    //下面步骤会在 build.gralde中配置so库的名字是这个    static {        System.loadLibrary("NdkJniSoName");    }    public native String mytest();}

方法名字是红色的,不要管,接下来可能方法一直是红色的,不要管,按照步骤来就行了。

7. cmd命令 进入到 my包

 执行命令 :  javac NdkJniTest.java   (编译 .java 产生 .class)

这里我产生了一个错误:

D:\androidstudio-xiangmu\MyJniStudy\app\src\main\java\my>javac NdkJniTest.java
NdkJniTest.java:7: 错误: 编码GBK的不可映射字符                                                                                                   
    //涓嬮潰姝ラ浼氬湪 build.gralde涓厤缃畇o搴撶殑鍚嶅瓧鏄繖涓?                                                                            
                                            ^
1 个错误   

我把注释全删 ,然后重新执行一次命令就好了。

这时会在my包下面多出一个文件 

8.cmd命令进入到java 目录,不进入任何包里面

执行命令   javah -jni my.NdkJniTest   ( .class产生 .h文件)

这时会在java目录下产生一个  my_NdkJniTest.h  文件。

9.将 .h 文件移动到 jni文件夹下面。

.h 文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class my_NdkJniTest */#ifndef _Included_my_NdkJniTest#define _Included_my_NdkJniTest#ifdef __cplusplusextern "C" {#endif/* * Class:     my_NdkJniTest * Method:    mytest * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_my_NdkJniTest_mytest  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

10.在 jni 文件夹下面新建一个 . C 文件 ,不是 .cpp文件

名字自己取。

我的 c文件名字是 jnitest.c

创建好 .c文件之后,编写这个 .c文件。

.c文件 要引入之前的 .h头文件,并实现头文件其中的方法。

我的 .c文件其中的代码:

#include "my_NdkJniTest.h"JNIEXPORT jstring JNICALL Java_my_NdkJniTest_mytest        (JNIEnv *env, jobject obj) {    return (*env)->NewStringUTF(env, "This is my Jni test!!!");}

11.到这一步,库文件和 jni接口文件都已经在上面全部准备好了

接下来

配置 gradle.properties 文件,在末尾加入:

android.useDeprecatedNdk=true

配置ndk  修改app模块的 build.gradle文件,如下:

apply plugin: 'com.android.application'android {    ...    defaultConfig {        ...        ndk {            moduleName "NdkJniSoName"         //生成的so名字            abiFilters "armeabi", "armeabi-v7a", "x86"//输出指定三种abi体系结构下的so库。        }    }    buildTypes {        ...    }    sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jni/'] } }}dependencies {    ...}

12.所有准备工作都做好了

sync project

13.开始使用

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        NdkJniTest ndkJniTest = new NdkJniTest();        String s = ndkJniTest.mytest(); //native方法        Log.i("TAG",s);    }}

14.结果,打印如下:

15.是不是还有一个疑惑?

我们产生的.so库在哪儿呢?自动生成的哦!!!

想要了解更多的,可以自己研究下 Android.mk文件,其实就是我们在 build.gradle 中配置的 ndk

 

3. 过瘾


按照上面的流程,相信你已经成功了!

是不是还不过瘾?好,我们接着来

我们在 NdkJniTest.java 中,再加入一个 native 方法。

package my;public class NdkJniTest {    static {        System.loadLibrary("NdkJniSoName");    }    public native String mytest();    //新加入的方法    public native int AddAB(int a , int b);}

这个native方法将要 实现两数之和 ,并将这个和返回。

重新 生成 .class 文件,重新生成 .h文件。

如果你不想要重新生成,你可以自己直接修改 .h文件,在其中加入:

JNIEXPORT jint JNICALL Java_my_NdkJniTest_AddAB   (JNIEnv *, jobject, jint, jint);

如果你的包名和我的不一样,自己根据情况修改上面的代码内容。

所以现在的.h文件所有内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class my_NdkJniTest */#ifndef _Included_my_NdkJniTest#define _Included_my_NdkJniTest#ifdef __cplusplusextern "C" {#endif/* * Class:     my_NdkJniTest * Method:    mytest * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_my_NdkJniTest_mytest  (JNIEnv *, jobject);JNIEXPORT jint JNICALL Java_my_NdkJniTest_AddAB   (JNIEnv *, jobject, jint, jint);#ifdef __cplusplus}#endif#endif

编写 .c文件,一定要引入 .h头文件。

之前我们实现了头文件的方法,新加入的方法还没有实现,所以我们要去实现新加入的方法。

所以.c文件所有内容如下:

#include "my_NdkJniTest.h"JNIEXPORT jstring JNICALL Java_my_NdkJniTest_mytest        (JNIEnv *env, jobject obj) {    return (*env)->NewStringUTF(env, "This is my Jni test!!!");}//实现新的方法JNIEXPORT jint JNICALL Java_my_NdkJniTest_AddAB        (JNIEnv *env, jobject obj, jint a, jint b) {    return (a+b);}

sync project

开始使用新方法,并查看结果:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        NdkJniTest ndkJniTest = new NdkJniTest();        String s = ndkJniTest.mytest(); //native方法        Log.i("TAG",s);                //测试新方法        int result = ndkJniTest.AddAB(2018,10);        Log.i("TAG",""+result);            }}

 

到此为止了!!!

 

 

 

 

更多相关文章

  1. Android(安卓)View 绘制刷新流程分析
  2. Android(安卓)使用Scroller实现绚丽的ListView左右滑动删除Item
  3. Android学习中遇到的优秀文章的总结(持续更新)
  4. Android(安卓)项目组件化之创建module,生成aar,引入aar
  5. 【Android】AsyncTask源码分析
  6. Android(安卓)Webview组件使用总结
  7. Android之预览PDF文件
  8. Android(安卓)studio如何指定使用自己生成的keystore调试
  9. Android(安卓)中解决Viewpage调用notifyDataSetChanged()时界面

随机推荐

  1. Ten Tips for Android Application Devel
  2. Develop Android on archlinux 64
  3. Android ShutdownThread.java源码分析
  4. Custom Android Window Title
  5. 高通 rom 分区表
  6. Android之模仿微信登陆界面(二)
  7. Android 高仿QQ 登陆界面
  8. Android Shareperferences使用
  9. Android 坐标系统
  10. Android两种 旋转Bitmap方法