开始学习NDK开发,首先以输出Hello World实例开始讲解。
NDK的开发步骤:
1、在Java文件中声明native方法
public class TestActivity extends Activity { static { System.loadLibrary("my-ndk"); } // 声明JNI层的原生方法,使用native关键字 public native String stringFromJNI(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tvText = new TextView(this); tvText.setText(stringFromJNI()); setContentView(tvText); } }
2、编译Java文件
直接用javac命令编译声明native方法的Java文件
shamoo的工程目录在E:\project\test
在cmd中,输入cd E:\project\test
javac src\com\shamoo\jni\HelloJni.java -d bin\classes
-d指定.class文件的输出目录
也可以使用eclipse直接生成,生成的目录在工程目录的bin\classes
3、使用javah命令生成头文件
关于javah命令,Shamoo也折腾了一段时间,一直使用命令失败,总是提示不能访问Android sdk的类,后来用-classpath指定src的位置就可以了,具体原因不明...
javah -classpath src -d jni -jni com.shamoo.activity.TestActivity
如果声明native方法的类中没有使用Android sdk的类就可以使用以下命令,例如HelloJni声明了navtive方法
javah -classpath bin/classes -d jni -jni com.shamoo.jni.HelloJni
-classpath指定.class文件的根目录 -d指定输出目录 -jni指定声明了native方法的类。javah是根据.class文件反编译生成头文件的
生成的头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_shamoo_activity_TestActivity */ #ifndef _Included_com_shamoo_activity_TestActivity #define _Included_com_shamoo_activity_TestActivity #ifdef __cplusplus extern "C" { #endif /* * Class: com_shamoo_activity_TestActivity * Method: stringFromJNI * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_shamoo_activity_TestActivity_stringFromJNI (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
从头文件可以看出,原生方法必须指定Java + 原生方法的包名(点用下划线代替) + 方法名
4、编写头文件对应的源文件 com_shamoo_activty_TestActivity.cpp
#include <jni.h> #include <stdio.h> #include <com_shamoo_activity_TestActivity.h> JNIEXPORT jstring JNICALL Java_com_shamoo_activity_TestActivity_stringFromJNI (JNIEnv *env, jobject) { printf("Hello World"); return env->NewStringUTF("Hello World"); }是不是很熟悉,printf("Hello World");不过printf默认不会输出到Log里面,需要设置一下才可以。这次编写源文件就不需要再写extern "C"标志,因为自动生成的头文件已经帮我们完成啦!
5、修改Android.mk文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := my-ndk LOCAL_SRC_FILES := my-ndk.cpp com_shamoo_activity_TestActivity.cpp LOCAL_LALIBS += -llog include $(BUILD_SHARED_LIBRARY)
Android.mk其实就是Makefile,分析一下上面的几个环境变量
LOCAL_PATH指定源码的目录,$(call my-dir),学过Linux Shell再熟悉不过了
LOCAL_MODULE编译生成的.so库
LOCAL_SRC_FILES指定加入编译的源文件
LOCAL_LALIBS指定其他库,-l + 库名,例如上述要使用到NDK的LOG就要使用log库
include导入一些Makefile的片段,比如导入CLEAR_VARS会在配置之前清除以前的环境变量,以免编译的时候受到其他环境变量的影响,BUILD_SHARED_LIBRARY是导入其他的共享库
好的直接编译,执行,没问题就会看到一个Activity显示Hello World的文本啦!