Android 原生開發包NDK(Native Delopment kits)將用于Android平臺上的C++開發。Android NDK是Android軟件開發包(SDK)的相關工具集,用來擴展Android SDK的功能,從而是開發人員能夠使用機器代碼生成的編程語言(如C、C++和匯編語言)實現一些對代碼行要求較高的模塊并將這些模塊嵌入到Android應用程序中。
眾所周知,Android程序運行在Dalvik虛擬機中,NDK允許用戶使用類似C / C++之類的原生代碼語言執行部分程序。
Android NDK不是一個單獨的工具:它是一個包含API、交叉編譯器、鏈接程序、調試器、構建工具、文檔和實例應用程序的綜合工具集。
1、以下是Android NDK的一些主要組件:
ARM x86和MIPS交叉編譯器
構建系統
java原生接口頭文件
C庫
Math庫
POSIX線程
小的C++庫
Zlib壓縮庫
Android 日志庫
Android 像素緩沖區庫
Android原生應用APIs
OPENGL ES 3D圖形庫
OPENSL ES 原生音頻庫
OpenMAX AL 小支持
2、Android NDK的結構
ndk-build :該shell腳本是Android NDK 構建系統的起始點,
ndk-gdb:該shell腳本允許用GNU調試器調試原生組件。(第五章)
ndk-stack:該shell腳本可以幫助分析原生組件崩潰時的堆棧追蹤號(第五章)
build:該目錄包含Android NDK構建系統的所有模塊,本章將詳細介紹Android ndk構建系統
platforms:該目錄包含了支持不同Android目標版本的頭文件的庫文件
Androidndk構建系統會根據具體的Android八本自動引用這些文檔。
samples:該目錄包含了一些實例應用程序,這些程序可以體現Android NDK的特性,對應學習android ndk的特性會很有幫助
source:
該目錄包含目前Android NDK 支持不同目標機體系機構的交叉編譯器,Android 目前支持ARM X86 MIPS等體系結構
Android NDK 的構建系統根據選定的體系結構使用不同的交叉編譯器。
3、為何要用到NDK?
概括來說主要分為以下幾種情況:
1. 代碼的保護,由于apk的java層代碼很容易被反編譯,而C/C++庫反匯難度較大。
2. 在NDK中調用第三方C/C++庫,因為大部分的開源庫都是用C/C++代碼編寫的。
3. 便于移植,用C/C++寫的庫可以方便在其他的嵌入式平臺上再次使用。
JNI是Java Native Interface的縮寫,它提供了若干的API實現了Java和其他語言的通信(主要是C&C++)。從Java1.1開始,JNI標準成為java平臺的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI一開始是為了本地已編譯語言,尤其是C和C++而設計的,但是它并不妨礙你使用其他編程語言,只要調用約定受支持就可以了。使用java與本地已編譯的代碼交互,通常會喪失平臺可移植性。但是,有些情況下這樣做是可以接受的,甚至是必須的。例如,使用一些舊的庫,與硬件、操作系統進行交互,或者為了提高程序的性能。JNI標準至少要保證本地代碼能工作在任何Java 虛擬機環境下。
JNI是java程序設計語言功能的強特征,它允許java類的某些方法原生實現,同時讓他們能夠像普通的java方法一樣被調用和使用。這些原生方法也可以使用java對象,使用方法與java代碼使用java對象的方法相同。原生方法可以創建新的java對象或者使用java應用程序創建的對象,這些java應用程序可以檢查,修改和調用這些對象的方法執行任務。
JNI的副作用:
一旦使用JNI,JAVA程序就喪失了JAVA平臺的兩個優點:
1、程序不再跨平臺。要想跨平臺,必須在不同的系統環境下重新編譯本地語言部分。
2、程序不再是絕對安全的,本地代碼的不當使用可能導致整個程序崩潰。一個通用規則是,你應該讓本地方法集中在少數幾個類當中。這樣就降低了JAVA和C之間的耦合性。
什么場合下應該使用JNI:
當你開始著手準備一個使用JNI的項目時,請確認是否還有替代方案。像上一節所提到的,應用程序使用JNI會帶來一些副作用。下面給出幾個方案,可以避免使用JNI的時候,達到與本地代碼進行交互的效果:
1、JAVA程序和本地程序使用TCP/IP或者IPC進行交互。
2、當用JAVA程序連接本地數據庫時,使用JDBC提供的API。
3、JAVA程序可以使用分布式對象技術,如JAVA IDL API。
這些方案的共同點是,JAVA和C處于不同的線程,或者不同的機器上。這樣,當本地程序崩潰時,不會影響到JAVA程序。
下面這些場合中,同一進程內JNI的使用無法避免:
1、程序當中用到了JAVA API不提供的特殊系統環境才會有的特征。而跨進程操作又不現實。
2、你可能想訪問一些己有的本地庫,但又不想付出跨進程調用時的代價,如效率,內存,數據傳遞方面。
3、JAVA程序當中的一部分代碼對效率要求非常高,如算法計算,圖形渲染等。
總之,只有當你必須在同一進程中調用本地代碼時,再使用JNI。
JNI的演化:
JDK1.0包含了一個本地方法接口,它允許JAVA程序調用C/C++寫的程序,許多第三方的程序和JAVA類庫。如:java.lang,java.io,java.net等都依賴于本地方法來訪問底層系統環境的特征。
不幸的是,JDK1.0中的本地方法有兩個主要問題:
1、本地方法像訪問C中的結構(structures)一樣訪問對象中的字段。盡管如此,JVM規范并沒有定義對象怎么樣在內存中實現。如果一個給定的JVM實現在布局對象時,和本地方法假設的不一樣,那你就不得不重新編寫本地方法庫。
2、因為本地方法可以保持對JVM中對象的直接指針,所以,JDK1.0中的本地方法采用了一種保守的GC策略。
JNI的誕生就是為了解決這兩個問題,它可以被所有平臺下的JVM支持:
(1)每一個JVM實現方案可以支持大量的本地代碼。
(2)開發工具作者不必處理不同的本地方法接口。
(3)本地代碼可以運行在不同的JVM上面。
JDK1.1中第一次支持JNI,但是,JDK1.1仍在使用老風格的本地代碼來實現JAVA的API。這種情況在JDK1.2下被徹底改變成符合標準的寫法。
JNI的設計目的:
標準的java類庫可能不支持你的程序所需的特性。或許你已經有了一個用其他語言寫成的庫或程序,而你希望在java程序中使用它。
你可能需要用底層語言實現一個小型的時間敏感代碼,比如匯編,然后在你的java程序中調用這些功能。
1、AndroidC++開發環境主要有以下幾部分構成:
Android軟件開發包(SDK)
Android原生開發包(NDK)
Ecplise上的Android開發工具 ADT插件
java開發包
GNU Make構建系統
ecplise IDE
2、
(1)首先我們安裝java環境
(2)安裝ecplise開發環境
(3)給ecplise添加ADT插件
(4)安裝SDK,NDK與ecplise進行關聯
(5)GNU make構建系統
3、配置開發環境
在ecplise中配置SDK,NDK
為了先給大家展示一下什么樣的項目為一個ndk項目,我們選擇在samples目錄下包含了Android NDK安裝程序自帶的示例應用程序。現在可以使用其中的示例應用程序。
導入方式:File-->import-->Android-->Existing Android code into workspace導入NDK路徑下的samples-->helloJni項目
成功如下所示:
導入之后,只將項目作為Android java 項目導入,為了讓構建流包含原生組件,需要手動添加原生支持,添加方式:
項目上右鍵--->Android ToolS--->add native support-->后點擊確定
添加成功:之后打開模擬器運行
運行方式:
在項目上右鍵-->run as--->Android application