Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 學習JNI--Android下使用JNI調用C

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

編輯:關於Android編程

一、什麼是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 
	/* Header for class com_example_exercise_MainActivity */
	#ifndef _Included_com_example_exercise_MainActivity
	#define _Included_com_example_exercise_MainActivity
	#ifdef __cplusplus
	extern "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和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文件,我們可以右鍵點擊工程,然後點擊AndroidTools->AddNativeSupport,如下圖:

\


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

\


這裡我們可以直接寫入我們之後想生成的so文件名,這個文件名跟.c文件關聯,這裡我們選擇hello,點擊Finish之後,我們發現eclipse自動在jni文件夾中生成了兩個新的文件:Android.mkhello.cpp<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPs7EvP48L3A+CjxwPsbk1tBBbmRyb2lkLm1rzsS8/s6qo7o8L3A+CjxwPiA8L3A+CjxwcmUgY2xhc3M9"brush:java;">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 
	#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");
		}

		@Override
		protected 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();
		}
	}


效果:












  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved