初学JNI(一)环境配置及调用流程
1.搭建环境
安装Cygwin(Cygwin是在Windows平台下模拟Linux环境的工具。)
安装NDK http://developer.android.com/tools/sdk/ndk/index.html
配置环境变量:
1.1.使用Cygwin提供的命令行工具,使用 cd ..命令回到home路径
1.2.进入/cygdrive路径,找到自己NDK的安装路径,然后复制当前命令行显示的完整路径
1.3.在Cygwin的etc路径下找到profile文件,在其中的Path中添加上面复制的完整路径,使用冒号分隔。
PS:在ndk-r7版本以后,不再需要安装Cygwin,可以在windows环境下直接使用ndk-build进行交叉编译编译。需要在环境变量中配置NDK的路径,如下:
在系统变量中新建:
变量名:NDK_HOME
变量值:D:\Develop\android-ndk
在Path中添加:
%NDK_HOME%,使用分号分隔
在命令提示符中执行ndk-build,如果出现以下内容,则配置环境变量成功:
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
D:\Develop\android-ndk\build/core/build-local.mk:130: *** Android NDK: Aborting
. Stop.
2.调用JNI的流程
2.1.在Java中定义native方法,该方法需要由C\C++来实现,例如:
public native String helloFromJNI();
2.2.在项目路径下建立jni文件夹
2.3.在jni路径下建立C\C++文件
2.4.在C\C++文件中定义对应的要事先的方法,需要导入jni.h头文件
2.5.编写Android.mk文件(可以在NDK的docs路径下找到ANDROID-MK.html,在第75行可以找到实例代码,复制即可),如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Hello
LOCAL_SRC_FILES := Hello.c
LOCAL_LDLIBS+=-llog
include $(BUILD_SHARED_LIBRARY)
Android.mk文件中,各行的解释:
2.5.1.
LOCAL_PATH := $(call my-dir)
记录Android.mk的文件位置,其中call my-dir,得到绝对路径2.5.2.
include $(CLEAR_VARS)
初始化参数信息
CLEAR_VARS 清空上次参数信息2.5.3.
LOCAL_MODULE := Hello
交叉编译后,生成的可执行文件名称2.5.4.
LOCAL_SRC_FILES := Hello.c
参与交叉编译的源文件,需要多个源文件时,使用空格分隔2.5.5.
include $(BUILD_SHARED_LIBRARY)
指定交叉编译后,生成的文件类型
BUILD_SHARED_LIBRARY-动态链接库
BUILD_STATIC_LIBRARY-静态链接库
2.6.使用Cygwin命令行,进入jni目录,使用ndk-build命令进行交叉编译(ndk-r7及以上版本不需要使用Cygwin,直接在项目路径下使用ndk-build命令即可进行交叉编译),生成.so文件
2.7.在Java代码中使用静态方法调用编译生成的库文件,如下:
static {
System.loadLibrary("Hello");
}
2.8.调用native方法,实现JNI调用
3.C\C++中方法的命名
在Java代码中定义的native方法如下:
public native String helloFromJNI();
则在C\C++代码中需要命名为:
jstring JNICALL Java_com_chen_jni_demo_MyActivity_helloFromJNI
4.方便生成方法名的方式
进入到工程的bin路径下(jdk1.7则进入src路径),使用javah命令生成.h头文件:
javah com.chen.jni.demo.MyActivity
生成的.h文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_chen_jni_demo_MyActivity */#ifndef _Included_com_chen_jni_demo_MyActivity
#define _Included_com_chen_jni_demo_MyActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_chen_jni_demo_MyActivity
* Method: helloFromJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_chen_jni_demo_MyActivity_helloFromJNI
(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif
将该文件复制到jni路径下,在C\C++代码中使用
#include "com_chen_jni_demo_MyActivity.h"
将该文件包含进去。
此时,方法名可以直接从.h文件中复制
JNIEXPORT jstring JNICALL Java_com_chen_jni_demo_MyActivity_helloFromJNI
(JNIEnv *, jobject)
5.在C\C++中使用Log输出日志
#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
在C\C++文件汇总,使用以上代码可以调用Log进行输出,此外,还必须在Android.mk文件中添加以下内容:
LOCAL_LDLIBS+=-llog
6.使用C++来实现JNI调用
不同于使用C代码来实现JNI调用,使用C++实现调用时,还需要在jni路径下编写Application.mk文件,内容如下:
APP_ABI:=armeabi
APP_STL := gnustl_static
此时Android.mk文件中的内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Hello
LOCAL_SRC_FILES := Hello.cpp
LOCAL_LDLIBS+=-llog
include $(BUILD_SHARED_LIBRARY)
此时,就可以在*.cpp文件中使用
#include <iostream>
using namespace std;