参考博文
JNI介绍
JNI: Java Native Interface. java本地接口.
功能: 使得Java虚拟机中的Java程序可以调用本地应用/或库, 本地程序一般是C/C++语言.
Java可以访问Native方法. Native方法调用Java对象.
JNI属于Java语言, 与Android无直接关系
JNI如何工作
在JNI框架,native方法一般在单独的.c或.cpp文件中实现.
当JVM调用这些函数,就传递一个 JNIEnv指针, 一个 jobject的指针,任何在Java方法中声明的Java参数:
一个JNI函数看起来类似这样:
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj)
{
/*Implement Native Method Here*/
}
其中, env指向一个结构包含了所有必须的函数与JVM交互、访问Java对象.
本地数据类型与Java数据类型可以互相映射。
对于复合数据类型,如对象,数组,字符串,就必须用JNIEnv中的方法来显示地转换。
如何编写第一个 .so 库
实现步骤:
- 在Java中声明Native方法(即需要调用的本地方法)
- 编译上述 Java源文件javac(得到 .class文件)
- 通过 javah 命令导出JNI的头文件(.h文件)
- 使用 Java需要交互的本地代码 实现在 Java中声明的Native方法
- 编译.so库文件
- 通过Java命令执行 Java程序,最终实现Java调用本地代码
NDK入门
NDK (Native Development Kit) 原生开发套件
- 是一套工具,使您能够在 Android 应用中使用 C 和 C++ 代码
- NDK是属于 Android 的,与Java并无直接关系
作用:
- 快速开发C、 C++的动态库,并自动将so和应用一起打包成 APK
- 即可通过 NDK在 Android中 使用 JNI与本地代码(如C、C++)交互
使用步骤:
- 配置Android NDK环境
- 创建Android项目,关联NDK
- 在Android想项目中声明所需调用的Native方法
- 实现在Android声明的Native方法
- 通过 ndk-build 命令,手动编译so库.
- 编译Android Studio工程,从而实现调用本地代码.
Android.mk和Application.mk文件编写
android.mk是用来描述要编译某个具体的模块,所需要的一些资源,包括要编译的源码、要链接的库等
application.mk:描述你的程序所需要的模块,即静态库或者共享库
动手编写简单的android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
- LOCAL_PATH:必须位于android.mk文件的开始,用来定位源文件的位置,$(call my-dir)返回当前路径,即android.mk所在的目录
- include $(CLEAR_VARS):清除变量的值,不包括LOCAL_PATH
- LOCAL_MODULE:描述的模块,名字唯一,不能有空格,编译系统会生成合适的前缀和后缀
- LOCAL_SRC_FILES:参与编译的所有源代码文件
- include $(BUILD_SHARED_LIBRARY):把当前模块编译为共享库,前缀为lib,后缀为.so
- include$(BUILD_STATIC_LIBRARY):把当前模块编译为静态库,前缀为lib,后缀为.a
动手编写简单的application.mk
APP_ABI := armeabi-v7a
APP_MODULES=hellp-jni
- APP_ABI:支持的ABI平台,上所示为armeabi-v7a,其他的如x86,多个用空格隔开,如armeabi-v7a x86
- APP_MODULES:如果指定,那么ndk只会编译列出的模块列表,模块名用空格隔开,如果没有指定,那么ndk会编译所有的android.mk文件声明的所有LOCAL_MODULE模块
NDK 日志
需要三步:
-
在Android.mk中添加以下内容
LOCAL_LDLIBS := -lm -llog 或者 LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
-
引用头文件
#include <android/log.h>
-
定义变量
//定义TAG之后,我们可以在LogCat通过TAG过滤出NDK打印的日志 #define TAG "JNI_TEST" // 定义info信息 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__) // 定义debug信息 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) // 定义error信息 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
-
使用
LOGI("the string is :%s",str1);