百度内推,可文末扫码加微信
一、jni是什么?为什么会有jni的存在?
JNI是Java Native Interface的缩写,中文可译为Java本地调用,它允许Java代码和其他语言写的代码进行交互,而我们在使用JNI的时候是让其与C语言通信,我们知道C语言是偏底层的语言,可以直接操作硬件,执行效率较高,这个时候JNI就派上了用场,可以通过JNI直接调用c语言的函数。JNI这个概念听着好像很神秘的感觉,其实总结下来就是俩句话“产生头文件”,“实现头文件定义的函数”。下面我们分析一下如何实现这俩句话。
二、JNI接口的实现
首先需要实现.java文件,该java文件中定义了我们C语言函数的接口,定义java文件为StarMultiClient.java,文件中内容如下:
package stl.startimes;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
public class StarMultiClient
{
public static native int StarMultiClientInit(int argc,String[] argv,String certificate_path);
public static native int StarMultiClientTerm();
public static native int StarMultiClientPrePlayStart(String gateway_ip,String multi_ip,int multi_port);
public static native int StarMultiClientPrePlayStop(String multi_ip,int multi_port);
static
{
try{
System.loadLibrary("StarMultiClient");
} catch(UnsatisfiedLinkError e)
{
System.err.println("Cannot load MULTI_CLIENT library:\n " +
e.toString());
}
}
}
如上代码中public定义的函数,即是最终我们要实现的C语言函数。StarMultiClient是最终我们提供给java程序调用的库的命名,比如libStarMultiClient.so,java程序在运行的时候会去调用System.loadLibrary来加载这个库,加载之后就可以调用我们封装的接口了。
写好java文件后生成我们的头文件,
javac StarMultiClient.java
javah StarMultiClient
通过这俩步即可自动生成stl_startimes_StarMultiClient.h的头文件。内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class stl_startimes_StarMultiClient */
#include "stl_type.h"
#ifndef _Included_stl_startimes_StarMultiClient
#define _Included_stl_startimes_StarMultiClient
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: stl_startimes_StarMultiClient
* Method: StarMultiClientInit
* Signature: (I[Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_stl_startimes_StarMultiClient_StarMultiClientInit
(JNIEnv *, jclass, jint, jobjectArray, jstring);
/*
* Class: stl_startimes_StarMultiClient
* Method: StarMultiClientTerm
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_stl_startimes_StarMultiClient_StarMultiClientTerm
(JNIEnv *, jclass);
/*
* Class: stl_startimes_StarMultiClient
* Method: StarMultiClientPrePlayStart
* Signature: (Ljava/lang/String;Ljava/lang/String;I)I
*/
JNIEXPORT jint JNICALL Java_stl_startimes_StarMultiClient_StarMultiClientPrePlayStart
(JNIEnv *, jclass, jstring, jstring, jint);
/*
* Class: stl_startimes_StarMultiClient
* Method: StarMultiClientPrePlayStop
* Signature: (Ljava/lang/String;I)I
*/
JNIEXPORT jint JNICALL Java_stl_startimes_StarMultiClient_StarMultiClientPrePlayStop
(JNIEnv *, jclass, jstring, jint);
#ifdef __cplusplus
}
#endif
#endif
这些生成的函数就是我们需要实现的函数,可以看到这些函数只是在我们的.java文件中定义的函数基础上加了一些前缀而已,无需关心,javah过程自己干的,我们只需要去实现这些函数即可。
创建一个与第二步中同名的.c文件,这里是stl_startimes_StarMultiClient.c,然后实现第二步生成的头文件中的所有函数即可。注意实现过程是用C语言实现的,jstring,jint类型都需要转换成我们C语言的类型,以及使用完这些类型需要及时释放,类型转换与释放变量可以去百度搜索,大把大把的。
以上.C完成之后我们就可以去编译了,编译的时候需要利用NDK的环境,可自行去网上下载,ndk安装完成后我们需要写安卓的makefile用于编译我们的.c文件,这里涉及到俩个makefile,一个是Android.mk,一个是Application.mk,其中Application.mk指定了要生成的库文件是属于
什么架构的,以及使用的安卓API版本
Application.mk内容如下:
APP_PLATFORM = android-18 ## (这里使用的是android-18,只要是android-15版本以上现在的安卓设备基本都支持)
APP_ABI := armeabi armeabi-v7a ##(这里指定了编译出的库所支持的架构,这是安卓的俩个主流架构,基本可以囊括现有安卓设备)
Android.mk内容如下:
LOCAL_PATH := $(call my-dir) ##声明当前路径
include $(CLEAR_VARS) ##清理环境变量
LOCAL_MODULE := stl_client_android_v1.00.00_debug ##要连接的库
LOCAL_SRC_FILES :=
(
L
O
C
A
L
P
A
T
H
)
/
.
.
/
l
i
b
/
(LOCAL_PATH)/../lib/
(LOCALPATH)/../lib/(TARGET_ARCH_ABI)/libstl_client_android_v1.00.00_debug.a #指定链接的库
include $(PREBUILT_STATIC_LIBRARY) ##声明编译时连接先前存在的静态库
include $(CLEAR_VARS)
LOCAL_C_INCLUDES +=
$(LOCAL_PATH)/
$(LOCAL_PATH)/…/
$(LOCAL_PATH)/…/include ##声明头文件路径
#连接的静态库
LOCAL_STATIC_LIBRARIES := stl_client_android_v1.00.00_debug
#要生成的.so库名称。java代码System.loadLibrary(“StarMultiClient”);加载的就是它
LOCAL_MODULE := StarMultiClient
#要编译的C文件
LOCAL_SRC_FILES := $(LOCAL_PATH)/…/client.c stl_startimes_StarMultiClient.c
LOCAL_LDLIBS := -lc
LOCAL_LDLIBS += -llog
##声明编译出动态库
include $(BUILD_SHARED_LIBRARY)
编译过程,首先执行export PATH=/opt/android-ndk-r10e:$PATH,指定ndk的路径,然后在.c所在文件夹下执行ndk-build,即可生成库文件libStarMultiClient.so
三、JNI的输出文件
经过编译后生成了很多文件,那么哪些是需要打包给安卓端的呢?
libStarMultiClient.so 我们的库文件,提供给安卓的接口都在这个文件实现的。
StarMultiClient.java java文件,安卓会通过这个文件中定义的类去调用我们的函数
StarMultiClient.class 字节码文件,需要给安卓虚拟机启动的时候加载使用,才可以使用我们的类
最好再输出一个接口说明文档供调用者阅读使用。详细说明jni接口的出入参数,返回值以及函数介绍。
扫一扫,可加楼主微信,一起交流C语言,嵌入式等IT技术。
声明:本文原创,码字不易,版权必究,编辑转载请注明链接出处与原作者。