Android ndk第一步,构建jni headers
转载请注明出处:http://www.cnblogs.com/fpzeng/p/4281801.html
源码请见 https://github.com/fpzeng/HelloJNI
PC系统: ubuntu 12.04
Android SDK: android-sdk-linux_r24
Android NDK:android-ndk-r10d
概述
在android上使用ndk的步骤:
- 创建java文件,声明native方法;
- 使用javah生成C语言接受的头文件*.h;
- 创建*.c文件,使用C语言实现该native方法;
- 编译*.c文件产生so库
- 运行的时候,java使用System.loadLibrary打开so库,调用native方法。
声明native方法
在com.fpzeng.example.jni.HellojniActivity声明native方法:
private native String nativeGetMacAddress(int Parameter1);
此时目录结构如下:
AndroidManifest.xml -jni Android.mk -src hello_jni.c -src -com -fpzeng -example -jni HellojniActivity.java -res ...
产生头文件
使用javah产生jni头文件,会将产生的头文件com_fpzeng_example_jni_HellojniActivity.h输出到jni目录下。命令如下:
javah -jni -d jni -classpath src/ com.fpzeng.example.jni.HellojniActivity
产生的 com_fpzeng_example_jni_HellojniActivity.h头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_fpzeng_example_jni_HellojniActivity */ #ifndef _Included_com_fpzeng_example_jni_HellojniActivity #define _Included_com_fpzeng_example_jni_HellojniActivity #ifdef __cplusplus extern "C" { #endif /* * Class: com_fpzeng_example_jni_HellojniActivity * Method: nativeGetMacAddress * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_fpzeng_example_jni_HellojniActivity_nativeGetMacAddress (JNIEnv *, jobject, jint); #ifdef __cplusplus } #endif #endif
此时的入参数是int,返回值类型时String类型。
引入Android SDK
如果将java中声明的native方法变的复杂,比如引入Context。在com.fpzeng.example.jni.HellojniActivity声明native方法更新为
private native String nativeGetMacAddress(Context context);
运行产生命令: javah -jni -d jni -classpath src/ com.fpzeng.example.jni.HellojniActivity,此时提示错误:
Error: Cannot determine signature for Context
这是由于javah不认识Context类,需要将android.jar包含进来才行。
我的LINUX环境变量中,使用ANDROID_SDK_ROOT指向了当前android-sdk-linux_r24的绝对路径,大家也需要设置自己的ANDROID SDK环境变量。此时,头文件的生成命令如下:
javah -jni -d jni -classpath src/:$ANDROID_SDK_ROOT/platforms/android-15/android.jar com.fpzeng.example.jni.HellojniActivity
产生的 com_fpzeng_example_jni_HellojniActivity.h头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_fpzeng_example_jni_HellojniActivity */ #ifndef _Included_com_fpzeng_example_jni_HellojniActivity #define _Included_com_fpzeng_example_jni_HellojniActivity #ifdef __cplusplus extern "C" { #endif /* * Class: com_fpzeng_example_jni_HellojniActivity * Method: nativeGetMacAddress * Signature: (Landroid/content/Context;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_fpzeng_example_jni_HellojniActivity_nativeGetMacAddress (JNIEnv *, jobject, jobject); #ifdef __cplusplus } #endif #endif
加入Android.mk
每次新加native方法都需要运行该命令,是不是很头痛?
首先在jni/Application.mk中指定当前的工程路径,用变量APP_PROJECT_PATH指向。
APP_PROJECT_PATH := $(shell pwd) APP_CFLAGS+=-Wno-error=format-security APP_PLATFORM := android-15 APP_ABI := armeabi-v7a APP_OPTIM := debug
然后在jni/Android.mk 加入响应的参数依赖,如下:
headers: $(warning app project path $(APP_PROJECT_PATH)) @cd $(APP_PROJECT_PATH) javah -jni -d jni -classpath src/:$ANDROID_SDK_ROOT/platforms/android-15/android.jar com.fpzeng.example.jni.HellojniActivity
此时运行ndk-build headers,首先打印 aap project path目录,然后进入该目录执行javah命令。