標籤:android ndk jni c語言
轉載請註明出處:http://blog.csdn.net/l1028386804/article/details/47405683
這裡,我將用一個小例子的形式來協助大家初探JNI的用法,首先,大家要先搭建好NDK環境,請大家先閱讀《Android之——NDK環境搭建》一文。
一、實現
這個小例子實現的功能就是,通過Android中的java代碼來調用C代碼實現java代碼與C代碼之間的互動。
1、布局檔案
我們首先在布局檔案activity_main.xml中,添加一個按鈕控制項,並給按鈕控制項設定一個點擊事件,具體代碼如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="click" android:text="調用C代碼" /></RelativeLayout>
2、完善類MainActivity1)定義本地方法
要實現JNI方法的調用,首先要在MainActivity中定義一個本地方法,java中本地方法是以native關鍵字定義的。
具體代碼如下:
public native String helloFromC()
2)用javah命令產生,h標頭檔
用javah命令產生,h標頭檔,前提是要配置好java環境變數,這裡我就不說怎麼配置環境變數了,相信稍微瞭解java的同學都知道。我們通過cmd命令列進入到MainActivity包所在的目錄。
如:
然後輸入命令
javah -encoding UTF-8 包名.類名
其中,-encoding UTF-8是指定產生的.h標頭檔的編碼為UTF-8,包名是類所在的包,類名就是包含本地方法的類名,類名不帶有.java尾碼。
如:
此時,在目前的目錄下會產生一個.h標頭檔。
如:
3)實現C代碼
com_lyz_hdk_helloworld_MainActivity.h中產生的程式碼如下:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_lyz_hdk_helloworld_MainActivity */#ifndef _Included_com_lyz_hdk_helloworld_MainActivity#define _Included_com_lyz_hdk_helloworld_MainActivity#ifdef __cplusplusextern "C" {#endif/* * Class: com_lyz_hdk_helloworld_MainActivity * Method: helloFromC * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
在Android項目的根目錄建立JNI目錄,將com_lyz_hdk_helloworld_MainActivity.h檔案拷貝到jni目錄下,然後建立hello.c檔案,引入所需要的庫,
如下所示:
#include <stdio.h>#include <jni.h>#include "com_lyz_hdk_helloworld_MainActivity.h"
在hello.c中實現Java_com_lyz_hdk_helloworld_MainActivity_helloFromC方法,返回相應的字串
具體代碼如下:
JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){char *str = "hello from c";jstring jstr = (**env).NewStringUTF(env, str);return jstr;}hello.c完整代碼如下:
#include <stdio.h>#include <jni.h>#include "com_lyz_hdk_helloworld_MainActivity.h"JNIEXPORT jstring JNICALL Java_com_lyz_hdk_helloworld_MainActivity_helloFromC(JNIEnv *env , jobject obj){char *str = "hello from c";jstring jstr = (**env).NewStringUTF(env, str);return jstr;}
4)在jni目錄下建立Android.mk
這個檔案是Android實現JNI所必須的檔案,而且檔案名稱固定為Android.mk不能更改。這個檔案裡的內容我們可以到ndk的docs目錄下找到ANDROID-MK.html檔案,開啟這個檔案,找到以下程式碼片段,拷貝到Android.mk檔案中,注意要每一行不要有空格。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c include $(BUILD_SHARED_LIBRARY)
其在檔案中的位置如:
其中:
LOCAL_PATH := $(call my-dir):當前檔案所存在的目錄
call my-dir 得到當前我的檔案的目錄
include $(CLEAR_VARS):配置資訊初始化
LOCAL_MODULE := hello-jni:指定編譯完成後的2進位值可執行檔的名稱
LOCAL_SRC_FILES := hello-jni.c:指定你要編譯哪些C的源檔案
include $(BUILD_SHARED_LIBRARY):編譯成動態連結庫檔案
include $(BUILD_STATIC_LIBRARY):編譯成靜態連結庫檔案
我要編譯的檔案是hello.c,要產生的so為libhello.so所以我將上面的配置修改為以下代碼:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := helloLOCAL_SRC_FILES := hello.cinclude $(BUILD_SHARED_LIBRARY)
以上配置也就是Android.mk中的內容了。
如:
這時,我們項目的jni目錄下的檔案如所示:
5)編譯產生so動態連結程式庫
我們開啟cygwin,進入到項目的jni目錄下。
如:
執行命令ndk-build
如:
重新整理項目工程,會在libs目錄下自動產生一個.so動態連結程式庫,
如:
6)完善MainActivity
在MainActivity類中,寫一個靜態代碼塊,用於載入.so動態連結程式庫,注意,這裡我們產生的.so檔案是libhello.so,我們在載入這個.so檔案的時候,只需要傳入hello即可。
具體代碼實現如下:
//載入靜態代碼塊static{System.loadLibrary("hello");}在按鈕的點擊事件中調動本地方法,同時將結果Toast出來。
具體代碼如下:
public void click(View v){Toast.makeText(this, "c代碼的內容是:"+helloFromC(), Toast.LENGTH_SHORT).show();}MainActivity整體代碼如下:
package com.lyz.hdk.helloworld;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.View;import android.widget.Toast;/** * 主程入口 * @author liuyazhuang * */public class MainActivity extends Activity {public native String helloFromC();//載入靜態代碼塊static{System.loadLibrary("hello");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}public void click(View v){Toast.makeText(this, "c代碼的內容是:"+helloFromC(), Toast.LENGTH_SHORT).show();}}
二、運行效果
三、溫馨提示:
大家可以到連結http://download.csdn.net/detail/l1028386804/8987847下載完整的Android JNI樣本原始碼。
本執行個體中,為了方面,我把一些文字直接寫在了布局檔案中和相關的類中,大家在真實的項目中要把這些文字寫在string.xml檔案中,在外部參考這些資源,切記,這是作為一個Android程式員最基本的開發常識和規範,我在這裡只是為了方便直接寫在了類和布局檔案中。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Android之——JNI初探