android平台中編寫jni模組的方法(3)

來源:互聯網
上載者:User

這篇文章來說說ndk的使用方法,其實主要是關於ndk的一些編譯選項的研究和翻譯(其實人家google的文檔已經說的很清楚了)。偶選用的測試環境是 slackware 12.0 + android 1.5 r1 for linux + jdk 1.6.0_12,ndk選用的是android 1.5 ndk r1這個版本的(直接解壓就行,免安裝的)。

1、從ndk安裝說起
ndk安裝的時候需要運行一 個~/android-ndk-1.5_r1/build/目錄下面的一個叫做host-setup.sh的指令碼。大略讀了一下這個指令碼,發現這個主要是 用來產生out/host/host/config.mk檔案的。主要用於指定使用者作業系統的判斷以及支援的編譯器類型(設定makefile中的 cc,ar,ld之類的變數)
ndk的目錄介紹。

2、ndk的目錄結構分析
進入android-ndk-1.5_r1目錄,看到如下目錄結構:
GNUmakefile: 標準的makefile格式的檔案,用於引用build/core/main.mk的編譯指令碼。
README.TXT:基本的說明,沒啥大用,真正有用的文檔都在docs目錄下面。
apps/:存放帶有jni介面的android工程目錄(工程裡面有利用native關鍵字定義的java函數)
build/:存放著幾乎所有的ndk編譯相關的指令碼以及必要的靜態連結庫。
docs/:存放這ndk的所有“官方”文檔,每一篇文檔對於jni編寫者來說這裡面的任何一點點資料都是無價的。
out/:存放一些中間的臨時檔案,例如jni的.c/.cpp檔案編譯過程中產生的.o檔案等。
sources/:存放jni檔案的.c/.cpp的原始碼檔案。

3、基本的使用方法
(1)建立一個android工程
進入apps目錄,運行如下命令:
android create project --target 2 --package com.TWM --activity NDKTest --path ./NDKTest/project
通 過命令列建立一個叫做NDKTest的activity,注意這裡的--path需要設定為./XXXXX/project這個目錄,這個XXXXX目錄 主要是為了ndk的make區分不同項目和工程使用的。編寫Application.mk檔案的時候,一定要把Application.mk寫到這個 XXXXX目錄下面。
$NDK/apps/<myapp>/Application.mk

另外,編譯jni庫的時候使用的命令也是如此:
make APP=<your app name>
這裡的<your app name>實際上也是這個XXXXX目錄。

(2)為工程添加一個jni的java調用介面
進入app/NDKTest/project/src/com/TWM/NdkTest目錄,建立一個新的java檔案(例如:NDKJni.java),然後把代碼寫成類似下面這個樣子:
package com.TWM.NdkTest ;
public class NDKJni {
    public native int MyFunc(int a, int b) ;
    static {
        System.loadLibrary("NDKjni") ;
    }
}
這裡的MyFunc由於是使用native修飾,因此,這個MyFunc函數是一個調用jni的函數。

(3)為java工程編寫Application.mk檔案
該檔案主要放在app/NDKTest目錄下,用於告知ndk的編譯指令碼,當前的程式需要哪個jni模組。
看上去應該是這個樣子的:
APP_PROJECT_PATH := $(call my-dir)/project   ---> 目前的目錄下的project目錄包含了jni模組的java介面
APP_MODULES      := NDKTest                               --->當前模組的名字叫做NDKTest

(4)弄清楚java程式的包層次
以當前的這個project為例,就是上面代碼中的package com.TWM.NdkTest,定義的類名為NDKJni。因此,根據這個包的層次,可以根據jni檔案的函數命名規則定義函數:
JNIEXPORT jint JNICALL Java_com_TWM_NdkTest_NDKJni_MyFunc(JNIEnv * env, jobject thiz, jint a, jint b) ;
當然,手工根據包層次定義jni函數還是很痛苦的,可以藉助於javah工具:
mkdir -p apps/NDKTest/project/jni
cd apps/NDKTest/project/jni
javah -classpath "../bin/classes" com.TWM.NdkTest.NDKJni
然後就會自動產生一個叫做com_TWM_NdkTest_NDKJni.h的檔案,裡面的內容基本上跟手工產生的差不多:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_TWM_NdkTest_NDKJni */

#ifndef _Included_com_TWM_NdkTest_NDKJni
#define _Included_com_TWM_NdkTest_NDKJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_TWM_NdkTest_NDKJni
 * Method:    MyFunc
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_TWM_NdkTest_NDKJni_MyFunc
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif
好了,有了這個函數的定義,就可以準備去編寫jni了。

(5)進入source目錄
建立目錄ndktest,然後在裡面放置兩個檔案,一個是隨便命名例如a.c,另外一個是一個叫做Android.mk的編譯指令檔。
裡面的內容如下:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := NDKTest         --->這裡是指定jni模組的名字,產生的so庫應該叫做libNDKTest.so,這個名字一定要與Application.mk檔案中的APP_MODULES相同。
LOCAL_SRC_FILES := a.c

include $(BUILD_SHARED_LIBRARY)  --->這裡是告訴編譯指令碼產生的庫是共用庫(本身NDK是可以產生動態庫和靜態庫的)。

然後在a.c裡面寫入的內容如下:
JNIEXPORT jint JNICALL
Java_com_TWM_NdkTest_NDKJni_MyFunc(JNIEnv * env, jobject thiz, jint a, jint b)
{
  return a+b ;
}

(6)開始編譯jni模組
首先進入android-ndk-1.5_r1目錄,然後運行如下命令:
make APP=NDKTest [斷行符號]
這個時候就會看到它開始編譯並且在apps/NDKTest/projects/目錄下建立了libs/armeabi/目錄,並且把產生的libNDKTest.so拷貝到該目錄下。
看到這裡或許有人會問,它的編譯參數怎麼沒有,我怎麼調試阿?!其實很簡單,只要多加一個編譯參數即可。
make APP=NDKTest V=1 [斷行符號]

你就會看到如下的輸出(偶的測試程式裡面把上面說的a.c改成NDKTest.c了,所以看到的內容略有不同):
wayne@wayne:~/android-ndk-1.5_r1$ make APP=NDKTest V=1
Android NDK: Building for application 'NDKTest'
Compile thumb  : NDKTest <= sources/ndktest/NDKTest.c
build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-gcc -Ibuild/platforms/android-1.5/arch-arm/usr/include -march=armv5te -mtune=xscale -msoft-float -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__   -Isources/ndktest -DANDROID  -O2 -DNDEBUG -g    -c -MMD -MP -MF out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o.d.tmp sources/ndktest/NDKTest.c -o out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o
build/core/mkdeps.sh out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o.d.tmp out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o.d
SharedLibrary  : libNDKTest.so
build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-gcc -nostdlib -Wl,-soname,libNDKTest.so -Wl,-shared,-Bsymbolic  out/apps/NDKTest/android-1.5-arm/objs/NDKTest/NDKTest.o -Wl,--whole-archive  -Wl,--no-whole-archive   build/platforms/android-1.5/arch-arm/usr/lib/libc.so build/platforms/android-1.5/arch-arm/usr/lib/libstdc++.so build/platforms/android-1.5/arch-arm/usr/lib/libm.so   -Wl,--no-undefined   -Wl,-rpath-link=build/platforms/android-1.5/arch-arm/usr/lib /home/wayne/android-ndk-1.5_r1/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a -o out/apps/NDKTest/android-1.5-arm/libNDKTest.so
Install        : libNDKTest.so => apps/NDKTest/project/libs/armeabi
mkdir -p apps/NDKTest/project/libs/armeabi
install -p out/apps/NDKTest/android-1.5-arm/libNDKTest.so apps/NDKTest/project/libs/armeabi/libNDKTest.so
build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-strip --strip-debug  apps/NDKTest/project/libs/armeabi/libNDKTest.so

(7)開始編譯android本地java程式
進入apps/NDKTest/project目錄,然後運行ant debug來產生調試版本的apk包,注意,此時,apk包裡面會自動把剛剛產生的libNDKTest.so打包進去的。這一點可以通過把apk檔案用unzip命令解包來驗證,在此不再贅述。

這就是android-ndk編譯jni程式的全過程,確實要比偶在上一篇文章中描述的方法來得簡單許多,總結一下:
(a)在apps目錄裡面建立帶有native關鍵字聲明的java項目。(注意,目錄需要多打一層,用來放Application.mk檔案)
(b)在sources目錄裡面建立真正的jni模組目錄,裡面一定要包含一個叫做Android.mk的檔案。
(c)在apps裡面的Application.mk與sources目錄裡面的Android.mk在MODULE的名字上一定要“遙相呼應”。
(d)編譯的方法是,進入android-ndk-1.5_r1目錄,運行make APP=<your app name> V=1產生jni庫;其實不止如此,make APP=<your app name> clean也可以清除掉。

但願這篇文章能夠對各位致力於android開發和移植的朋友們有所協助。

相關文章

聯繫我們

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