瀏覽人次:【14002】
什麼是Android NDK?
每個Android應用程式都是透過Dalvik虛擬機器執行,由虛擬機器來負責程式所需的資源管理,就像Java程式是透過Java虛擬機器執行一樣。Dalvik對於Android應用程式使用原生程式碼的概念也學習自Java。Dalvik實作了標準的JNI(Java Native Interface,Java原生介面,Java語言用來與C或C++等原生程式碼溝通的介面)功能,使Android應用程式中的Java類別能順利的與原生函式庫溝通。這些函式庫可能是原本已內建於Android系統中的核心函式庫(如:libc、WebKit、SQLite等),或是由開發者自行撰寫並編譯完成的函式庫。Android應用程式透過Dalvik虛擬機器的JNI功能與原生函式庫溝通的方式,如圖一所示:
《圖一 Android應用程式透過Dalvik虛擬機器中的JNI功能呼叫由原生程式碼實作的使用者自訂函式庫或內建核心函式庫。》
|
事實上,各地的開發者也對Android系統的內部架構相當感興趣;一部份開發者希望能藉由與原生函式庫的溝通來再利用原本已存在的原生程式函式庫,例如:將寫好的遊戲圖像或資料處理引擎移植到Android平台;另一部份的開發者則希望能透過Dalvik的JNI功能來使得他們自己的Android應用程式能直接調用Android系統中的核心函式庫來達到較佳的程式效能。也有許多人提出並建議了如何在Android應用程式中協作Java程式碼與原生函式庫的方法,然而這些方法大多相當繁雜且多出於推論。NDK的出現,就是Google希望為開發者為這類型的開發工作訂出一套標準化的工具與模式。
因此,Android NDK本身是用來輔助在開發有需要在Android應用程式中放入原生語言函式庫時SDK(Software Development Kit)的不足,而不是必須有了此套件才能開發與原生語言函式庫協同運作的Android應用程式。
Google方面則強調,Android平台在設計之初就已經將Java類別與Dalvik虛擬機器間可能的效能瓶頸給考慮進去,兩方面間的溝通介面已經過許多改進而有不差的效能,諸如Dalvik使用的改良過的.dex檔而非傳統.class檔等;因此使用原生語言撰寫在大部分的狀況下並不會提升應用程式的效能。由於Android平台整個開發框架的限制,Android應用程式必須使用Activity類別作為程式的進入點,這使得開發者無法撰寫百分之百由原生語言構成的Android應用程式,盲目的使用原生語言反而可能造成程式結構雜亂,且可維護性降低等缺點。
Android NDK包含了什麼?
NDK主要提供了以下工具:
●一組可協助開發者在Linux、OS X、Windows等平台上生成原生語言函式庫的工具鏈(toolchains),其中包含專用的編譯器、連結器等等。
●目前Android系統平台所提供的,可供外部程式呼叫的核心函式庫API(Application Programming Interface,應用程式開發介面)。
●一套可以統整並處理單一格式建置檔案(make file)的建置系統(build system)。
如同前述所言,Google希望能統一各平台上開發具有原生程式碼之Android應用程式的方式。所以提出了具有特定格式的建置檔供開發者使用;其一是用來敘述單一個函式庫之結構與內容的Android.mk設定檔,第二是用來敘述應用程式中所需原生程式碼函式庫狀況的Application.mk設定檔;這兩類設定檔所面對的都是Android NDK所提供的建置系統,因此同樣的一份專案與設定檔不管移植到哪個平台都不需要再因為使用了不同的建置環境而再做變動。
值得注意的是,Google非常明白有許多的開發者都希望能不要透過撰寫Java類別而直接使用Android的內建函式庫來實作他們所需的功能。而這些內建函式庫也可以透過追蹤Android系統已釋出的原始碼來得知其使用方式。但由於Android系統內部的各項開發與改進工作仍然持續在進行中,因此NDK的文件中有特別說明,大部分的系統函式庫在未來的版本中都還有變動的可能,例如更名或刪除,因此強烈不建議開發者使用NDK中所沒有提及的函式庫API。
而目前NDK中所列出的系統函式庫在未來就不會再多做變動,Google也承諾會在未來的版本中持續增加可供使用的函式庫(例如:Android 1.6 NDK相較於1.5 NDK就新增了OpenGL ES函式庫;而Android NDK Project Page上,相關工作人員也承諾會在近期的版本中增加更多對於多媒體的函式庫支援)。
Android NDK使用實例
在使用Android NDK之前必須先確定系統中已有安裝對應版本的SDK,以及GNU Make工具3.81或更新的版本。在下載好Android NDK套件後,必須解壓縮並安裝NDK,安裝動作是為了確保原生程式碼的編譯環境不會出錯,並針對開發平台做些許微調。
使用NDK開發使用自行撰寫之原生程式碼的應用程式約分為以下四步驟:
1. 於將使用到原生語言函式的Java類別中以native關鍵字宣告該方法。並以System.loadLibrary()方法明確的要求Dalvik虛擬機器於執行時期載入該函式庫。
2. 撰寫該方法於原生語言的實作(此時稱為函式)。注意此實作必須遵從JNI的相關規範;例如必須使用JNI所定義的資料型態,以及函式的命名規則等。
3. 為每個原生函式庫撰寫Android.mk設定檔,由於Dalvik虛擬機器遵從Solaris平台的JNI函式庫命名規則,所以函式庫檔案必須以”lib”開頭,”.so”作為副檔名。
4. 為整個應用程式專案撰寫Application.mk設定檔。
5. 執行make指令進行原生程式碼的編譯與連結動作,Android NDK的建置系統會將編譯好的函式庫放到專案中適合的位置。
透過以下範例我們將可以知道Android對原生函式的呼叫可以是雙向的;可自Java類別中呼叫原生函式,也可自原生函式中呼叫類別方法。圖三的JNIDemo類別首先以靜態初始化(static initializer)的方式載入libjnidemo.so函式庫,其中有原生方法nativeMethod()的實作內容(見圖四),並在螢幕上繪製一個按鈕。當按鈕按下時,Dalvik虛擬機器會呼叫以C語言實作的nativeMethod()函式,nativeMethod()則以標準的JNI方式轉而呼叫JNIDemo類別中的callback()方法,令螢幕顯示”Method callback() has been invoked.”字樣。
《圖二 JNIDemo專案的目錄結構》 |
此範例完整的專案目錄結構則如圖二。我們可以看到,除了在一般Android專案中可以見到的src、gen、res目錄外,jni目錄則用來放置以原生語言撰寫的原始碼檔案與其Android.mk設定檔。在經過Android NDK建置過後,建置系統會將編譯好的函式庫檔案(在此例中為libjnidemo.so檔)放在<專案名>/libs/armeabi/目錄下。這些檔案與目錄應在需要安裝時包裝為apk檔,並以一般安裝方式載入並安裝在Android平台上。
《圖三 JNIDemo類別》
|
《圖四 jnidemo.c檔案內容》
|
Android NDK目前的缺點
目前Android NDK最為人詬病的是提供的系統函式庫API數量實在太少(僅有C/C++語言的部份標準函式庫、Android Log功能函式庫、與ZLib函式庫)。除了1.6版新提供的OpenGL ES函式庫,對於需要繪製3D畫面的開發者有較實質的幫助外,對一般希望能藉由調用Android系統函式庫來提升應用程式效能的開發者來說,幫助實在非常渺小。也因此,NDK的釋出對許多已經開發者而言,只不過提供了一個工具來協助他們連結應用程式與想要使用的原生函式庫;對於系統函式庫的存取,大部分對Android原始碼已有相當認識的開發者,大多會選擇無視Google的警告,持續使用他們想要使用的系統函式庫。例如,開發者可能會需要加速應用程式上圖像的繪製,而進一步想直接操控Android系統中負責圖片繪製的Skia繪圖引擎,此需求是必要且急迫的,那就只能硬著頭皮使用,而以版本控制的方式來避免未來該函式庫更名或移除的危機了。
另一點,則是關於原生程式碼部分除錯的難度。在一般開發C或C++程式時,開發者們通常會選擇使用IDE所附的除錯器,或以類似gdb的除錯工具來協助除錯,例如設定中斷點、查看變數內容等。Google在針對Android應用程式的開發上也有提供LogCat工具來協助開發者查看程式運行狀況。但對於要使用在Android應用程式內部的原生語言函式庫的開發就沒有以上工具的協助了,這使得原生語言部分的開發相當困難,除錯效率也相當低落。開發者目前幾乎必須先將原生語言的部分先加以抽離開來實作,同時進行傳統的除錯工作,待功能性無誤後,再代換入必須與Android應用程式之Java類別相接的部分來完成開發工作,而無法兩造同步進行開發。
Google自第一版NDK釋出後就不斷的在相關文件與網頁上宣稱在未來版本的NDK中會加入為原生程式碼設計的除錯工具。此工具將會透過gdb連線的方式,給予開發者儘可能多的資訊,且在不更動目前所有原始碼與設定檔的前提下協助開發者進行除錯的工作。不過截至目前為止各方尚沒有相關的訊息出現。
筆者截稿當晚Google恰好發佈Android NDK第3版,此版本主要是為了對應Android 2.0平台上OpengGL ES 2.0函式庫所做的更新。並更換所使用的編譯器版本,以及修改工具中的些許臭蟲。此版本沒有開放新的系統函式庫,對於除錯器也沒有進一步的消息。
結語
C與C++等原生語言對於Android應用程式的開發目前限制甚多,Google官方也屢屢強調原生語言僅適合實作於應用程式的某些部份。因此將應用程式的主要邏輯以Java類別形式撰寫,提昇開發效率與程式結構,有需要使用極高效率的運算處理時才使用原生語言或系統函式庫,這才是整個Android平台開發框架的立意所在。
---本文作者任職於資策會網路多媒體研究所---
註1.Google釋出的第三版Android NDK將名稱由類似「Android 1.6 NDK, Release 1(釋出1版)」的形式改為「Android NDK, Revision 3(修訂3版)」,此項更動是由於有很多開發者被之前1.6的版本名稱所誤導,誤以為Android 1.6 NDK所生成的應用程式只能執行在1.6版本或以上的Android平台。未來NDK的版本都會以「Android NDK, Revision x」的形式作為名稱,代表發佈的版本數,而支援的平台版本則另作說明。
|