NDK开发系列二

来源:互联网 发布:模架编程培训要多久 编辑:程序博客网 时间:2024/06/05 22:46

上一篇讲述了如何搭建环境以及解读第一个Demo,今天这篇将讲述如何创建自己的so库,并学习JNI中,Java如何调用C代码的。

一:创建native方法,并生成头文件
1:创建Java类

package com.luosiye.jni;/** * @author LuoSiYe *         Created on 2017/12/14. *         新建一个Java类,并在方法前加上native关键词 *         这个时候会报错,没关系。 */public class JavaCallC {    /**     * 传入多个参数,返回结果,两个数相加     * */    public native int add(int arg0,int arg1);    /**     * 传入一个String类型,把C代码中的字符串进行拼接返回     * **/    public native String split(String arg0);    /**     * 给数组的每个元素都加上一个数字,     * 并将数组元素返回     * **/    public native int[] addArray(int[] arg0);    /**     * 匹配密码,返回一个boolean类型的值     * **/    public native boolean checkPwd(String pwd);}

2:生成头文件

用javah -jni 命令的方式,看下图:
这里写图片描述

上面有些报错,可以不用管它,完成之后,我们就可以看到生成的头文件了。
这里写图片描述

二:编写.cpp代码

1:在cpp文件夹下创建文件,名称任意取
这里写图片描述

比如,我创建的文件叫luosiye.cpp,直接看代码,里面有很详尽的解释

#include <jni.h>#include <string>/** * extern "C" 一定记得把这句加上,不然就会找不到本地方法 * 关于方法名怎么写,可以直接在生成的那个头文件找到对应 * 的方法,拷贝过来,然后把参数补上 * **/extern "C"JNIEXPORT jint JNICALL Java_com_luosiye_jni_JavaCallC_add(JNIEnv * env, jobject object, jint arg0, jint arg1){    /** JNI 当中,基本数据类型,是可以相互任意转化的,     *  比如,你也可以这样写,     *  int result = arg0+arg1     *  return result     *     *  虽然arg0和arg1都是jint型,但是JNI规定基本数据类型可以相互转化     * */    return arg0 + arg1;}extern "C"JNIEXPORT jstring JNICALL Java_com_luosiye_jni_JavaCallC_split(JNIEnv * env, jobject object, jstring arg0){    /**     * jstring 已经不属于基本数据类型了,所以需要先将jstring 转化成char*     * **/    const char* fromJava = env->GetStringUTFChars(arg0,0);    char* fromCplusplus = " and I am from Cplusplus";    char * result;    //该方法是C++中string类的一个方法,需加上#include<string>    sprintf(result,"%s%s",fromJava,fromCplusplus);    //最后将两个拼接后的char* 重新转化成jstring类型    return env->NewStringUTF(result);}extern "C"JNIEXPORT jintArray JNICALL Java_com_luosiye_jni_JavaCallC_addArray(JNIEnv *env , jobject object, jintArray array){    //先获取数组的长度    int size = env->GetArrayLength(array);    //获取该数组    jint* result = env->GetIntArrayElements(array,JNI_FALSE);    //上面的两个方法,都可以在jni.h文件中找到,    //对每个元素加10    for (int i = 0; i < size; ++i) {        *(result+i) += 10;    }    return array;}extern "C"JNIEXPORT jboolean JNICALL Java_com_luosiye_jni_JavaCallC_checkPwd(JNIEnv *env , jobject object, jstring pwd){    char* sPwd = "123456";    //要先将jstring类型的pwd转换成char*,    const char* uPwd = env->GetStringUTFChars(pwd,0);    //比较两个字符串,strcmp()函数来自于string类    int result = strcmp(sPwd,uPwd);    if (result ==0)        return JNI_TRUE;    else        return JNI_FALSE;}

三:编译so文件
在CMakeLists.txt文件中添加你的so库文件,需要在两个地方添加内容,看下面的图:
add_library
这里写图片描述

link_library
这里写图片描述

添加完之后,我们Rebuild一下项目,然后去build/intermediates/cmake下面看有没有生成这个so文件,比如我的:
这里写图片描述

四:在Java代码中调用native方法

如果你前面的三步都问题,也把.so文件编译出来了,那么我们可以开始在Java代码中调用了。

1:首先,我们要在调用之前加上这行代码

static {        System.loadLibrary("native-lib");        System.loadLibrary("luosiye-lib");    }

这个随便放在那,只要放在调用native方法前就行,另外,我们在build下生成的.so文件,AS通常会在前面加上一个lib,这个可以不用管,你要加载的lib名称,就是你在CMakeLists.txt配置的那个名称。

2:调用native方法

package com.luosiye.jni;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.widget.Button;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    private final static String TAG = MainActivity.class.getSimpleName();    private TextView viewOne;    private TextView viewTwo;    private TextView viewThr;    private Button clickBtn;    private JavaCallC jni;//这个就是我们写native方法的类    static {        System.loadLibrary("native-lib");        System.loadLibrary("luosiye-lib");    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        jni = new JavaCallC();        viewOne = findViewById(R.id.sample_text);        viewTwo = findViewById(R.id.main_text_two);        viewThr = findViewById(R.id.main_text_thr);        clickBtn = findViewById(R.id.main_button);        viewOne.setText(jni.add(99,1)+"");        viewTwo.setText(jni.split("I am from java"));        viewThr.setText("result == "+jni.checkPwd("123456"));        int[] array = {1,2,3,4,5};        for (int i=0;i<5;i++){            Log.d(TAG,"第"+i+"个元素的返回值是:"+jni.addArray(array)[i]);        }    }    /**     * A native method that is implemented by the 'native-lib' native library,     * which is packaged with this application.     */    public native String stringFromJNI();}

3:运行结果这里写图片描述

Log
这里写图片描述

OK,今天这篇先说这些,下一篇将和大家讲述一下如何从C去调用Java代码。

原创粉丝点击