天天看點

Android NDK編譯C/C++為so共享對象

概念

JNI(Java Native Interface,Java本地接口),實作了Java和其他語言的互動(主要是C/C++),如:Java程式通過JNI調用C/C++編寫的在Windows上運作的DLL動态連結庫。

so(shared object,共享對象),Linux系統中的動态庫,類似于Windows系統中的DLL。.so有時被直接調用,有時會參與到編譯中。Android由Linux核心發展而來,是以在Android系統中也使用.so。

Android NDK(Android Native Development Kit),是Google提供的一系列的工具,簡化通過JNI将C/C++動态庫編譯為.so庫的過程。NDK內建了交叉編譯器,并提供了相應的.mk檔案隔離CPU、平台、ABI等差異,開發者隻需要簡單修改mk檔案,執行編譯腳本就可以建立.so。

NDK與JNI的關系:

JNI是Java與其他語言互動的機制,是Java語言自身的特性,與Android無關。

Android在架構上分為Application應用層、Application Framework應用架構層、libraries類庫、Linux kernel核心。在應用架構層以及之上,使用Java語言進行開發;在此之下,Android自身的類庫、驅動使用C/C++編寫,再通過JNI提供接口給上層的Java調用。是以,Android架構使用了大量的JNI技術,讓應用層的開發人員使用Java操控C/C++。

通常的Android開發都在應用架構層以及之上進行,但有時也需要對底層進行實作。顯然,對底層的開發要複雜得多,NDK則是Google推出的幫助開發者通過C/C++編寫應用的開發包,包含部分Android底層中常用的C/C++的頭檔案、庫檔案、說明文檔和示例代碼。

安裝

Windows下配置NDK的步驟:

1、下載下傳:android-ndk-r13b-windows-x86_64.zip

2、解壓:

D:\sdk\android-ndk-r13b

3、環境變量:

ANDROID_NDK:D:\sdk\android-ndk-r13b 
PATH:%ANDROID_NDK%
           

4、驗證:cmd指令輸入

ndk-build

若出現“Android NDK: Could not find application project directory”表示NDK正确安裝,隻是沒有待編譯的工程而已。

NDK中的hello-jni

可以下載下傳Google的NDK Samples,下面以其中的hello-jni工程為例,說明NDK中JNI的使用:

hello-jni工程目錄結構:

  • hello-jni
    • jni
      • Android.mk(編譯配置檔案)
      • hello-jni.c(.c代碼)
    • res
    • src
      • com/example/hellojni/HelloJni.java(.java代碼)
    • test

ndk-build

JNI是獨立于NDK存在的,了解JNI才對NDK有更好的認識。[參考1]。

獨立使用JNI時,需要自行使用Cygwin等編譯工具将C/C++代碼編譯為動态庫;而NDKr7開始,內建了交叉編譯器和ndk-build.cmd腳本,開發者可以直接執行這個腳本完成編譯工作。

運作以下指令,進行編譯:

D:\>cd sdk\android-ndk-r13b\samples\hello-jni    //定位到hello-jni
D:\sdk\android-ndk-r13b\samples\hello-jni>ndk-build    //編譯
           

P.S.

當ndk-build指令提示找不到工程時,可以檢視工程的Android.mk檔案中的路徑關系,定位到正确的路徑後使用ndk-build指令。或者,可以将工程路徑設定為

NDK_PROJECT_PATH

環境變量。

編譯成功的話,\hello-jni會多出兩個檔案夾\libs與\obj。其中:

\libs目錄下是編譯出來的不同CPU類型的.so檔案,在實際使用時根據需要選擇

\obj是編譯過程中的生成的其他檔案(如.o中間檔案,或調試檔案)

Android NDK編譯C/C++為so共享對象

調用

在Eclipse-ADT中import進hello-jni工程,建立與\src同級的檔案夾\libs,并把編譯出來的.so放在該檔案夾下。(這裡我直接import進編譯後的工程檔案夾)

Android NDK編譯C/C++為so共享對象

直接運作出結果:

Android NDK編譯C/C++為so共享對象

Android.mk

ndk-build指令實際是執行了

%NDK_PROJECT_PATH%/jni/Android.mk

這個makefile檔案,如果未配置

%NDK_PROJECT_PATH%

環境變量,則需要定位到工程目錄。同時,待編譯的.c和編譯配置檔案Android.mk也需要位于名為jni的目錄下。

Android.mk是NDK編譯的配置檔案,其中定義了需要編譯的.c檔案、依賴的.h頭檔案、編譯出的so庫名等等資訊,是使用NDK進行編譯的關鍵。

//Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni    //編譯出的庫名為 libhello-jni.so
LOCAL_SRC_FILES := hello-jni.c  //編譯源檔案

include $(BUILD_SHARED_LIBRARY)
           

Android.mk常見配置

常見配置将在工作中積累更新…

Application.mk

不同CPU編譯的.so不同,ndk-build預設編譯所有CPU的.so。可以通過Application.mk檔案指定APP_ABI指定CPU,如armeabi-v7a。

//Application.mk
APP_ABI := all  //編譯所有CPU的.so
APP_ABI := armeabi-v7a  //編譯armeabi-v7a的.so
           

Eclipse內建NDK編譯操作

前文中對NDK的操作都使用cmd指令,顯然在工作中十分不便,好在可以将這些操作都內建到Eclipse中的按鈕,一鍵完成任務。

參考:Eclipse內建JNI與AndroidNDK操作

Eclipse添加NDK攜帶的JNI代碼提示

NDK中攜帶了不同CPU的JNI操作源碼,可以添加到Eclipse中有助于在Eclipse中編寫JNI的C/C++代碼。

1、右擊工程 -> Android Tools -> Add Native Support,之後點選彈出視窗的finish即可

2、右擊工程 -> Properties -> C/C++ General -> Paths and Symbols,選擇c,cpp語言 -> Add,使用File system選擇NDK中一個Android版本具體CPU實作的include,确定即可。

//include路徑
D:\sdk\android-ndk-r13b\platforms\android-19\arch-arm\usr\include
           
Android NDK編譯C/C++為so共享對象

提示效果:

Android NDK編譯C/C++為so共享對象

參考

  1. JNI入門——hellojni
  2. so格式檔案是什麼
  3. Android jni開發資料–NDK環境搭建
  4. Android架構介紹
  5. NDK與JNI的關系
  6. Eclipse內建JNI與AndroidNDK操作