接下來幾篇文章,學習JNI開發,主要是學習《JNI詳解》,將裡面的執行個體通過Android平台實現,首先由一個經典執行個體引出 – HelloWorld!!HelloWorld是經典的,一想起學編程,就想起那些年我們一起寫過的HelloWorld。這裡用HelloWorld來講解JNI的開發過程。這個過程大致可通過來說明:
1) 建立一個HelloWorld工程;
2) 建立一個帶有native方法的類Helloworld.java;
[java]
package org.winplus.helloworld;
public class HelloWorld {
public native void print();
private void stitic() {
System.loadLibrary("helloworld");
}
}
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的標頭檔。產生的程式碼如下:
[cpp]
<SPAN style="FONT-SIZE: 16px">/* 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</SPAN>
/* 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實現標頭檔中的函數
[cpp]
<SPAN style="FONT-SIZE: 16px">#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;
}
</SPAN>
#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檔案 www.2cto.com
c) 將產生的檔案拷貝到libs/armeabi目錄下,並更改名字為:libhelloworld.so
7) 運行程式,查看結果。
作者:tangcheng_ok