android JNI的调用

突然写博客的初衷

以前从来也没有写博客的习惯,不过最近面试中,面试官问有没有写过什么博客啊,有没有博客的地址啊,我蒙蔽了,半开玩笑的说:“正准备写…”匆忙岔开话题。
正好也临近年关,忙了一年了,回去也好好过个年,顺便整理一下自己的知识点,用博客的方式记录下来,方便自己查阅,顺便吐槽一下百度云,坑爹的公司出的坑爹的产品,我的项目都在上面,现在拿下来都很艰难。

今天写一下android JNI的调用,写一个最简单的计算器,只有两个数字的加减乘除,逻辑运算用C来实现。

这里写图片描述

JNI的调用逻辑共以下几步

1、创建一个java类,加载一个动态库,编写一个需要的native方法。
2、编译上面的java类,生成一个class字节码文件。
3、根据上面的字节码文件生成一个后缀为 .h 开头的h文件。
4、创建一个后缀为 .c 的文件,将.h文件的代码copy进入,重新编写实现代码.
5、配置jni运行环境
6、rebuild project 一下,会在app > build文件夹下生成需要的.so文件,这就是你需要的文件,上面的.class .h .c 都可以删除了,只要这些so文件copy到jni文件夹中就可以使用了,下面详细讲解,同时加深自己的印象并且和大家共勉。

1、创建一个java类,加载一个动态库,编写一个需要的native方法。

public class MyJNI {
    static {
        System.loadLibrary("Ccalculate");
    }
    public static native int add(int i ,int j);
    public static native int subtract(int i ,int j);
    public static native int multiply(int i ,int j);
    public static native int divide(int i ,int j);
}

里面的静态代码块中的“Ccalculate” 是自定义的命名,下面是运算的几个方法,这几个方法在java文件中声明,用C去实现,这时定义的几个native方法都处在报错状态,没关系,不用处理。

2、编译上面的java类,生成一个class字节码文件。

使用cmd或者使用alt+f12快捷键调用控制台,生成对应的.class文件,我这里是MyJNI.class,第一步完成,如果没完成,请去补课。

这里写图片描述

3、根据上面的字节码文件生成一个后缀为 .h 开头的h文件。

找到自己的class文件,用java提供的工具 javah来生成一个.h文件,代码为 javah -jni MyJNI ,这句话的意思就是用javah找到刚刚编写的字节码文件MyJNI.class 文件,生成一个.h的文件
我的编译代码是javah -jni com.org.zl.testjni.JNI.MyJNI生成一个.h的文件
这里写图片描述

打来.h文件,查看里面的代码

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_org_zl_testjni_JNI_MyJNI */

#ifndef _Included_com_org_zl_testjni_JNI_MyJNI
#define _Included_com_org_zl_testjni_JNI_MyJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL 
/*
其实我也看不懂,不过没关系,这个方法后面有个add,是我在java中定义的一个方法,这个我看懂了,后来问做C开发的朋友,他们说不知道这个什么鬼,只好我就自己想办法,详情请看  JNIEnv解析 
 */
Java_com_org_zl_testjni_JNI_MyJNI_add
  (JNIEnv *, jclass, jint, jint);

/*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    subtract
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_org_zl_testjni_JNI_MyJNI_subtract
  (JNIEnv *, jclass, jint, jint);

/*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    multiply
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_org_zl_testjni_JNI_MyJNI_multiply
  (JNIEnv *, jclass, jint, jint);

/*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    divide
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_org_zl_testjni_JNI_MyJNI_divide
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

这时.h文件就OK了,下一步COPY,实现它,.h也在报错,没干系,不要管他,因为我们用它过度的,最后需要的是SO文件,所以到最后删掉都没事

4、创建一个后缀为 .c 的文件,将.h文件的代码copy进入,重新编写实现代码(包括修改比较).

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_org_zl_testjni_JNI_MyJNI */

#ifndef _Included_com_org_zl_testjni_JNI_MyJNI
#define _Included_com_org_zl_testjni_JNI_MyJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL 


//这里是.h文件的代码的add方法,
Java_com_org_zl_testjni_JNI_MyJNI_add
  (JNIEnv *, jclass, jint, jint);

//这里是修改过后的实现方法
Java_com_org_zl_testjni_JNI_MyJNI_add     
  **(JNIEnv *en, jclass obj, jint i, jint j){//这里修改过(添加了变量,和大括号)
        return i+j;//这里也是,其他很像**
}
/
*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    subtract
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_org_zl_testjni_JNI_MyJNI_subtract
  (JNIEnv *en, jclass obj, jint i, jint j) {
    return i-j;
}

/*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    multiply
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_org_zl_testjni_JNI_MyJNI_multiply
(JNIEnv *en, jclass obj, jint i, jint j){
    return i*j;

}
/*
 * Class:     com_org_zl_testjni_JNI_MyJNI
 * Method:    divide
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_org_zl_testjni_JNI_MyJNI_divide
(JNIEnv *en, jclass obj, jint i, jint j){
    return i/j;
}

#ifdef __cplusplus
}
#endif
#endif

5、配置jni运行环境

1、app下的build.gradle需要添加一句代码
(这个名字和上面的静态代码块中的一样,用到名字的就这两个地方,保证一样就可以了)

System.loadLibrary("Ccalculate"); 和下面的名字一样,记得ndk{}应该写在defaultConfig {}里面,不然会报错

报错信息是

Error:(15, 1) A problem occurred evaluating project ':app'.
> Could not find method ndk() for arguments [build_2y5lwsos45iu20kkou5i1vyei$_run_closure1$_closure4@5363efbc] on project ':app' of type org.gradle.api.Project.

2、gradle.properties
android.useDeprecatedNdk=true

这里写图片描述

3、local.properties

因为我的NDK是用android studio自己下载的,所以我直接去sdk文件夹中找ndk了,如果你是自己下载的NDK,那么这里填写你自己的ndk路径

ndk.dir=D\:\\Android\\SDK\\ndk-bundle

这里写图片描述

6、重建项目,获取新生成的so文件

刚开始是没有ndk文件夹的,重建完后即可,将so文件夹放入jni中,需要的文件已经创建出来了,将.class .h .c 删除,即可。

这里写图片描述

7、拷贝进jni文件夹中.运行android项目

这里写图片描述

8、项目地址

https://github.com/hahhahahahah/JNIDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值