说明:
以下文档中使用 *android_src 目录代表我的android6.0源码的根目录。*
1.在eclipse或者androidstudio中新建一个工程HelloWorld。
在包com/sk/helloworld
下面新建一个java文件。内容如下:
package com.sk.helloworld;
import android.R.integer;
public class JNICore {
static{
System.loadLibrary("JNICore");
}
public native String getStringFromNative();
public native boolean isNativeOK();
}
测试MainActivity.java文件如下:
package com.sk.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tView = (TextView) findViewById(R.id.tv);
JNICore jniCore = new JNICore();
boolean b = jniCore.isNativeOK();
if(b) {
tView.setText(jniCore.getStringFromNative());
}else{
tView.setText("isNativeOK false");
}
}
}
a. 终端进入HelloWorld的bin/classes目录。执行以下语句:
javah -classpath ./ -d ../../jni -jni com.sk.helloworld.JNICore
会在jni目录生成一个com.sk.helloworld.JNICore.h头文件。可按此头文件在当前目录写一个同名的cpp源码文件。内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <android/log.h>
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
jboolean mBoolean = JNI_FALSE;
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_sk_helloworld_JNICore
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_sk_helloworld_JNICore_getStringFromNative
(JNIEnv *env, jobject thiz) {
jstring des = (jstring)env->NewStringUTF("The string \"Hello World~\"is get from native.");
return des;
}
/*
* Class: com_sk_helloworld_JNICore
* Method: isNativeOK
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_sk_helloworld_JNICore_isNativeOK
(JNIEnv *env, jobject obj) {
mBoolean = JNI_TRUE;
return mBoolean;
}
#ifdef __cplusplus
}
#endif
#endif
b.再该目录下面新建两个文件Android.mk Application.mk。
Android.mk文件定义生成一个名为libJNICore.so的动态链接库。内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libJNICore
LOCAL_CPP_EXTENSION := .cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := com_sk_helloworld_JNICore.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk文件配置NDK编译的选项,
APP_OPTIM ———– 定义是debug还是release版本
APP_PLATFORM—— 定义编译时的ndk版本
APP_ABI —————-定义生成的 取得值包括:(1)、32位:armeabi、armeabi-v7a、x86、mips;(2)、64 位:arm64-v8a,x86_64, mips64;
APP_STL ————–定义C++库。这里我使用的c++源文件。且引用了iostream库。
文件内容如下:
APP_OPTIM := debug
APP_PLATFORM := android-19
APP_ABI := armeabi
APP_STL := stlport_static
2.在androi_src/packages/apps/HelloWorld
目录下编写Android.mk文件。用来定义生成apk文件,并拷贝到android_src/out/target/product/generic/system/app/HelloWorld
下面。该文件有一个特别的地方
LOCAL_JNI_SHARED_LIBRARIES := libJNICore 这条语句定义使用jni生成的动态链接库。如果没有这一句,将不会编译jni目录下面的c++文件。我之前在这里耗了很多时间,一直没有生成so库。导致后面运行HelloWorld.apk的时候找不到库而挂掉。
include $(BUILD_PACKAGE)这条语句定义要打包成apk。生成后会自动把生成的apk及so库文件一并拷贝到android_src/out/target/product/generic/system/app/HelloWorld
下面。编译后可到此目录查看是否有apk及so库。
该文件内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_CERTIFICATE := platform
LOCAL_PACKAGE_NAME := HelloWorld
LOCAL_JNI_SHARED_LIBRARIES := libJNICore
include $(BUILD_PACKAGE)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
**
工程新建完毕,可在eclipse工具上测试是否能编译通过。然后将HelloWorld文件夹拷贝到android_src/packages/apps/目录。删除HelloWorld目录下的bin和gen目录。
**
a.准备工作就绪,进行编译。android源码太大。编译耗时。但好在android提供了模块儿编译。在根目录执行source build/envsetup.sh后会增加几个命令。简单介绍需要用到的:
m:编译所有的模块
mm:编译当前目录下的模块,当前目录下要有Android.mk文件
mmm:编译指定路径下的模块,指定路径下要有Android.mk文件
这里我们到android_src/packages/apps/HelloWorld
目录下,执行mm命令进行编译。完成后,会在android_src/out/target/product/generic/system/app/
下生成HelloWorld目录。
然后将生成的apk打包进系统文件。
在源码根目录使用 如 命令打包:
make snod
b.之后就可以使用emulator运行模拟器,进行运行刚才增加的HelloWorld应用。
运行结果如下: