最近做android项目,终于用到了NDK。我本身太懒,碰不到的东西都不想去学习,等到问题出来了才有劲头去研究。虽然项目本身的JNI问题在网上七凑八凑的搞定了,但是感觉NDK的内容还是要从头系统的学习一下,所以这里在标题后面加了个一。这个“一”可能会不断的增加,也可能就会这么一直孤独下去了……
现在开始记录一下初次学习的步骤吧。刚学习我也是去网上找了一篇博客,博客地址如下:(http://blog.csdn.net/redoffice/article/details/6654714)这篇博客里面的作者写的很清楚,也
特别适合我这种懒人的入门学习。但是完全照着他的去做并不能走完一个流程,大部分原因应
该是jdk,ndk的版本导致的。这里我们还是以他的为基础,用最新的ndk(我的是ndk8)吧整
个流程再走一遍,顺便记录下某些问题的解决方法。
首先,建立android工程,工程中的MainActivity内容如下(这里面的代码还是上文提到那篇
博客的代码,暂时不纠结这个,主要还是把流程走通):
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView myTextView = new TextView(this);
myTextView.setText( stringTestNdk() );
setContentView(myTextView);
}
public native String stringTestNdk();
public native String stringTestNdk2();
static {
System.loadLibrary("testNDK");
}
<span style="font-family:Arial, Helvetica, sans-serif;font-size:24px;"><span style="font-size: 18px; white-space: normal;">
</span></span>
其中 System.loadLibrary("testNDK");是加载testNDK库文件(全名为libtestNDK.so)。两
个native方法是我们要在C/C++中实现的的native方法。
然后,打开cmd,进入工程下面输入javah -classpath bin/classes -d ndk com.exm.helloword.MainActivity
(这里注意原博客里面没有加入bin后面的classes,但是那样执行可能因为jdk版本问题会出错)。这样就生成了
一个.h文件。这个头文件貌似没用到,但是还是生成,待会写c/C++文件的时候可以吧函数名拷过去。
头文件的内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_exm_helloword_MainActivity */
#ifndef _Included_com_exm_helloword_MainActivity
#define _Included_com_exm_helloword_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_exm_helloword_MainActivity
* Method: stringTestNdk
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_exm_helloword_MainActivity_stringTestNdk
(JNIEnv *, jobject);
/*
* Class: com_exm_helloword_MainActivity
* Method: stringTestNdk2
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_exm_helloword_MainActivity_stringTestNdk2
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
这里生成的头文件默认生成在工程目录下的ndk目录下,我在工程下面新建了一个jni目录,
把头文件拷贝到到jni目录中,看里面的两个方法,命名规则是 包名+类名+函数名,括号里的两个参数是默认的。
再然后,在jni目录下新建一个testNSK.cpp的C++文件,里面的内容我直接把上文提到博客里面
的c内容加入进去,代码如下:
#include <string.h>
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_exm_helloword_MainActivity_stringTestNdk
(JNIEnv *env, jobject obj){
return (*env)->NewStringUTF(env, "Hello Test Little T !");
}
编写完成该C++文件以后,在jni目录下新建一个mk文件,命名为Android.mk内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= testNDK
LOCAL_SRC_FILES := testNDK.cpp
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH := $(call my-dir)
编写完mk文件后
用ndk编译上述文件,以便生成so文件。编译过程如下(适合ndk8以上,不用安装配置cygwin):
在cmd中进入到工程的jni目录下,输入ndk命令D:\android\ndk-bulid(我没有配置环境变量,切ndk在该
目录下所以输入的是整个路径名称加上ndk命令)
编译过程到这里就算是结束了。但是我碰到了两个问题:
(1)the mangling of ‘va_list’ has changed in GCC4.4
在mk文件中加入 LOCAL_CFLAGS = -Wno-psabi,修改后mk文件如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
<span style="color:#FF0000;">LOCAL_CFLAGS = -Wno-psabi</span>
LOCAL_MODULE:= testNDK
LOCAL_SRC_FILES := testNDK.cpp
include $(BUILD_SHARED_LIBRARY)
(2) base operand of '->' has non-pointer type 'JNIEnv {aka _JNIEnv}':
问题是原博客的是c文件,我写的是c++文件,所以要把testNDK.cpp的内容改为:
#include <string.h>
#include <jni.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_com_exm_helloword_MainActivity_stringTestNdk(JNIEnv *env, jobject obj){
<return env->NewStringUTF("Hello Test Little T !");
}
<span style="color:#FF0000;">}
修改完成再运行ndk命令,便可在工程下发现多了一个obj包,包里面有个local文件夹,
可以找到libtestNDK.so的包。然后运行工程,便可输出如下信息。"Hello Test Little T !"
好了,到这里算是吧流程走完了,但是里面的很多概念性的东西还不是很了解,
当然上文提到的博客里面有比较详细明了的说明,更细节的和深入的内容有
待继续去学习,希望那个“一”不会孤独下去。