Android之——JNI初探

來源:互聯網
上載者:User

標籤: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初探

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.