學習JNI--Android下使用JNI調用C

來源:互聯網
上載者:User

標籤:android   java   jni   ndk   library   

一、什麼是JNI:

JNIJava Native Interface的縮寫,中文為JAVA本地調用。從Java1.1開始,Java Native Interface(JNI)標準成為java平台的一部分,它允許Java代碼和其他語言寫的代碼進行互動。JNI一開始是為了本地已編譯語言,尤其是C和C++而設計的,但是它並不妨礙你使用其他語言,只要呼叫慣例受支援就可以了。

1、使用JNI的好處:

a、可以使用JNI來實現“本地方法”(native methods),並在JAVA程式中調用它們,一般是在java中調用C的函數;相反的也可以用C來調用Java中的方法,這樣可以複用很多以前寫過的代碼。

b、JNI支援一個“調用介面”(invocation interface),它允許你把一個JVM嵌入到本地程式中。本地程式可以連結一個實現了JVM的本地庫,然後使用“調用介面”執行JAVA語言編寫的軟體模組。

2、使用JNI的副作用:

a、眾所周知的Java的可移植性在使用JNI之後可能會被破壞,程式不再跨平台,原因很簡單,一個作業系統上的本地方法很可能不能在另一個平台上正常運行,那麼導致使用了這些本地方法的Java代碼也同樣無法在別的平台上運行。

b、程式不再是絕對安全的,本地代碼的不當使用可能導致整個程式崩潰。

一個比較好的做法是,讓調用的本地方法只集中在你寫的工程的少數幾個類中,這樣可以降低Java和C代碼的耦合性,也提高了代碼的可維護性。


二、Java調用C來實現簡單的HelloWorld:(以Android+eclipse為例)


好吧,又是HelloWorld!


這裡我們以Android工程為例。

在真正開始做之前,還是先來瞭解一下基本流程:

1、先建立一個Java檔案:HelloWorld.java,並且聲明一個本地方法,注意要加上一個關鍵字native,在這裡我們不寫他的實現,具體實現交給C:

public native void helloworld();

2、然後我們可以使用javah指令來產生對應java檔案的.h標頭檔(C來使用):

這裡我預設已經搭好了環境,如果沒有可以參看:http://www.cnblogs.com/baronzhao/archive/2012/07/10/2585181.html

開啟cygwin,我們首先進入到對應工程的src目錄下,在我這裡是使用的cygwin開啟的目錄:/cygdrive/d/Android_Workspace/JNI_day19/Exercise/src

然後執行:javah -jni com.example.exercise.MainActivity,其中com.example.exercise.MainActivity為MainActivity.java的全類名

正常的話就會在src目錄下產生一個.h的標頭檔:com_example_exercise_MainActivity.h,其內容為:

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


實際上上面那些endif之類的宏定義都不是必須的,關鍵的部分只有一個include<jni.h>和JNIEXPORT jstring JNICALL Java_com_example_exercise_MainActivity_getStr(JNIEnv *, jobject);

其中,jni.h是jni定義的對應java中的類型和方法的c中的對應類型和函數的標頭檔,這個是必須有的。

其次,JNIEXPORT jstring JNICALL Java_com_example_exercise_MainActivity_getStr(JNIEnv *, jobject); 這一句除了JNIEXPORT可以去掉之外,其他的必須一致保留,大概寫法就是:傳回型別(這裡是void) java_全類名(.換成_)_方法名(JNIEnv* env,jobject ojb)


3、在工程中建立一個名為jni的檔案夾,並將剛才產生的.h檔案剪下到jni檔案夾中,並寫好相應的.c/.cpp代碼。

這裡有一個小細節就是,有時候eclipse會在#include <jni.h>這裡報一個黃色的問號的警告,找不到這個對應的jni.h檔案,我們可以右鍵點擊工程,然後點擊AndroidTools->AddNativeSupport,如:



點擊完之後會彈出一個對話方塊:



這裡我們可以直接寫入我們之後想產生的so檔案名稱,這個檔案名稱跟.c檔案關聯,這裡我們選擇hello,點擊Finish之後,我們發現eclipse自動在jni檔案夾中產生了兩個新的檔案:Android.mkhello.cpp檔案

其中Android.mk檔案為:

 

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) #對應的是打包成函數庫的名字 LOCAL_MODULE    := hello #src目錄,對應的是c代碼的檔案 LOCAL_SRC_FILES := hello.cpp include $(BUILD_SHARED_LIBRARY)

這個檔案的作用是指定產生.so檔案的規則。

而hello.cpp檔案則是我們需要實際寫c代碼的檔案,在這裡面,我們將實現剛才標頭檔中的jstring JNICALL Java_com_example_exercise_MainActivity_getStr(JNIEnv *, jobject);這個函數。

實際上這裡要做的也很簡單,我們的目的就是想在這個函數裡返回一個字串:"hello from C!",實際上這裡就需要用到jni.h中定義的一個方法了:jstring     (*NewStringUTF)(JNIEnv*, const char*);它的作用就是返回一個jstring字串

#include <stdio.h>#include "com_example_err_MainActivity.h"//jstring     (*NewStringUTF)(JNIEnv*, const char*);JNIEXPORT jstring JNICALL Java_com_example_err_MainActivity_helloWorld(JNIEnv * env, jobject obj) {return (*env).NewStringUTF("hello from c!");}


4、之後我們需要做的就是產生.so庫檔案,在系統內容變數配置好了的情況下,直接開啟cmd,進入到對應的工程目錄下,執行ndk-build即可產生對應的庫檔案:libhello.so。


實際上這個檔案會出現在工程檔案夾的:obj/local/armeabi/檔案夾下。

至此,函數庫就已經產生好了,接下來的工作就是調用這個函數

5、在MainActiviy.java中調用這個.so檔案。

我們可以再MainActiviy.java檔案下,定義一個Button,對應點擊事件cilck,每當點擊的時候,就調用這個方法,將其返回的字串"hello from c!"以Toast的形式列印出來,在這之前需要注意的是,我們需要先載入剛才產生的.so庫檔案,這裡使用一個static塊來載入,System.loadLibrary("hello");,注意這裡我們不需要寫libhello.so,而只需要寫hello即可:

public class MainActivity extends Activity {public native String helloWorld();static {System.loadLibrary("hello");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View view) {String helloWorld = helloWorld();System.out.println(helloWorld);Toast.makeText(getApplicationContext(), helloWorld, Toast.LENGTH_LONG).show();}}


效果:












學習JNI--Android下使用JNI調用C

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.