一、整体步骤
- 定义被native修饰的字段或方法
- 执行java -jni命令,生成被native修饰方法的jni接口,生成.h头文件
- .h中的文件复制到.c文件中,补充完整参数和方法体
- 配置Application.mk和Android.mk文件
- 执行ndk-build命令,生成2个so文件
- 回到java层,加载so
- 加载后保存,运行
二、普通方法
1. 创建一个新的项目,名字为 JNIstudy
然后,
2. 在 MainActivity.java 文件中创建一个native方法;
3. 在 Oncreate中,用 Toast 弹窗进行提示。
4. 保存,然后打开cmd,cd到所在src文件的路径下面,然后在选所在的盘,进入src目录
5. 输入 javah,可以查看常用的命令
6. 生成 JNI 样式的标头文件
先把之前输入的代码稍微进行下调整,然后在生成JNI时看看到底是哪个生成的。更改后的代码如下:
package com.example.jnistudy;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, Getstring(), 1);
}
public native String Getstring();
public String Getstring1(){
return null;
};
}
在cmd中输入:
D:\Android\Java\adt-bundle-windows-x86_64_20140101\eclipse\myprojects\JNIstudy\src>javah -jni com.example.jnistudy.MainActivity
点击回车:
7. 回到Eclipse,刷新src包,可以发现已经生成了.h头文件
可以看出来,只有被native修饰的方法在.h头文件中
8. 在JNIstudy项目下新建文件夹jni,将.h头文件拖到jni文件夹中,并改名为JNIstudy.h
有了.h头文件,我们还需要.c文件。接下来创建.c文件。
9. 在jni文件夹下新建JNIstudy.c文件,注意文件名需要和.h头文件一样
10. 在.c文件中输入相关代码
此处,如果我们想给这个函数一个返回值,是不能直接return xxx的,需要使用c语言的方法。相关的方法可以参考原版jni.h
文件。
11. 在原版jni.h文件中搜索newstringutf,找到下图显示的函数,赋值粘贴到.c文件中
12. 对方法进行修改,补充接收的变量str,然后填入指针*env,并用箭头指向后面的方法
然后,我们看这个方法的参数,第一个是类型为JNIEnv*
的变量, 第二个是类型为const char*
的变量。
13.最后补充一个返回值str。所有的代码如下:
#include<JNIstudy.h>
JNIEXPORT jstring JNICALL Java_com_example_jnistudy_MainActivity_Getstring
(JNIEnv *env, jobject obj){
jstring str = (*env)->NewStringUTF(env, "Hello NDK");
return str;
}
除了.c和.h文件以外,我们还需要2个配置文件:Android.mk 和 Application.mk
14. 新建两个.mk配置文件
选中“jni”目录右键依次选择New=>File,点击该选项弹出弹窗,输入 “Android.mk”,此名称不可更改,最后点击“Finish”完成 “Android.mk”文件的创建。Android.mk中填入的代码如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JNIstudy
LOCAL_SRC_FILES:= JNIstudy.c
LOCAL_ARM_MODE := arm
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
解释内容如下:
15. 同理创建Application.mk文件
输入代码:
APP_ABI :=x86 armeabi-v7a
16. 返回到jni目录下,使用ndk-build命令
出现so库,则表示成功了。
- 刷新项目,在libs文件夹下可以看到生成的so库
18. 加载so库
返回.java文件,填写代码
最后,运行程序
三、静态方法
1. 前1-10步参考普通方法,此处不再重复
2. 在java.h头文件中搜索GetobjectField
,找到合适的方法,复制到.c文件中。注意文件中有C和C++两种语言
3. 补全参数。我们发现此时的方法中有一个参数名字为jFieldID
,我们返回java.h文件中找。注意删除多余的括号,图中未删除
注意,变量前面加下划线。普通方法中的都没加,静态中的加了。
此处忍不住吐槽下ZD老师,太不细心,实战过程中总是需要学生帮忙找错……普通方法和静态方法都写完了,才发现变量前面没有加下划线……这里懒得重新截图了,操作到这里的时候注意自己改。
4. 找到这个方法,复制到.c文件中
5. 补全参数。第一个const char*
使用MainActivity.java中定义的字段,第二个使用smali中string的写法
6. 这时,我们可以看到,还有一个参数jclass
参数,需要再次返回java.h文件中找,搜索findclass
,然后复制到.c文件中补全参数。第二个参数const char使用的是类的路径。注意需要把类路径中的点换成斜杠
7. 补充return str,调用java层普通字段最后完成的代码如下
三、静态方法
1. 静态方法和普通方法套路类似,在java.h文件中搜索GetstaticFIeld
,找到对应的方法,复制到.c文件中并补齐
此时,我们发现,除了env之外,还有两个参数,分别为jclass
和jfieldID
。
2. 将普通字段中的jclass
方法直接复制下来
此时,另外一个参数,由于是静态的,需要重新到java.h文件中去找。
正好就在刚才所搜内容的上面。将其复制粘贴到.c文件中。
3. 最终的代码如下
4. 在cmd中,首先cd到jni路径下,然后执行ndk-build命令
5. 最后运行程序即可