JNI: Java Native Interface, 提供了java语言和其他语言(例如c和c++)进行相互调用的方式。
本文是用java调用c生成的so模式。其中,编译so文件过程如下:
1)打开android studio, 新建一个空的
点击next, name中输入"test",点击finish。
创建完后,切换到project模式,显示如下:
2、编写带有native声明的java类
在test->app->src->main->java->com.sf.test目录,右键新建java类,名称为"Test"
双击Test,添加如下内容:
package com.sf.test;
public class Test {
public native void displayHelloWorld();
static {
System.loadLibrary("Test");
}
}
native方法 displayHelloWorld() 为我们在java中调用的函数,需要在c语言中重写来实现。
System.loadLibrary 后面跟的是动态库的名字。
3、利用javac编译成java类
右键com.sf.test.选择”open in terminal“,可以看见android studio底部出现终端调试助手,并且已经切换到相关目录下。
执行命令, javac Test.java
生成相应的class类(Test.class)
4、利用javac生成相应的h头文件
在main目录下新建jni文件夹,保存相关c和h文件,以及编译使用的文件。
命令为:
javac Test.java -h ../../../../jni (将生成的h文件保存到jni目录下)
此时可以查看到main/jni/目录下多了一个文件: com_sf_test_Test.h,头文件中内容为自动生成:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_sf_test_Test */
#ifndef _Included_com_sf_test_Test
#define _Included_com_sf_test_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_sf_test_Test
* Method: displayHelloWorld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_sf_test_Test_displayHelloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
其中JNIEXPORT void JNICALL Java_com_sf_test_Test_displayHelloWorld
(JNIEnv *, jobject);为从java转换到c后的调用函数,对应Test.java中的 displayHelloWorld。
5、编写c语言的本地实现
在jni目录下添加test.c文件,其中内容为:
#include "jni.h"
#include "com_sf_test_Test.h"
JNIEXPORT void JNICALL Java_com_sf_test_Test_displayHelloWorld
(JNIEnv *jv, jobject jo)
{
printf("Hello world\n");
return ;
}
两个头文件必须包含,下面函数的名称参数跟com_sf_test_Test.h中的必须一致。
6、编写ndk相关内容
jni目录下添加Android.mk和Application.mk文件
其中 Android.mk内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyTest
LOCAL_SRC_FILES := test.c
include $(BUILD_SHARED_LIBRARY)
Application.mk内如如下:
APP_ABI := all
7、利用ndk进行编译
在jni目录下,输入命令 ndk-build,可以生成相关的so文件
[armeabi] Install : libMyTest.so => libs/armeabi/libMyTest.so
生成的文件保存子main/libs目录下
目前存在的问题,只生成了armeabi架构适用的so文件。其他平台如x86等适用的没有生成。