日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android中JNI的使用方法

發布時間:2023/12/19 Android 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android中JNI的使用方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android中JNI的使用方法

首先看一下Android平臺的框架圖:

    

?

  可以看到Android上層的ApplicationApplicationFramework都是使用Java編寫,

底層包括系統和使用眾多的LIiraries都是C/C++編寫的。

  所以上層Java要調用底層的C/C++函數庫必須通過JavaJNI來實現。

下面將學習Android是如何通過Jni來實現JavaC/C++函數的調用。以HelloWorld程序為例:

第一步:

使用Java編寫HelloWorld? Android應用程序:

package com.lucyfyr; import android.app.Activity; import android.os.Bundle; import android.util.Log;public class HelloWorld extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Log.v("dufresne", printJNI("I am HelloWorld Activity")); }static{//加載庫文件System.loadLibrary("HelloWorldJni");}//聲明原生函數 參數為String類型 返回類型為Stringprivate native String printJNI(String inputStr); }

?

  這一步我們可以使用eclipse來生成一個App

因為eclipse會自動為我們編譯此Java文件,后面要是用到。

?

第二步:

  生成共享庫的頭文件:

  進入到eclipse生成的Android Project中 :/HelloWorld/bin/classes/com/lucyfyr/ 下:

  可以看到里面后很多后綴為.class的文件,就是eclipse為我們自動編譯好了的java文件,其中就有:

    HelloWorld.class文件。

  退回到classes一級目錄:/HelloWorld/bin/classes/?

執行如下命令:

  javah com.lucyfyr.HelloWorld

  生成文件:com_lucyfyr_HelloWorld.h

?

/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_lucyfyr_HelloWorld */ #ifndef _Included_com_lucyfyr_HelloWorld #define _Included_com_lucyfyr_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: com_lucyfyr_HelloWorld * Method: printJNI * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif

?

  可以看到自動生成對應的函數:Java_com_lucyfyr_HelloWorld_printJNI

    Java_ + 包名(com.lucyfyr+ 類名(HelloWorld) + 接口名(printJNI):必須要按此JNI規范來操作;

  java虛擬機就可以在com.simon.HelloWorld類調用printJNI接口的時候自動找到這個C實現的Native函數調用。

  當然函數名太長,可以在.c文件中通過函數名映射表來實現簡化。

?

第三步:

實現JNI原生函數源文件:

新建com_lucyfyr_HelloWorld.c文件:

?

#include <jni.h> #define LOG_TAG "HelloWorld" #include <utils/Log.h> /* Native interface, it will be call in java code */ JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI(JNIEnv *env, jobject obj,jstring inputStr) {LOGI("dufresne Hello World From libhelloworld.so!");// 從 instring 字符串取得指向字符串 UTF 編碼的指針const char *str =(const char *)(*env)->GetStringUTFChars( env,inputStr, JNI_FALSE );LOGI("dufresne--->%s",(const char *)str);// 通知虛擬機本地代碼不再需要通過 str 訪問 Java 字符串。(*env)->ReleaseStringUTFChars(env, inputStr, (const char *)str );return (*env)->NewStringUTF(env, "Hello World! I am Native interface"); } /* This function will be call when the library first be load. * You can do some init in the libray. return which version jni it support. */ jint JNI_OnLoad(JavaVM* vm, void* reserved) {void *venv;LOGI("dufresne----->JNI_OnLoad!");if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {LOGE("dufresne--->ERROR: GetEnv failed");return -1;}   return JNI_VERSION_1_4; }

?

  OnLoadJava_com_lucyfyr_HelloWorld_printJNI

函數里面做一些log輸出 注意JNI中的log輸出的不同。

  JNI_OnLoad函數JNI規范定義的,當共享庫第一次被加載的時候會被回調,

這個函數里面可以進行一些初始化工作,比如注冊函數映射表,緩存一些變量等,

最后返回當前環境所支持的JNI環境。本例只是簡單的返回當前JNI環境。

?

第四步:

編譯生成so

  編譯com_lucyfyr_HelloWorld.cso庫可以和app一起編譯,也可以都單獨編譯。

在當前目錄下建立jni文件夾:HelloWorld/jni/

  下建立Android.mk ,并將com_lucyfyr_HelloWorld.c com_lucyfyr_HelloWorld.h 拷貝到進去

編寫編譯生成so庫的Android.mk文件:

?

LOCAL_PATH:= $(call my-dir) # 一個完整模塊編譯 include $(CLEAR_VARS) LOCAL_SRC_FILES:=com_lucyfyr_HelloWorld.c LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) LOCAL_MODULE := libHelloWorldJni LOCAL_SHARED_LIBRARIES := libutils LOCAL_PRELINK_MODULE := false LOCAL_MODULE_TAGS :=optional include $(BUILD_SHARED_LIBRARY)

?

系統變量解析:

  LOCAL_PATH - 編譯時的目錄   

  $(call 目錄,目錄….) 目錄引入操作符     如該目錄下有個文件夾名稱 src,則可以這樣寫 $(call src),那么就會得到 src 目錄的完整路徑

  include $(CLEAR_VARS) -清除之前的一些系統變量  

  LOCAL_MODULE - 編譯生成的目標對象  

  LOCAL_SRC_FILES - 編譯的源文件  

  LOCAL_C_INCLUDES - 需要包含的頭文件目錄  

  LOCAL_SHARED_LIBRARIES - 鏈接時需要的外部庫  

  LOCAL_PRELINK_MODULE - 是否需要prelink處理   i

  nclude$BUILD_SHARED_LIBRARY- 指明要編譯成動態庫

  android.mk編譯模塊添加具體方法參考:http://blog.csdn.net/yili_xie/article/details/4906865

?

編譯此模塊:輸入編譯命令

  ./makeMtk mm packages/apps/HelloWorld/jni/

  上面是我的工程根目錄編譯命令。具體編譯方式根據自己系統要求執行。

編譯輸出: libHelloWorldJni.so (system/lib中視具體而定)

  此時庫文件編譯好了可以使用,如果在eclipse中模擬器上使用,需要將 libHelloWorldJni.so導入到system/lib 下,

  或者對應appdata/data/com.lucyfyr/lib/下;

但是在導入system/lib 下的時候,卻始終提示out of memory。于是網上說使用emulator去搞,

  但是此命令使用起來卻有問題,始終沒有解決。但是可以導入到data/data/com.lucyfyr/lib/下使用。但是我這里直接在真機上弄的。

看一下HelloWorldAndroid.mk文件的配置

  其中存在:

    include $(LOCAL_PATH)/jni/Android.mk 表示編譯庫文件

    LOCAL_JNI_SHARED_LIBRARIES := libHelloWorldJni 表示app依賴庫,打包的時候會一起打包。

?

第五步:

驗證執行

  將編譯好的apk安裝到手機上

  使用adb push到手機上去需要自己去導入庫文件libHelloWorldJni.sodata/data/com.lucyfyr/lib/

  使用adb install方式安裝則會自動導入。

啟動HelloWorld :輸入命令?adb logcat |grep dufresne

輸出log如下:

  I/HelloWorld(28500): dufresne Hello World From libhelloworld.so!

  I/HelloWorld(28500): dufresne--->I am HelloWorld Activity

  V/dufresne(28500): Hello World! I am Native interface

符合調用打印順序正確。

?

以上通過一個簡單的例子學習了Android如何編寫編譯C庫文件,以及如何使用庫文件。

對于JNI的使用其中還涉及到其他方面的一些知識:C++接口如何調用,函數名注冊表怎么回事,

參數類型如何匹配,JNI如何調用Java中的方法java<--->JNI等。

(用于參考)

//---------------教程2------------------------------------------

我使用GNUStep,下載地址http://www.gnustep.org/experience/Windows.html。

?

下載安裝后,驗證是否成功。打開GNUstep->Shell,輸入make -v 和 gcc -v命令,如圖所示。

?

?

下載NDK,地址http://developer.android.com/tools/sdk/ndk/index.html。下載完后解壓即可。

?

配置ndk環境變量,gnustep是模擬linux的環境的,打開gnustep的安裝目錄下的G:softinstallGNUstepGNUstepGNUstep.conf文件,添加以下內容:

?

NDK=/g/softinstall/Android/android-ndk-r8b

?

export=NDK

?

說明如果不知道ndk目錄在linux下應該是在哪里,你可以打開gnustep的命令窗口,輸入mount,就可以找到對應的盤符。

?

驗證環境變量,如下圖。

?

?

以上就配置成功了。

?

下載進入正題啦。Jni的開發步驟。

?

打開eclipse,新建工程名為testJni。在activity中添加以下代碼

?

package com.xzw.jni; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.support.v4.app.NavUtils; /** * * @author XuZhiwei (xuzhiwei@gmail.com) * sina:http://weibo.com/xzw1989 * * Create at 2012-8-30 上午10:49:45 */ public class MainActivity extends Activity { @Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public native String hello(); static{ System.loadLibrary("testJni"); } }

?

編譯后的文件在bin目錄下,通過javah命令生成c/c++的文件頭。如下圖 ?

?

?

?

?

會在項目目錄下生成jni/com_xzw_jni_TestJni.h。

?

頭文件代碼如下:

?

/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_xzw_jni_TestJni */ #ifndef _Included_com_xzw_jni_TestJni #define _Included_com_xzw_jni_TestJni #ifdef __cplusplus extern "C" { #endif /* * Class: com_xzw_jni_TestJni * Method: hello * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_xzw_jni_TestJni_hello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif

?

根據頭文件編寫c代碼

?

#include <string.h> #include <jni.h> jstring Java_com_xzw_jni_TestJni_hello (JNIEnv* env, jobject thiz){ return (*env)->NewStringUTF(env, "哈哈完成自動化編譯 !"); }

?

接下來編寫 Android.mk,該文件可以直接從NDK的samples下的hello-jni的jni文件下直接靠過來改改就可以了。也貼下代碼哈。

?

# Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := testJni LOCAL_SRC_FILES := testJni.c include $(BUILD_SHARED_LIBRARY)

?

其中你只需要該LOCAL_MODULE和LOCAL_SRC_FILES就可以了。

?

說明:LOCAL_MODULE是描述模塊的,用來給java調用的模塊名,會生成對應的libtestJni.so

?

LOCAL_SRC_FILES就是源文件啦,多個文件空格隔開即可。

?

接下來,我們要開始編譯生成so文件咯。

?

打開gnustep的命令窗口,進入到項目底下,輸入$NDK/ndk-build命令,即可自動生成libs/armeabi/libtestJni.so文件。

?

?

接下來就是java調用來。直接上代碼

?

?

package com.xzw.jni; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.support.v4.app.NavUtils; /** * * @author XuZhiwei (xuzhiwei@gmail.com) * sina:http://weibo.com/xzw1989 * * Create at 2012-8-30 上午10:49:45 */ public class TestJni extends Activity { @Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText(hello()); setContentView(tv); } public native String hello(); static{ System.loadLibrary("testJni"); } }

?

運行結果如下

?

?

本文出自 “Mr.Xu” 博客,請務必保留此出處http://xuzhiwei.blog.51cto.com/978424/976839

?

?

轉載于:https://www.cnblogs.com/navy-wang/p/3272626.html

總結

以上是生活随笔為你收集整理的Android中JNI的使用方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。