基础
装ndk,并在studio中设定ndk的位置。并在project下的gradle.propreties文件中添加上android.useDeprecatedNdk=true。假设当前的module名为deaml,则在demo的build.gradle文件中的defaultConfig区域块中添加如下信息:
ndk {
moduleName "NdkJniDemo" //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无}
函数签名
基本数据类型:
引用数据类型:
数组
生成头文件及运行
使用javah命令生成相应的头文件(javah为java bin目录下的文件,与javac处于同一目录中,因此需要将bin目录配置到环境变量path中)。其余步骤如下:第一步:定义好native方法。如下:
public class JNIInterface {
public static native String getStringFromNative();
static {//加载生成的.so文件,与上面配置在build.gradle中的ndk下的moduleName值要一致
System.loadLibrary("NdkJniDemo");
}
}
然后make project,是为了在demo的/build/intermediates文件夹下生成classes文件夹。
第二步:使用命令行,进入到demo/build/intermediates/classes/debug文件夹下。执行javah -jni命令,后面跟的参数为第一步定义好的类的全名。该步用来生成相应的头文件。如下:
在该步中,也可以在studio的terminal中执行,但有可能会遇到提示javah不是内部命令之类的错误,并且环境变量已经配置完成,此时就需要在命令行中单独执行javah -jni命令。
头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_baigle_demo_JNIInterface */
#ifndef _Included_com_baigle_demo_JNIInterface
#define _Included_com_baigle_demo_JNIInterface
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_baigle_demo_JNIInterface
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_baigle_demo_JNIInterface_getStringFromNative
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
在第二行中引入了系统生成的jni.h头文件,并生成了相应的native对应的方法(Java_com_baigle_demo_JNIInterface_getStringFromNative)。只是该方法没有方法体,类似于java中的抽象方法。
上述方法中,有两个参数,使用第一个参数可以调用jni.h(系统生成的一个头文件)中的方法,第二个jobject表示当前native方法所在的类的对象。
第二步补充:javah -jni生成的native方法中不含有参数,如果含有参数,生成方法如下:
native方法代码:
public class JNIUtils {
public static native String getSign(PackageManager manager);
}
命令行如下:
如果提示自己的native文件没找到,就重新make project一次。并且javah -classpath之间的分隔使用的是";[空格]"。
第三步:在demo/src/main中新建jni文件夹,并将第二步中生成的.h文件(在demo/build/intermediates/classes/debug文件夹下)剪切到该文件夹中。新建一个c文件,引入第二步生成的头文件。如下:
#include "com_baigle_demo_JNIInterface.h"
JNIEXPORT jstring JNICALL Java_com_baigle_demo_JNIInterface_getStringFromNative
(JNIEnv * env, jobject obj){
return (*env)->NewStringUTF(env,"12345678");
}
第四步:make project,然后运行即可。
运行.so文件
打开demo\build\intermediates\ndk\debug\lib文件夹,可以看到自己配置的三个体系结构下的.so文件。删除main/jni文件夹,然后将三个.so文件复制到libs目录中,并在build.gradle中添加如下代码 sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
可以一样运行。输出日志
使用eclipse运行ndk时,需要配置Android.mk文件,但studio中不用。studio的Android.mk为自动生成,在build\intermediates\ndk\debug目录中。一个eclipse下的Android.mk如下(来自于ndk demo):
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := plasma
LOCAL_SRC_FILES := plasma.c
LOCAL_LDLIBS := -lm -llog -ljnigraphics
include $(BUILD_SHARED_LIBRARY)
其中LOCAL_LDLIBS中有值"-llog",则表示可以在c/c++文件中输出日志。而studio中Android.mk的一些内容可以在build.gradle文件中ndk{}块中进行配置——如LOCAL_MODULE便是ndk中配置的moduleName的值。所以,只需要在ndk{}中加入ldLibs "log"即可。具体步骤如下:
第一,在ndk{}中添加ldLibs “log",完整的ndk{}如下:
ndk {
moduleName "ImageJniUtils" //生成的so名字
ldLibs "log","jnigraphics" //可以使用log与graphics
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无
}
第二,在c/c++文件中引入android/log.h头文件。并且可以定义成宏函数。如下:
#include <android/log.h>
#define LOG_TAG "libplasma"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
其中__android_log_print为android/log.h中定义的函数。
第一个参数表示log的等级(如info,warn,error等),第二个参数表示输出日志的TAG(即Log.e(TAG,msg)中的TAG),第三个及以后的参数表示要输出的log(有可能在输出的时候会进行格式化)。使用如下:
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);//格式化后输出
LOGE("Bitmap format is not RGB_565 !");//直接输出
debug
第一步:在build.gradle中的buildTypes{}中添加如下: debug {
jniDebuggable true
}
第二步(参考):打开edit configurations,在弹出的对话框中选择android native。如下:
第三步,配置android native。如下:
其中在General选择卡中要选择一个要调试的module。
第四步:在第三步的对话框中,选择Native Debugger选项卡,并添加一个Symbol directories,在要调试的module下的build文件夹中选择。如下:
第五步:在运行时选择第三步填写的name,如上面的name为demo-native,因此在运行时选择demo-native即可。然后在代码中加断点跑debug即可。