A. android.mk解析與使用看這篇就夠了
背景圖來源:
爭取每一篇文章都是精華,每一篇文章都能做到後期維護,本篇內容也可通過本人唯一 〖阿里雲地址 (點我跳轉)〗 查看
寫在前面:
官網對Android.mk的介紹 (點我跳轉);注意新的源碼中很多app已經切換到了Android.bp,不過目前Android.mk還是兼容的
一、Android.mk理解:
Android.mk是一個向Android NDK構建系統描述NDK項目的GNU makefile片段(可以理解為Android工程管理文件的說明書)。將源文件分組為模塊或編譯生成以下幾種:
1、庫是寫好的現有的,成熟的,可以復用的代碼。本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。庫有兩種:靜態庫(.a、.lib)和動態庫(.so、.dll)
2、靜態庫和動態庫的理解(可選):
靜態庫在編譯時會將依賴的所有代碼合並到一個可執行文件中,而動態庫在運行時才載入依賴的代碼,通常用於模塊化設計和代碼復用。
二、Android.mk詳細解析:
1、LOCAL_PATH := $(call my-dir):
定義當前模塊的路徑
2、include $(CLEAR_VARS):
清理變數,為新模塊的配置做准備
3、LOCAL_SRC_FILES :=$(call all-subdir-java-files):
指定需要編譯的Java文件
4、LOCAL_MODULE := Bgwan:
定義模塊名稱
5、LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT):
設置模塊生成的目標路徑
6、include $(BUILD_SHARED_LIBRARY):
指示構建系統生成共享庫
7、LOCAL_MODULE_TAGS := optional:
設置編譯標簽
8、LOCAL_CERTIFICATE := platform:
設置簽名屬性
9、LOCAL_STATIC_JAVA_LIBRARIES := jar1 jar2:
引用靜態jar庫
10、LOCAL_STATIC_JAVA_AAR_LIBRARIES := aar_alias:
引用靜態aar庫
11、需要進行預編譯的庫:
定義靜態庫別名和路徑
12、include $(BUILD_MULTI_PREBUILT):
預編譯庫
13、GNU Make系統變數:
收集其他系統變數
三、Android.mk案例實戰:
1、項目目錄結構(新增內容):
便於理解內容,新增目錄結構示例
2、引用aar包:
在源碼環境中,通過Android.mk將aar導入APK
3、解決運行時找不到so的問題:
源碼下編譯的APK不含so文件,解決方案
4、編譯靜態庫、動態庫和多個共享庫:
5、使用/引用靜態庫和動態庫:
6、使用/引用第三方文件:
7、共享通用模塊:
8、拷貝文件到指定目錄:
9、編譯apk和生成目錄:
10、編譯jar包:
11、源碼環境下引用jar包:
12、使用預編譯庫:
13、編譯獨立可執行文件:
14、apk生成目錄:
15、編譯特定目錄下的apk:
16、引用jar包:
17、預編譯jar包:
18、Android.mk中的判斷語句:
19、開啟混淆:
20、指定資源目錄:
21、引用so庫:
22、Android.mk文件配置簽名:
四、總結:重要的注意事項:
請根據實際項目使用和理解
1、Android.mk可以引用Android.bp中的模塊,反之Android.bp不能引用Android.mk中的模塊。
2、Android.bp模塊不支持../../去尋找上層路徑的文件。
3、本地庫依賴於其他so時,需注意載入順序。
4、Android 6.0版本之前,載入本地庫前需先載入依賴的so。
5、Android 6.0版本後,預編譯的動態庫不再推薦使用。
致謝(引用和推薦)(可選):
感謝各位前輩的開源精神和分享,以下文章提供參考。
B. 怎麼樣將自己開發的Android應用程序編譯到系統Image中
1. 搭建編譯環境
編譯環境: Ubuntu 10.10
Android版本:Android 2.2
編譯過程中可能需要在Ubuntu上安裝必要的一些軟體,我安裝過的包含如下軟體,不同的系統可能會有差別:
jdk6(Android官方建議裝jdk5,但是我在編譯時會遇到Java override問題,改用6沒有任何問題), bison, lib64z1-dev, libasound2-dev, flex, gperf, libncurses5-dev
2. 應用程序存放目錄
SimpleJNI是採用Android NDK和Java編寫的程序,包含apk和so庫文件,它的源代碼在source tree的development/samples/目錄下。
實際上package在編譯時所放的目錄並沒有明確限定,編譯後apk和so存放的位置是根據目錄下Android.mk所指定的編譯類型所決定的,例如:
SimpleJNI根目錄下的Android.mk中有一行include $(BUILD_PACKAGE),表示將該目錄下的模塊編譯成package,即apk文件,默認存放的位置為/system/app。
SimpleJNI/jni目錄下的Android.mk中有一行為include $(BUILD_SHARED_LIBRARY),表示將該目錄下的native.cpp編譯為共享庫文件,即so文件,默認存放的位置為/system/lib
因此,如果我們想要將自己編寫的程序編譯至image中,只需要將Eclipse下完成的整個工程到source tree下的某個目錄即可,我一般習慣放到packages/apps下。
3. 添加Android.mk
完成了上一步,可以知道,Android.mk在編譯中起著至關重要的作用,這其實就是Android編譯環境中的make file。為了完成我們的工作,需要在源代碼中添加Android.mk。添加自己的Android.mk可以仿照SimpleJNI中的Android.mk,稍微修改即可。我們首先看看SimpleJNI目錄下的兩個Android.mk的內容:
根目錄下的Android.mk
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
LOCAL_PATH:= $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SimpleJNI
LOCAL_JNI_SHARED_LIBRARIES := libsimplejni
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
# ============================================================
# Also build all of the sub-targets under this one: the shared library.
include $(call all-makefiles-under,$(LOCAL_PATH))
根目錄下的Android.mk決定了整個工程編譯的配置,其中,
LOCAL_PATH 定義了當前的目錄
LOCAL_MUDULE_TAGS 定義了當前模塊的類型,編譯器在編譯時會根據類型的不同有些差別,有些tags的mole甚至不會被編譯至系統中。LOCAL_MUDULE_TAGS主要有如下幾種:user debug eng tests optional samples shell_ash shell_mksh。optional表示在所有版本的編譯條件下都被編譯至image中,剩下的表示在該版本中才會被編譯只image中,如user表示在user版本下才會被編譯至image中。
對於包含LOCAL_PACKAGE_NAME的mk文件,該項默認為optinal,具體可以參看build/core/package.mk。SimpleJNI中定義為samples的具體作用我也不太清楚,為了保險起見,我自己的apk一般定義為optional。
LOCAL_SRC_FILES 定義了編譯apk所需要的java代碼的目錄
LOCAL_PACKAGE_NAME 這里需要改成自己的package的名字
LOCAL_JNI_SHARED_LIBRARIES 定義了要包含的so庫文件的名字,如果你的程序沒有採用JNI,這行不需要。
LOCAL_PROGUARD_ENABLED 定義了Java開發中的ProGuard壓縮方法,主要用來分析壓縮程序的,在我自己的應用中我沒有加這行。
include $(BUILD_PACKAGE) 這行是build的關鍵,表示當前java代碼build成apk
include $(call all-makefiles-under,$(LOCAL_PATH)) 表示需要build該目錄下的子目錄的文件,這樣編譯系統就會在當前目錄下的子目錄尋找Android.mk來編譯so等其它程序。
根據上述所寫,創建我自己的Android.mk如下:
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
LOCAL_PATH:= $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := TestJniApp
LOCAL_JNI_SHARED_LIBRARIES := libtestjniapp
include $(BUILD_PACKAGE)
# ============================================================
# Also build all of the sub-targets under this one: the shared library.
include $(call all-makefiles-under,$(LOCAL_PATH))
看起來很簡單吧,基本不需要改動即可。
Jni目錄下的Android.mk
由於我們的TestJniApp是用JNI完成的,包含C源代碼,因此也需要一個jni目錄下的Android.mk。同樣首先看看SimpleJNI中jni目錄下的Android.mk的內容:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples
# This is the target being built.
LOCAL_MODULE:= libsimplejni
# All of the source files that we will compile.
LOCAL_SRC_FILES:= /
native.cpp
# All of the shared libraries we link against.
LOCAL_SHARED_LIBRARIES := /
libutils
# No static libraries.
LOCAL_STATIC_LIBRARIES :=
# Also need the JNI headers.
LOCAL_C_INCLUDES += /
$(JNI_H_INCLUDE)
# No special compiler flags.
LOCAL_CFLAGS +=
# Don't prelink this library. For more efficient code, you may want
# to add this library to the prelink map and set this to true. However,
# it's difficult to do this for applications that are not supplied as
# part of a system image.
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE 當前模塊的名字,即編譯後的so文件的名字
LOCAL_SRC_FILES 所要編譯的文件
LOCAL_SHARED_LIBRARIES, LOCAL_STATIC_LIBRARIES 該模塊要鏈接的動態庫和靜態庫。
LOCAL_C_INCLUDES 要包含的頭文件
LOCAL_CFLAGS C語言編譯選項
LOCAL_PRELINK_MODULE 定義是否使用prelink工具,它用事先鏈接代替運行時鏈接的方法來加速共享庫的載入,不僅可以加快起動速度,還可以減少部分內存開銷。
經過修改後,我自己的TestJniApp中jni目錄下的Android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libtestjniapp
LOCAL_SRC_FILES := com_test_app_Jni.c
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
這里有一點需要注意,如果要將so文件編譯入image,必須要修改LOCAL_MODULE_TAGS,將原有的值samples修改為user,或者可以直接刪掉 。刪掉是因為對於包含LOCAL_MODULE的mk文件,如果沒有指定LOCAL_MODULE_TAGS,該項默認為user,而只有定義為user的情況下,才會將so文件編譯入image,具體定義可以參看build/core/base_rule.mk。
4. 修改/bulid/target/proct/generic.mk 把工程編譯到系統中
至此,還有最後一部工作。為了將工程編譯進入image,還需要在/bulid/target/proct/generic.mk文件中將package name添加進去
PRODUCT_PACKAGES := /
AccountAndSyncSettings /
CarHome /
DeskClock /
……
SyncProvider /
TestJniApp
完成上面這些步驟後,在source tree根目錄下編譯image就可以了。
C. android.mk是在什麼情況下生成的
當你需要使用JNI的時候,你需要創建一個native工程。Android.mk就是一個makefile配置文件,幫你把C/C++的代碼編譯成動態庫so的。
創建的方式有兩種:
在工程根目錄裏手動創建一個目錄叫jni,在裡面新建一個Android.mk,然後創建c,cpp文件,把他們配置到Android.mk里。
右鍵工程,選擇Android Tools->Add Native Support自動生成。
(3)mk編譯成共享庫擴展閱讀:
創建Android庫
Android 庫在結構上與 Android 應用模塊相同。可以提供構建應用所需的一切內容,包括源代碼、資源文件和 Android 清單。
不過,Android 庫將編譯到可以用作 Android 應用模塊依賴項的 Android 歸檔 (AAR:Android Archive Resource) 文件,而不是在設備上運行的 APK。
與 JAR 文件不同,AAR 文件可以包含 Android 資源和一個清單文件,這樣,除了 Java 類與方法外,還可以捆綁布局和可繪制對象等共享資源。
庫模塊在以下情況下非常有用:
構建使用某些相同組件(例如 Activity、服務或 UI 布局)的多個應用。
構建存在多個 APK 變體(例如免費版本和付費版本)的應用並且需要在兩種版本中使用相同的核心組件。
D. 編譯找不到prebuilt_shared_library的庫
編譯找不到prebuilt_shared_library的庫解決方法。必須將自己使用的每個預編譯庫差和敬聲明為棚慶一個獨虛慎立模塊。為此,執行以下步驟。
1、為模塊提供名稱。此名稱不需要與預編譯庫本身的名稱相同。
2、在模塊的Android.mk文件中,將指向您提供的預編譯庫的路徑分配到LOCAL_SRC_FILES。指定LOCAL_PATH變數的值的相對路徑。注意:請務必選擇與您的目標ABI對應的預編譯庫版本。要詳細了解如何確保庫支持ABI,請參閱為預編譯庫選擇ABI。
3、根據您使用的是共享庫(.so)還是靜態庫(.a),添加PREBUILT_SHARED_LIBRARY或PREBUILT_STATIC_LIBRARY。
E. android.mk文件怎麼寫
一個Android.mk file用來向編譯系統描述你的源代碼。具體來說:該文件是GNU Makefile的一小部分,會被編譯系統解析一次或多次。你可以在每一個Android.mk file中定義一個或多個模塊,你也可以在幾個模塊中使用同一個源代碼文件。編譯系統為你處理許多細節問題。例如,你不需要在你的Android.mk中列出頭文件和依賴文件。NDK編譯系統將會為你自動處理這些問題。這也意味著,在升級NDK後,你應該得到新的toolchain/platform支持,而且不需要改變你的Android.mk文件。
先看一個簡單的例子:一個簡單的"hello world",比如下面的文件:
sources/helloworld/helloworld.c
sources/helloworld/Android.mk
相應的Android.mk文件會象下面這樣:
---------- cut here ------------------
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE
:= helloworld
LOCAL_SRC_FILES := helloworld.c
include $(BUILD_SHARED_LIBRARY)
---------- cut here ------------------
我們來解釋一下這幾行代碼:
LOCAL_PATH := $(call my-dir)
一個Android.mk file首先必須定義好LOCAL_PATH變數。它用於在開發樹中查找源文件。在這個例子中,宏函數』my-dir』, 由編譯系統提供,用於返回當前路徑(即包含Android.mk file文件的目錄)。
include $( CLEAR_VARS)
CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變數(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。這是必要的,因為所有的編譯控制文件都在同一個GNU MAKE執行環境中,所有的變數都是全局的。
LOCAL_MODULE := helloworld
LOCAL_MODULE變數必須定義,以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。注意編譯系統會自動產生合適的前綴和後綴,換句話說,一個被命名為'foo'的共享庫模塊,將會生成'libfoo.so'文件。
LOCAL_SRC_FILES := helloworld.c
LOCAL_SRC_FILES變數必須包含將要編譯打包進模塊中的C或C++源代碼文件。注意,你不用在這里列出頭文件和包含文件,因為編譯系統將會自動為你找出依賴型的文件;僅僅列出直接傳遞給編譯器的源代碼文件就好。
在Android中增加本地程序或者庫,這些程序和庫與其所載路徑沒有任何關系,只和它們的Android.mk文件有關系。Android.mk和普通的Makefile有所不同,它具有統一的寫法,主要包含一些系統公共的宏。
在一個Android.mk中可以生成多個可執行程序、動態庫和靜態庫。
1,編譯應用程序的模板:
#Test Exe
LOCAL_PATH := $(call my-dir)
#include $(CLEAR_VARS)
LOCAL_SRC_FILES:= main.c
LOCAL_MODULE:= test_exe
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_EXECUTABLE)
(菜鳥級別解釋::=是賦值的意思,$是引用某變數的值)LOCAL_SRC_FILES中加入源文件路徑,LOCAL_C_INCLUDES 中加入所需要包含的頭文件路徑,LOCAL_STATIC_LIBRARIES加入所需要鏈接的靜態庫(*.a)的名稱,LOCAL_SHARED_LIBRARIES中加入所需要鏈接的動態庫(*.so)的名稱,LOCAL_MODULE表示模塊最終的名稱,BUILD_EXECUTABLE表示以一個可執行程序的方式進行編譯。
2,編譯靜態庫的模板:
#Test Static Lib
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= /
helloworld.c
LOCAL_MODULE:= libtest_static
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_STATIC_LIBRARY)
一般的和上面相似,BUILD_STATIC_LIBRARY表示編譯一個靜態庫。
3,編譯動態庫的模板:
#Test Shared Lib
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= /
helloworld.c
LOCAL_MODULE:= libtest_shared
TARGET_PRELINK_MODULES := false
#LOCAL_C_INCLUDES :=
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_SHARED_LIBRARY)
一般的和上面相似,BUILD_SHARED_LIBRARY表示編譯一個靜態庫。
以上三者的生成結果分別在如下,generic依具體target會變:
out/target/proct/generic/obj/EXECUTABLE
out/target/proct/generic/obj/STATIC_LIBRARY
out/target/proct/generic/obj/SHARED_LIBRARY
每個模塊的目標文件夾分別為:
可執行程序:XXX_intermediates
靜態庫: XXX_static_intermediates
動態庫: XXX_shared_intermediates
另外,在Android.mk文件中,還可以指定最後的目標安裝路徑,用LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH來指定。不同的文件系統路徑用以下的宏進行選擇:
TARGET_ROOT_OUT:表示根文件系統。
TARGET_OUT:表示system文件系統。
TARGET_OUT_DATA:表示data文件系統。
用法如:
CAL_MODULE_PATH:=$(TARGET_ROOT_OUT)
F. Android 怎麼自定義共享庫
在Android源碼根目錄下的vendor目錄下,有一個專門存放各種供應商代碼的sample目錄。其中的PlatformLibrary目錄展示了如何編寫自定義共享庫。為了讓大家更好地理解如何封裝Java共享庫,我們可以通過PlatformLibrary目錄來學習。
PlatformLibrary目錄下的Android.mk文件用於定義構建規則,它默認繼承Android的make框架。在該目錄下,我們還需要編寫com.example.android.platform_library.xml文件,該文件用於模塊注冊,需要將其放置到/system/etc/permissions目錄下。
接下來,我們可以在java目錄下編寫Java源代碼,如PlatformLibrary.java。然後編寫Android.mk文件來定義如何編譯該模塊。內容如下:
# 獲得當前目錄,清空環境變數
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 源碼所在目錄,all-subdir-java-files表示所有了目錄中的Java文件。
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# 該模塊是可選的。
LOCAL_MODULE_TAGS := optional
# Java模塊名稱
LOCAL_MODULE:= com.example.android.platform_library
# 編譯為Java庫。最近以jar的形式而不是apk的形式存在。
include $(BUILD_JAVA_LIBRARY)
# 構建該庫的API文檔
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files) $(call all-subdir-html-files)
LOCAL_MODULE:= platform_library
# 文檔對應的庫
LOCAL_DROIDDOC_OPTIONS := com.example.android.platform_library
# 庫的類型
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_DROIDDOC_USE_STANDARD_DOCLET := true
# 編譯為Java API。
include $(BUILD_DROIDDOC)
完成上述步驟後,我們需要編寫com.example.android.platform_library.xml文件,內容如下:
現在我們已經基本完成了Java庫的封裝,接下來需要對框架中的其他文件進行配置。我們可以在sample/frameworks/Android.mk文件中添加如下內容:
# 包含子目錄中的所有make文件
include $(call all-subdir-makefiles)
在sdk_addon目錄下編寫manifest.ini文件,內容如下:
# 該模塊的名稱、供應商及描述
name=Sample Add-On
vendor=Android Open Source Project
description=sample add-on
# 構建該模塊的Android平台代號
api=3
# 模塊的版本號。必須為整數。
revision=1
# 該模塊中包括的共享庫列表
libraries=com.example.android.platform_library
# 對每個庫的詳細定義,格式如下:
# =.jar;
# : 通過前面libraies定義的庫的名稱。
# .jar:包含庫API的jar文件。該文件放在libs/add-on下面。
com.example.android.platform_library=platform_library.jar;Sample optional plaform library
至此,我們已經完成了Java庫的封裝,接下來我們再來看如何通過JNI的方式對C代碼進行封裝。
在sample/frameworks/PlatformLibrary目錄下添加一個文件夾,用於放置JNI本地代碼。然後在jni目錄下編寫PlatformLibrary.cpp文件,實現PlatformLibrary.java中規定本地調用的具體實現。
在jni目錄下編寫Android.mk文件,定義本地庫的名字、依賴、編譯選項及編譯方式。
最後,修改sdk_addon/sample_addon.mk文件,在PRODUCT_PACKAGES中添加該JNI本地庫。
至此,我們已經完成了JNI庫的添加。接下來我們再看看如何添加原生應用程序。添加原生應用程序就很簡單了,只需要按照Android應用開發的基本方法,寫好一個應用即可。
在應用根目錄中添加一個Android.mk文件,內容如下:
# 獲得當前目錄,清空環境變數
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 目標名稱
LOCAL_MODULE_TAGS := user
# 目標名稱
LOCAL_PACKAGE_NAME := PlatformLibraryClient
# 只編譯這個apk包中的java文件
LOCAL_SRC_FILES := $(call all-java-files-under, src)
# 使用當前版本的SDK
LOCAL_SDK_VERSION := current
# 依賴使用剛才編寫的擴展
LOCAL_JAVA_LIBRARIES := com.example.android.platform_library
include $(BUILD_PACKAGE)
在AndroidManifest.xml中添加一句:
然後修改sdk_addon/sample_addon.mk文件,在PRODUCT_PACKAGES中添加該JNI本地庫。
至此,我們已經完成了JNI庫的添加。
G. 關於android NDK開發中application.mk文件的疑惑
介紹:
Android SDK是一個允許Android應用開發人員使用C或C++源文件編譯並嵌入到本機源代碼中的應用程序包的一組工具。
重要說明:
Android NDK只能用於android 1.5以上版本
1.Android NDK的目的:
Android虛擬機允許你的應用程序源代碼通過JNI調用在本地實現的源代碼,簡單的說,這就意味著:
你的應用程序將聲明一個或多個用』native』關鍵字的方法用來指明它們是通過本地代碼實現的
例如:native byte[] loadFile(String filePath)
你必須提供包含實現這些方法的共享庫(就是.so),將共享庫打包到你的應用程序包apk中,這些庫文件必須根據標準的Unix約定來命名為 lib<something>.so,並且是需要包含一個標準的JNI的介面,例如
libFileLoader.so
你的應用程序必須明確的裝載這些庫文件(.so文件),比如,在程序的開始裝載它,只需要簡單的添加幾句源代碼:
java代碼:
static {
System.loadLibrary(「FileLoader」);
}
注意:這里你不必再將前綴lib和後綴.so寫入。
Android NDK對於Android SDK只是個組件,它可以幫你:
生成的JNI兼容的共享庫可以在大於Android1.5平台的ARM CPU上運行
將生成的共享庫拷貝到合適的程序工程路徑的位置上,以保證它們自動的添加到你的apk包中(並且簽名的)
在以後的版本中,我們將提供來幫助你的源代碼通過遠程gdb連接和盡可能多的源代碼的信息。
而且,Android NDK還提供:
一組交叉編譯鏈(編譯器、鏈接器等)來生成可以在Linux,OS X和Windows(用Cygwin)運行的二進制文件
一組與由Android平台提供的穩定的本地API列表的頭文件
它們在docs/STABLE-APIS.html中有說明
重要提示:
記住,在以後的更新和發布平台中,Android系統鏡像中的大多數本地系統庫並不是一成不變的,而是可以徹底改變,甚至刪除的
一個編譯系統(build system)可以允許開發者寫一個非常短的編譯文件(build files)去描述哪個源代碼需要編譯,並且怎樣編譯。編譯系統可以解決所有的toolchain/platform/CPU/ABI細節的問題。並且,較晚的NDK版本中還添加了更多的可以不用改變開發者的編譯文件的情況下的toolchains,platforms,系統介面。
2.Android NDK的缺點
NDK並不是一個可以編寫通用的源代碼並且可以在Android設備上運行的方法,你的應用程序還是需要使用JAVA程序,適當的處理系統事件來避免「應用程序沒有反應」的對話框或者處理Android應用程序的生命周期
注意:可以適當的在源代碼中寫一個復雜的應用程序,用於啟動/停止一個小型的「應用程序包」
強烈建議很好地理解的 JNI,因為許多操作在這種環境要求的開發人員,都採取具體的行動,不一定在常典型的本機代碼。這些措施包括:
不能通過指針直接訪問VM的對象。比如:你不能安全的得到一個指向String對象的16位char數組的循環遍歷
需要顯示引用管理本機代碼時候要保持處理JNI調用之間的VM對象
NDK在Android平台僅僅提供了有限的本地API和庫文件的支持的系統頭文件,然而一個標準的Android系統鏡像包括許多本地共享庫,這些都應該被考慮在更新和發行版本的可以徹底改變的實現細節
如果Android系統庫沒有明確的被NDK明確的支持,然後應用程序不應該依賴於它提供的,或者打破了將來在各種設備上的無線系統更新
選定的系統庫將逐漸被添加到穩定的NDK API中。
3.NDK開發實踐
下面將給出一個怎樣用Android NDK開發本地代碼的粗略的概述
(1) 把本地代碼放在$PROJECT/jni/…下,比如將hello.c放到apps/hello/jni/目錄下
(2) 在你的NDK編譯系統中在$PROJECT/jni/Android.mk來描述你的源代碼
(3) 可選:在$PROJECT/jni/Application.mk到你的編譯系統中來詳細描述你的項目,盡管你開始的話不一定需要它,但是它允許你使用更多的CPU或者覆蓋編譯器/鏈接器的標記
(4) 從你的項目的目錄開始通過運行」$NDK/ndk-build」來編譯你的代碼,或者從子目錄開始
(5) 最後一步可以,萬一成功,剝離共享庫的應用層序需要你的應用程序的項目根目錄。然後你通過通常的方法來生成最終的apk。