接下來幾篇文章,學習JNI開發,主要是學習《JNI詳解》,將裏面的實例通過Android平臺實現,首先由一個經典實例引出 – HelloWorld!!HelloWorld是經典的,一想起學編程,就想起那些年我們一起寫過的HelloWorld。這裏用HelloWorld來講解JNI的開發過程。這個過程大致可通過下圖來說明:
1) 新建一個HelloWorld工程;
2) 創建一個帶有native方法的類Helloworld.java;
package org.winplus.helloworld;
public class HelloWorld {
public native void print();
private void stitic() {
System.loadLibrary("helloworld");
}
}
HelloWorld類首先聲明瞭一個publicnativevoid print()方法。Static包含的是本地庫。在java代碼中聲明爲native的本地方法只作爲聲明存在。在調用本地方法之前,必須先裝載含有該方法的本地庫,如HelloWorld中所示,置於static中,在JavaVM初始化一個類時,首先會執行這段代碼,這可保證調用本地方法之前裝載了本地庫。轉載的機制請看後文…
3) 使用javac編譯Helloworld.java
使用Eclipse的同學不需要做此動作,都自動編譯了。進入Class目錄。
4) 使用javah –jni 編譯Helloworld.class 生成頭文件 Helloworld.h;Javah –jni org.winplus.helloworld.HelloWorld會生成一個名爲:org_winplus_helloworld_ HelloWorld.h的頭文件。生成的代碼如下:/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_winplus_helloworld_HelloWorld */
#ifndef _Included_org_winplus_helloworld_HelloWorld
#define _Included_org_winplus_helloworld_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_winplus_helloworld_HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_winplus_helloworld_HelloWorld_print
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
我們注意到JNIEXPORTvoid JNICALL Java_org_winplus_helloworld_HelloWorld_print(JNIEnv *,jobject);這裏我們注意到JNIEXPORT和JNICALL兩個宏,我們看到這個函數聲明接收兩個參數而對應的Java代碼中並沒有參數。第一個參數是指向JNIEnv結構的指針;第二個參數,爲HelloWorld對象自身,即this指針。
5) 使用C實現頭文件中的函數
#include <jni.h>
#include <stdio.h>
#include "android/log.h"
#include "HelloWorld.h"
static const char *TAG="HelloWorld";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
JNIEXPORT void JNICALL Java_org_winplus_helloworld_HelloWorld_print
(JNIEnv *env, jobject obj){
LOGI("Hello World");
return;
}
這裏爲了方便看到打印信息,使用了jni中的log.h頭文件和ANDROID_LOG_INFO宏。
6) 編譯C文件生成本地庫。這一步比較繁瑣,請下載源碼看吧。具體步驟
a) 將頭文件及C文件拷貝到jni目錄,並編寫Android.mk和Application.mk文件
b) 通過ndk或者在Ubuntu下編譯,生成helloworld.so文件
c) 將生成的文件拷貝到libs/armeabi目錄下,並更改名字爲:libhelloworld.so
7) 運行程序,查看結果。