android的JNI开发一种是内核级的(android源码),一种是一般的应用程序(它被打入到APK包)。在此讨论的是一般的应用程序。
开发JNI应用需要的工具有
Android NDK
下载地址:
http://developer.android.com/sdk/ndk/index.html#requirements
而要运行Android NDK的命令(比如ndk-build)需要
:
* For all development platforms, GNU Make 3.81 or later is required. Earlier versions of GNU Make might work but have not been tested
* A recent version of awk (either GNU Awk or Nawk) is also required.
* For Windows , Cygwin 1.7 or higher is required
. The NDK will not work with Cygwin 1.5 installations.
以上信息来自于http://developer.android.com/sdk/ndk/index.html#requirements.
注意: Android的这个文档有点误导人 。
对于Linux平台需要GNU Make 3.81 or later,或A recent version of awk (either GNU Awk or Nawk)。
虽然对于Windows也需要GNU Make 3.81 or later,或A recent version of awk (either GNU Awk or Nawk)。
但是实际上如果对 Cygwin 1.7 or higher是完全安装的话,
Cygwin 就已经包含了GNU Make和awk的window版本
。
因此Window平台下,其实对Cygwin进行完全安装就行了 。
在http://developer.android.com/sdk/ndk/index.html#requirements还有很多有用信息,可以参阅。
GNU Make下载地址
linux版本
http://ftp.gnu.org/gnu/make/
awk下载地址:
linux版本
http://linux.softpedia.com/get/Text-Editing-Processing/Filters/GNU-awk-207.shtml
window版本
http://www.softpedia.com/get/CD-DVD-Tools/CD-DVD-Images-Utils/Gawk-for-Windows.shtml
gawk下载地址:
http://ftp.gnu.org/gnu/gawk/
Cygwin下载地址。
7,定义Jni函数
。
8,编辑Android.mk
在jni下新建Android.mk文件如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)。
开发JNI应用需要的工具有
下载地址:
* For all development platforms, GNU Make 3.81 or later is required. Earlier versions of GNU Make might work but have not been tested
* A recent version of awk (either GNU Awk or Nawk) is also required.
* For Windows ,
以上信息来自于http://developer.android.com/sdk/ndk/index.html#requirements.
注意:
对于Linux平台需要GNU Make 3.81 or later,或A recent version of awk (either GNU Awk or Nawk)。
虽然对于Windows也需要GNU Make 3.81 or later,或A recent version of awk (either GNU Awk or Nawk)。
但是实际上如果对 Cygwin 1.7 or higher是完全安装的话,
因此Window平台下,其实对Cygwin进行完全安装就行了
在http://developer.android.com/sdk/ndk/index.html#requirements还有很多有用信息,可以参阅。
GNU Make下载地址
linux版本
http://ftp.gnu.org/gnu/make/
awk下载地址:
linux版本
http://linux.softpedia.com/get/Text-Editing-Processing/Filters/GNU-awk-207.shtml
window版本
http://www.softpedia.com/get/CD-DVD-Tools/CD-DVD-Images-Utils/Gawk-for-Windows.shtml
gawk下载地址:
http://ftp.gnu.org/gnu/gawk/
Cygwin下载地址。
注意:
Cygwin的安装包选项那屏,点击包菜单根的"All"后面的"Default",然它变成"install",就是完全安装。
在安装Android NDK后:
在其samples目录下找到很多实例程序
在其docs目录下可以看到有很多帮助文档,
首先阅读的应该是OVERVIEW.TXT。
关于Android.mk文件的编写在ANDROID-MK.TXT中
关于Application.mk文件的编写在APPLICATION-MK.TXT中
关于Android NDK的安装要求在INSTALL.TXT中。
如何在Eclipse中进行android的JNI开发。
1,首先需要在Eclipse建个Android工程
。
工程名为JniHello,Activity名为HelloActivity
2,HelloActivity中载入一个JNI包
。
在使用JNI的接口前,需要载入JIN的包。
我这里的JIN包名为hello-jni
(其文件名为lib+包名+.so,即libhello-jni.so)。
HelloActivity中载入如下:
static {
System.loadLibrary("hello-jni");
}
3, 在Java声明一个JNI函数
:
native String getStringFromJni();
4, 在Java中使用JIN函数和一般的java函数一样
。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView=(TextView)findViewById(R.id.textView1);
textView.setText( getStringFromJni()) ;
}
5, 建立jni源代码的目录jni
.
在JniHello下建立个jni目录。
在其samples目录下找到很多实例程序
在其docs目录下可以看到有很多帮助文档,
首先阅读的应该是OVERVIEW.TXT。
关于Android.mk文件的编写在ANDROID-MK.TXT中
关于Application.mk文件的编写在APPLICATION-MK.TXT中
关于Android NDK的安装要求在INSTALL.TXT中。
如何在Eclipse中进行android的JNI开发。
工程名为JniHello,Activity名为HelloActivity
在使用JNI的接口前,需要载入JIN的包。
我这里的JIN包名为hello-jni
(其文件名为lib+包名+.so,即libhello-jni.so)。
HelloActivity中载入如下:
static {
System.loadLibrary("hello-jni");
}
3,
native String getStringFromJni();
4,
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView=(TextView)findViewById(R.id.textView1);
textView.setText( getStringFromJni()) ;
}
5,
在JniHello下建立个jni目录。
6,在头文件中声明C\C++的Jni函数
如果你需要不同的JNI的C\C++实现文件的函数能互相调用,那么你就需要为你的JNI的C\C++端编写扩展名为h的头文件。
你可以手写头文件,也可以使用javah命令。
这里我不需要不同的JNI的C\C++实现文件的函数进行调用,因此略去该步骤。
在目录jni下新建个文件hello-jni.c如下:
#include <string.h>
#include <jni.h>
jstring
Java _ c om_teleca_robin_HelloActivity _ getStringFromJni ( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello robin,this world is from JNI !");
}
函数返回类型
jstring 代表的是返回类型。这里应该表示的是java的String.
函数名字
函数名字首先是前缀java,然后是要调用该JNI的Java类的路径,
接着是Java中申明的函数的名字。
函数参数
第一个参数永远应该是JNIEnv* env,
第二个参数jobject thiz是java中的this指针。
第三个参数开始是Java的函数中的参数。
比如实例bitmap-plasma中的Plasma对renderPlasma声明如下:
private static native void renderPlasma(Bitmap bitmap, long time_ms);
在jni中则为
JNIEXPORT void JNICALL Java_com_example_plasma_PlasmaView_renderPlasma(JNIEnv * env, jobject obj, jobject bitmap, jlong time_ms)
#include <string.h>
#include <jni.h>
jstring
Java _ c om_teleca_robin_HelloActivity _ getStringFromJni ( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello robin,this world is from JNI !");
}
函数返回类型
jstring 代表的是返回类型。这里应该表示的是java的String.
函数名字
函数名字首先是前缀java,然后是要调用该JNI的Java类的路径,
接着是Java中申明的函数的名字。
函数参数
第一个参数永远应该是JNIEnv* env,
第二个参数jobject thiz是java中的this指针。
第三个参数开始是Java的函数中的参数。
比如实例bitmap-plasma中的Plasma对renderPlasma声明如下:
private static native void renderPlasma(Bitmap bitmap, long time_ms);
在jni中则为
JNIEXPORT void JNICALL Java_com_example_plasma_PlasmaView_renderPlasma(JNIEnv * env, jobject obj, jobject bitmap, jlong time_ms)
注意:JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的
应用层级的Java类别通过VM而调用到本地函数,VM默认是按照JNI的java函数和C\C++本地函数的命名规范,去寻找*.so里的本地函数。
查找的过程还是有点耗时。如果调用次数很多,而每次都寻找一遍的话,会花掉许多时间。
如果你想节约VM查找JNI本地函数的时间,你可以通过registerNativeMethods()函数把JNI本地函数向VM进行登记,以节约VM查找JNI本地函数的时间。
如果你的JNI本地函数的命名没严格遵守java函数和C\C++本地函数对应的命名规范,你必须通过registerNativeMethods()函数把JNI本地函数向VM进行登记,以便VM能找到你的JNI本地函数。
关于JNI本地函数向VM进行登记,请参照《
JNI系统程序开发》
在jni下新建Android.mk文件如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)。
关于Android.mk的更多内容请参照《Android.mk》
9,编译JNI
在cygwin\home\hubin的.bash_profile文件中添加设置ndk的路径。
NDK=/cygdrive/d/SDK/android-ndk-r4b
export NDK 。
programs->Cygwin->Cygwin Bash Shell或直接点击cygwin\Cygwin.bat打开cygwin bash shell窗口,
然后进入工程JniHello的根目录
执行$NDK/ndk-build。
这时应该就能在JniHello的根目录的libs\armeabi下生成libhello-jni.so。
注意 :在cygwin中进入一个盘符的命令为cd D:的形式
9,编译JNI
在cygwin\home\hubin的.bash_profile文件中添加设置ndk的路径。
NDK=/cygdrive/d/SDK/android-ndk-r4b
export NDK 。
programs->Cygwin->Cygwin Bash Shell或直接点击cygwin\Cygwin.bat打开cygwin bash shell窗口,
然后进入工程JniHello的根目录
执行$NDK/ndk-build。
这时应该就能在JniHello的根目录的libs\armeabi下生成libhello-jni.so。
注意 :在cygwin中进入一个盘符的命令为cd D:的形式
关于Cygwin的使用的更多内容请参阅《
Cygwin使用指南》
10,在Ecplise中重新打包生成apk文件,libhello-jni.so也同时被打进了apk
.
11,像运行一般android程序一样运行该程序
。
在jni函数中向android的控制台打印信息可以采用以下的方式。
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
LOGI("frame/s (avg,min,max) = (%.1f,%.1f,%.1f) "
"render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n",
1000./avgFrame, 1000./maxFrame, 1000./minFrame,
avgRender, minRender, maxRender);
关于如何定义多个JNI包(module),请参考android-ndk-r4b\samples\two-libs
在jni函数中向android的控制台打印信息可以采用以下的方式。
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
LOGI("frame/s (avg,min,max) = (%.1f,%.1f,%.1f) "
"render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n",
1000./avgFrame, 1000./maxFrame, 1000./minFrame,
avgRender, minRender, maxRender);
关于jni的使用可以参照《
JNI应用程序开发实例1》