真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

androidjni,Androidjni編程

android 怎么封裝jni

一、底層實(shí)現(xiàn):

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了新華免費(fèi)建站歡迎大家使用!

c文件:hardware/libhardware_legacy/power/power.c

以其中set_screen_state(int)函數(shù)為例

其Android.mk中添加:

LOCAL_MODULE:= libpower 編譯成lib

LOCAL_SRC_FILES += power.c

hardware/libhardware_legacy/power/power.c

1: int

2: set_screen_state(int on)

3: {

4: QEMU_FALLBACK(set_screen_state(on));

5:

6: LOGI("*** set_screen_state %d", on);

7:

8: initialize_fds();

9:

10: //LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,

11: // systemTime(), strerror(g_error));

12:

13: if (g_error)

14: goto failure;

15:

16: char buf[32];

17: int len;

18: if(on)

19: len = snprintf(buf, sizeof(buf), "%s", on_state);

20: else

21: len = snprintf(buf, sizeof(buf), "%s", off_state);

22:

23: buf[sizeof(buf) - 1] = '\0';

24: len = write(g_fds[REQUEST_STATE], buf, len);

25: if(len 0) {

26: failure:

27: LOGE("Failed setting last user activity: g_error=%d\n", g_error);

28: }

29: return 0;

30: }

其頭文件power.h中:

1: #if__cplusplus

2: extern "C" { //注1

3: #endif

4: enum {

5: PARTIAL_WAKE_LOCK = 1, // the cpu stays on, but the screen is off

6: FULL_WAKE_LOCK = 2 // the screen is also on

7: };

8:

9: // while you have a lock held, the device will stay on at least at the

10: // level you request.

11: int acquire_wake_lock(int lock, const char* id);

12: int release_wake_lock(const char* id);

13:

14: // true if you want the screen on, false if you want it off

15: int set_screen_state(int on);

16:

17: // set how long to stay awake after the last user activity in seconds

18: int set_last_user_activity_timeout(int64_t delay);

19:

20:

21: #if __cplusplus

22: } // extern "C"

23: #endif

注1:

注1:extern表示其他的類已經(jīng)定義了這段代碼里面的內(nèi)容,這里只是做聲明。

"C”表示的一種編譯和連接規(guī)約,這里為下一步c++調(diào)用其做準(zhǔn)備.

比如void foo(int,int);該函數(shù)被C編譯器編譯后在庫(kù)中的名字為_foo,

而C++編譯器則會(huì)產(chǎn)生像_foo_int_int之類的名字用來(lái)支持函數(shù)重載和類型安全連接。

由于編譯后的名字不同,C++程序不能直接調(diào)用C函數(shù)。

因此C++提供了一個(gè)C連接交換指定符號(hào)extern“C”來(lái)解決這個(gè)問(wèn)題而不是一種語(yǔ)言。

C表示這段代碼可以是符合C語(yǔ)言的編譯和連接規(guī)約的任何語(yǔ)言,如Fortran、assembler等。

二、cpp構(gòu)成jni橋梁

一個(gè)CPP文件調(diào)用之,則需添加其頭文件,比如frameworks/base/core/jni/android_os_Power.cpp.

1: #include "JNIHelp.h"

2: #include "jni.h"

3: #include "android_runtime/AndroidRuntime.h"

4: #include hardware_legacy/power.h

5: namespace android{

6: ....

7:

8: //定義函數(shù):

9: static int setScreenState(JNIEnv *env, jobject clazz, jboolean on)

10: {

11: return set_screen_state(on);//以此實(shí)現(xiàn)cpp到c的調(diào)用

12: }

13:

14: static JNINativeMethod method_table[] = {//此處實(shí)現(xiàn)java對(duì)cpp的調(diào)用轉(zhuǎn)化 注2

15: { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },

16: { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },

17: { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },

18: { "setScreenState", "(Z)I", (void*)setScreenState },

19: { "shutdown", "()V", (void*)android_os_Power_shutdown },

20: { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },

21: };

22: int register_android_os_Power(JNIEnv *env) //此處注冊(cè)jni

23: { //向VM(即AndroidRuntime)登記 gMethods[]表格所含的本地函數(shù)

24: return AndroidRuntime::registerNativeMethods(

25: env, "android/os/Power",

26: method_table, NELEM(method_table));

27: }

28: };

注2:

typedef struct {

const char* name; //Java中函數(shù)的名字

const char* signature; //用字符串是描述了函數(shù)的參數(shù)和返回值

void* fnPtr; //函數(shù)指針,指向C函數(shù)

} JNINativeMethod;

其中比較難以理解的是第二個(gè)參數(shù),例如

"()V"

"(II)V"

"(Ljava/lang/String;Ljava/lang/String;)V"

實(shí)際上這些字符是與函數(shù)的參數(shù)類型一一對(duì)應(yīng)的。

"()" 中的字符表示參數(shù),后面的則代表返回值。例如"()V" 就表示void Func();

"(II)V" 表示 void Func(int, int);

具體的每一個(gè)字符的對(duì)應(yīng)關(guān)系如下

字符 Java類型 C類型

V void void

Z jboolean boolean

I jint int

J jlong long

D jdouble double

F jfloat float

B jbyte byte

C jchar char

S jshort short

數(shù)組則以"["開始,用兩個(gè)字符表示

[I jintArray int[]

[F jfloatArray float[]

[B jbyteArray byte[]

[C jcharArray char[]

[S jshortArray short[]

[D jdoubleArray double[]

[J jlongArray long[]

[Z jbooleanArray boolean[]

上面的都是基本類型。如果Java函數(shù)的參數(shù)是class,則以"L"開頭,以";"結(jié)尾中間是用"/" 隔開的包及類名。而其對(duì)應(yīng)的C函數(shù)名的參數(shù)則為jobject. 一個(gè)例外是String類,其對(duì)應(yīng)的類為jstring

Ljava/lang/String; String jstring

Ljava/net/Socket; Socket jobject

如果JAVA函數(shù)位于一個(gè)嵌入類,則用$作為類名間的分隔符。

例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

三、java的封裝實(shí)現(xiàn)

frameworks/base/core/java/android/os/Power.java //此處路徑跟cpp中注冊(cè)jni處的路徑是一致的.待細(xì)研究是否有關(guān)系

1: package android.os;

2: public class Power

3: {

4: ...

5: public static native int setScreenState(boolean on); //被native修飾的表示調(diào)用了非java語(yǔ)言的本地方法

6: ...

7: }

四、java中對(duì)其調(diào)用

frameworks/base/services/java/com/android/server/PowerManagerService.java

import android.os.Power;

public class PowerManagerService extends IPowerManager.Stub

implements LocalPowerManager, Watchdog.Monitor {

...

int err = Power.setScreenState(on);

...

}

android jni怎么使用

安裝NDK,在eclipse里設(shè)置關(guān)聯(lián)

首先你在類里面寫native方法,如native String printHello();

設(shè)置靜態(tài)方法塊?調(diào)用so文件,如static {System.loadLibrary("jnitest");}

右鍵工程-android tools-add native support

編寫C/C++文件,對(duì)應(yīng).c/.cpp,如

JNIEXPORT jstring JNICALL Java_com_example_jnit_MainActivity_printHello

(JNIEnv *env, jobject obj){

return env-NewStringUTF("Hello world !");

}

編譯運(yùn)行

android 為什么要使用jni

android的jni可以使用c/c++來(lái)開發(fā),相比java而言,運(yùn)行的效率提高了很多,特別是在做一些圖像算法,或者游戲邏輯的時(shí)候,使用jni將大大的提高效率。比如某個(gè)游戲要采用opengl,同樣加載一個(gè)由1000個(gè)多邊形組成的3d模型,jni要比java運(yùn)算快好幾倍,這樣就保證了游戲運(yùn)行的fps不會(huì)太低。

另外一個(gè)好處就是內(nèi)存管理上面,java的內(nèi)存管理全部由虛擬機(jī)來(lái)管理,C++由程序員來(lái)管理,利用率上面就好多了。

等等其他優(yōu)點(diǎn)。

既然這么多的優(yōu)點(diǎn),為什么一個(gè)android程序不采用純c來(lái)開發(fā)呢?因?yàn)槭莂ndroid的 UI framework采用java,所以,在UI上面還是采用java來(lái)開發(fā)。

如何在Android下使用JNI

1.引言

我們知道,Android系統(tǒng)的底層庫(kù)由c/c++編寫,上層Android應(yīng)用程序通過(guò)Java虛擬機(jī)調(diào)用底層接口,銜接底層c/c++庫(kù)與Java應(yīng)用程序間的接口正是JNI(JavaNative Interface)。本文描述了如何在ubuntu下配置AndroidJNI的開發(fā)環(huán)境,以及如何編寫一個(gè)簡(jiǎn)單的c函數(shù)庫(kù)和JNI接口,并通過(guò)編寫Java程序調(diào)用這些接口,最終運(yùn)行在模擬器上的過(guò)程。

2.環(huán)境配置

2.1.安裝jdk1.6

(1)從jdk官方網(wǎng)站下載jdk-6u29-linux-i586.bin文件。

(2)執(zhí)行jdk安裝文件

[html] view plaincopyprint?

01.$chmod a+x jdk-6u29-linux-i586.bin

02.$jdk-6u29-linux-i586.bin

$chmod a+x jdk-6u29-linux-i586.bin

$jdk-6u29-linux-i586.bin

(3)配置jdk環(huán)境變量

[html] view plaincopyprint?

01.$sudo vim /etc/profile

02.#JAVAEVIRENMENT

03.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29

04.exportJRE_HOME=$JAVA_HOME/jre

05.exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

06.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

$sudo vim /etc/profile

#JAVAEVIRENMENT

exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29

exportJRE_HOME=$JAVA_HOME/jre

exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

保存后退出編輯,并重啟系統(tǒng)。

(4)驗(yàn)證安裝

[html] view plaincopyprint?

01.$java -version

02.javaversion "1.6.0_29"

03.Java(TM)SE Runtime Environment (build 1.6.0_29-b11)

04.JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)

05.$javah

06.用法:javah[選項(xiàng)]類

07.其中[選項(xiàng)]包括:

08.-help輸出此幫助消息并退出

09.-classpath路徑用于裝入類的路徑

10.-bootclasspath路徑用于裝入引導(dǎo)類的路徑

11.-d目錄輸出目錄

12.-o文件輸出文件(只能使用-d或-o中的一個(gè))

13.-jni生成JNI樣式的頭文件(默認(rèn))

14.-version輸出版本信息

15.-verbose啟用詳細(xì)輸出

16.-force始終寫入輸出文件

17.使用全限定名稱指定類(例

18.如,java.lang.Object)。

$java -version

javaversion "1.6.0_29"

Java(TM)SE Runtime Environment (build 1.6.0_29-b11)

JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)

$javah

用法:javah[選項(xiàng)]類

其中[選項(xiàng)]包括:

-help輸出此幫助消息并退出

-classpath路徑用于裝入類的路徑

-bootclasspath路徑用于裝入引導(dǎo)類的路徑

-d目錄輸出目錄

-o文件輸出文件(只能使用-d或-o中的一個(gè))

-jni生成JNI樣式的頭文件(默認(rèn))

-version輸出版本信息

-verbose啟用詳細(xì)輸出

-force始終寫入輸出文件

使用全限定名稱指定類(例

如,java.lang.Object)。2.2.安裝android應(yīng)用程序開發(fā)環(huán)境

ubuntu下安裝android應(yīng)用程序開發(fā)環(huán)境與windows類似,依次安裝好以下軟件即可:

(1)Eclipse

(2)ADT

(3)AndroidSDK

與windows下安裝唯一不同的一點(diǎn)是,下載這些軟件的時(shí)候要下載Linux版本的安裝包。

安裝好以上android應(yīng)用程序的開發(fā)環(huán)境后,還可以選擇是否需要配置emulator和adb工具的環(huán)境變量,以方便在進(jìn)行JNI開發(fā)的時(shí)候使用。配置步驟如下:

把emulator所在目錄android-sdk-linux/tools以及adb所在目錄android-sdk-linux/platform-tools添加到環(huán)境變量中,android-sdk-linux指androidsdk安裝包android-sdk_rxx-linux的解壓目錄。

[plain] view plaincopyprint?

01.$sudo vim /etc/profile

02.exportPATH=~/software/android/android-sdk-linux/tools:$PATH

03. exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH

$sudo vim /etc/profile

exportPATH=~/software/android/android-sdk-linux/tools:$PATH

exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH

編輯完畢后退出,并重啟生效。

2.3.安裝NDK

NDK是由android提供的編譯android本地代碼的一個(gè)工具。

(1)從androidndk官網(wǎng)下載ndk,目前最新版本為android-ndk-r6b-linux-x86.tar.bz2.

(2)解壓ndk到工作目錄:

[plain] view plaincopyprint?

01.$tar -xvf android-ndk-r6b-linux-x86.tar.bz2

02.$sudo mv android-ndk-r6b /usr/local/ndk

$tar -xvf android-ndk-r6b-linux-x86.tar.bz2

$sudo mv android-ndk-r6b /usr/local/ndk

(3)設(shè)置ndk環(huán)境變量

[plain] view plaincopyprint?

01.$sudo vim /etc/profile

02.exportPATH=/usr/local/ndk:$PATH

$sudo vim /etc/profile

exportPATH=/usr/local/ndk:$PATH

編輯完畢后保存退出,并重啟生效

(4)驗(yàn)證安裝

[plain] view plaincopyprint?

01.$ cd/usr/local/ndk/samples/hello-jni/

02.$ ndk-build

03.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver

04.Gdbsetup : libs/armeabi/gdb.setup

05.Install : libhello-jni.so = libs/armeabi/libhello-jni.so

$ cd/usr/local/ndk/samples/hello-jni/

$ ndk-build

Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver

Gdbsetup : libs/armeabi/gdb.setup

Install : libhello-jni.so = libs/armeabi/libhello-jni.so

3.JNI實(shí)現(xiàn)

我們需要定義一個(gè)符合JNI接口規(guī)范的c/c++接口,這個(gè)接口不用太復(fù)雜,例如輸出一個(gè)字符串。接下來(lái),則需要把c/c++接口的代碼文件編譯成共享庫(kù)(動(dòng)態(tài)庫(kù)).so文件,并放到模擬器的相關(guān)目錄下。最后,啟動(dòng)Java應(yīng)用程序,就可以看到最終效果了。

3.1.編寫Java應(yīng)用程序代碼

(1)啟動(dòng)Eclipse,新建android工程

Project:JNITest

Package:org.tonny.jni

Activity:JNITest

(2)編輯資源文件

編輯res/values/strings.xml文件如下:

編輯res/layout/main.xml文件

我們?cè)谥鹘缑嫔咸砑恿艘粋€(gè)EditText控件和一個(gè)Button控件。

(3)編輯JNITest.java文件

 

static表示在系統(tǒng)第一次加載類的時(shí)候,先執(zhí)行這一段代碼,在這里表示加載動(dòng)態(tài)庫(kù)libJNITest.so文件。

再看這一段:

[java] view plaincopyprint?

01.privatenativeString GetReply();

privatenativeString GetReply();

native表示這個(gè)方法由本地代碼定義,需要通過(guò)jni接口調(diào)用本地c/c++代碼。

[java] view plaincopyprint?

01.publicvoidonClick(View arg0) {

02.edtName.setText(reply);

03.}

publicvoidonClick(View arg0) {

edtName.setText(reply);

}

這段代碼表示點(diǎn)擊按鈕后,把native方法的返回的字符串顯示到EditText控件。

(4)編譯工程,生成.class文件。

3.2.用javah工具生成符合JNI規(guī)范的c語(yǔ)言頭文件

在終端中,進(jìn)入android工程所在的bin目錄

[plain] view plaincopyprint?

01.$cd ~/project/Android/JNITest/bin

$cd ~/project/Android/JNITest/bin

我們用ls命令查看,可以看到bin目錄下有個(gè)classes目錄,其目錄結(jié)構(gòu)為classes/org/tonny/jni,即classes的子目錄結(jié)構(gòu)是android工程的包名org.tonny.jni。請(qǐng)注意,下面我們準(zhǔn)備執(zhí)行javah命令的時(shí)候,必須進(jìn)入到org/tonny/jni的上級(jí)目錄,即classes目錄,否則javah會(huì)提示找不到相關(guān)的java類。

下面繼續(xù):

[plain] view plaincopyprint?

01.$cd classes

02.$javah org.tonny.jni.JNITest

03.$ls

04.org org_tonny_jni_JNITest.h

$cd classes

$javah org.tonny.jni.JNITest

$ls

org org_tonny_jni_JNITest.h

執(zhí)行javahorg.tonny.jni.JNITest命令,在classes目錄下會(huì)生成org_tonny_jni_JNITest.h頭文件。如果不進(jìn)入到classes目錄下的話,也可以這樣:

[plain] view plaincopyprint?

01.$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest

$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest

-classpath 參數(shù)表示裝載類的目錄。

3.3.編寫c/c++代碼

生成org_tonny_jni_JNITest.h頭文件后,我們就可以編寫相應(yīng)的函數(shù)代碼了。下面在android工程目錄下新建jni目錄,即~/project/Android/JNITest/jni,把org_tonny_jni_JNITest.h頭文件拷貝到j(luò)ni目錄下,并在jni目錄下新建org_tonny_jni_JNITest.c文件,編輯代碼如下:

[cpp] view plaincopyprint?

01.#includejni.h

02.#includestring.h

03.#include"org_tonny_jni_JNITest.h"

04.

05.

06.JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply

07.(JNIEnv *env, jobject obj){

08.return(*env)-NewStringUTF(env,(char*)"Hello,JNITest");

09.}

#includejni.h

#includestring.h

#include"org_tonny_jni_JNITest.h"

JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply

(JNIEnv *env, jobject obj){

return(*env)-NewStringUTF(env,(char*)"Hello,JNITest");

}

我們可以看到,該函數(shù)的實(shí)現(xiàn)相當(dāng)簡(jiǎn)單,返回一個(gè)字符串為:"Hello,JNITest"

3.4.編寫Android.mk文件

在~/project/Android/JNITest/jni目錄下新建Android.mk文件,android可以根據(jù)這個(gè)文件的編譯參數(shù)編譯模塊。編輯Android.mk文件如下:

[plain] view plaincopyprint?

01.LOCAL_PATH:= $(call my-dir)

02.include$(CLEAR_VARS)

03.LOCAL_MODULE := libJNITest

04.LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c

05.include$(BUILD_SHARED_LIBRARY)

LOCAL_PATH:= $(call my-dir)

include$(CLEAR_VARS)

LOCAL_MODULE := libJNITest

LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c

include$(BUILD_SHARED_LIBRARY)

LOCAL_MODULE表示編譯的動(dòng)態(tài)庫(kù)名稱

LOCAL_SRC_FILES 表示源代碼文件

3.5.用ndk工具編譯并生成.so文件

進(jìn)入到JNITest的工程目錄,執(zhí)行ndk-build命令即可生成libJNITest.so文件。

[plain] view plaincopyprint?

01.$cd ~/project/Android/JNITest/

02.$ndk-build

03.Invalidattribute name:

04.package

05.Install : libJNITest.so = libs/armeabi/libJNITest.so

$cd ~/project/Android/JNITest/

$ndk-build

Invalidattribute name:

package

Install : libJNITest.so = libs/armeabi/libJNITest.so

可以看到,在工程目錄的libs/armeabi目錄下生成了libJNITest.so文件。

3.6.在模擬器上運(yùn)行

(1)首先,我們把a(bǔ)ndroid模擬器啟動(dòng)起來(lái)。進(jìn)入到emulator所在目錄,執(zhí)行emulator命令:

[plain] view plaincopyprint?

01.$cd ~/software/android/android-sdk-linux/tools

02.$./emulator @AVD-2.3.3-V10 -partition-size 512

$cd ~/software/android/android-sdk-linux/tools

$./emulator @AVD-2.3.3-V10 -partition-size 512

AVD-2.3.3-V10表示你的模擬器名稱,與在Eclipse-AVDManager下的AVDName對(duì)應(yīng),-partition-size表示模擬器的存儲(chǔ)設(shè)備容量。

(2)接下來(lái),我們需要把libJNITest.so文件拷貝到模擬器的/system/lib目錄下,執(zhí)行以下命令:

[plain] view plaincopyprint?

01.$cd ~/project/Android/JNITest/libs/armeabi/

02.$adb remount

03.$adb push libJNITest.so /system/lib

04.80 KB/s (10084 bytes in 0.121s)

$cd ~/project/Android/JNITest/libs/armeabi/

$adb remount

$adb push libJNITest.so /system/lib

80 KB/s (10084 bytes in 0.121s)

當(dāng)在終端上看到有80 KB/s (10084 bytes in 0.121s)傳輸速度等信息的時(shí)候,說(shuō)明拷貝成功。

(3)在終端上執(zhí)行JNITest程序,這個(gè)我們可以在Eclipse下,右鍵點(diǎn)擊JNITest工程,RunAs-Android Application,即可在模擬器上啟動(dòng)程序


本文標(biāo)題:androidjni,Androidjni編程
網(wǎng)頁(yè)路徑:http://weahome.cn/article/hosdge.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部