概念

事前準備

本指南假設您已掌握原生程式設計和 Android 開發中的概念。

簡介

本節會概略解釋 NDK 的運作方式。Android NDK 是我們推出的一套工具,讓您可以將 C 或 C++ (「原生程式碼」) 嵌入 Android 應用程式中。如果是想要執行以下一或多項操作的開發人員,則在 Android 應用程式中使用原生程式碼的功能特別實用:

  • 在不同平台之間移植應用程式。
  • 重複使用現有的程式庫,或開放自己的程式庫供他人重複使用。
  • 提高特定情況下的效能,特別是在玩遊戲等需要進行大量運算的情況下。

運作方式

本節介紹建立 Android 原生應用程式時使用的主要元件,然後說明建立和封裝程序。

主要元件

在建立應用程式時,您應該瞭解一下以下元件:

  • 原生共享程式庫:NDK 會從 C/C++ 原始碼建構這些程式庫或 .so 檔案。

  • 原生靜態程式庫:NDK 也可以建構靜態程式庫或 .a 檔案,而您可以將這些檔案連結至其他程式庫。

  • Java Native Interface (JNI):JNI 是 Java 與 C++ 元件通訊時所用的介面。本指南介紹 JNI 的相關知識;如要瞭解與 JNI 相關的資訊,請參閱 Java Native Interface 規範

  • 應用程式二進位檔介面 (ABI):ABI 明確定義應用程式機器碼與執行階段系統互動的方式。NDK 會根據這些定義建立 .so 檔案。不同的 ABI 會對應到不同的架構:NDK 支援 32 位元 ARM、AArch64、x86 和 x86-64 的 ABI。詳情請參閱 Android ABI

  • 資訊清單:如要編寫不含 Java 元件的應用程式,必須在資訊清單中宣告 NativeActivity 類別。請參閱使用 native_activity.h 介面的內容,進一步瞭解如何宣告。

流程

開發 Android 原生應用程式的一般流程如下:

  1. 設計應用程式、決定要在 Java 中實作的部分,以及要以原生程式碼的形式實作的部分。

  2. 您可以比照建立其他 Android 專案的方式,建立一個 Android 應用程式專案。

  3. 如要編寫僅限原生的應用程式,請在 AndroidManifest.xml 中宣告 NativeActivity 類別。詳情請參閱原生活動和應用程式

  4. 建立提供原生資料庫說明的 Android.mk 檔案,包括名稱、旗標、已連結的程式庫和要在「JNI」目錄中編譯的來源檔案。

  5. 您也可以視需要建立 Application.mk 檔案來設定目標 ABI、工具鏈、發布/偵錯模式和 STL。如果並未針對上述任何一項指定值,則系統將分別套用下列預設值:

    • ABI:所有未淘汰的 ABI
    • 模式:發布
    • STL:系統
  6. 將原生來源存放在專案的 jni 目錄下。

  7. 使用 ndk-build 編譯原生 (.so.a) 程式庫。

  8. 建立 Java 元件,產生可執行的 .dex 檔案。

  9. .so.dex 以及執行應用程式所需的其他檔案等所有內容封裝至 APK 檔案。

原生活動和應用程式

Android SDK 提供 NativeActivity 輔助類別,讓您可以編寫完全原生的活動。NativeActivity 會處理 Android 架構與原生程式碼之間的通訊,因此您無需為其建立子類別或呼叫方法,只需在 AndroidManifest.xml 檔案中將應用程式宣告為原生,然後開始建立原生應用程式即可。

使用 NativeActivity 的 Android 應用程式仍會在其虛擬機器中執行,並以沙箱的形式與其他應用程式分隔。因此,您仍可透過 JNI 存取 Android 架構 API。在某些情況下 (例如用於感應器、輸入事件和資產),NDK 提供可用的原生介面,讓您無需透過 JNI 呼叫。如要進一步瞭解此類支援,請參閱原生 API

無論您是否在開發原生活動,我們建議您使用傳統 Android 建立工具建立專案,這有助於確保以正確的結構建立及封裝 Android 應用程式。

Android NDK 提供以下 2 種實作原生活動的方式:

  • native_activity.h 標頭會定義原生版本的 NativeActivity 類別,當中包含建立原生活動所需的回呼介面和資料結構。由於應用程式的主執行緒會處理回呼,因此不得封鎖您的回呼實作。否則,您可能會因為主執行緒在回呼傳回前沒有回應,而收到 ANR (應用程式無回應) 錯誤。
  • android_native_app_glue.h 檔案會定義在 native_activity.h 介面頂端建構的靜態輔助程式庫。這會產生另一個執行緒,用於處理事件迴圈中的回呼或輸入事件等。將這些事件移至另一個執行緒,可防止任何回呼封鎖主執行緒。

您也可以使用 <ndk_root>/sources/android/native_app_glue/android_native_app_glue.c 來源來修改實作。

如要進一步瞭解如何使用此靜態程式庫,請參閱原生活動範例應用程式及其說明文件。此外,您亦可查看 <ndk_root>/sources/android/native_app_glue/android_native_app_glue.h 檔案中的註解,以便瞭解更多資訊。

使用 native_activity.h 介面

如要透過 native_activity.h 介面實作原生活動,請執行以下操作:

  1. 在專案的根目錄中建立 jni/ 目錄,這個目錄會儲存所有原生程式碼。

  2. AndroidManifest.xml 檔案中宣告您的原生活動。

    由於您的應用程式沒有 Java 程式碼,因此請將 android:hasCode 設為 false

    <application android:label="@string/app_name" android:hasCode="false">
    

    您必須將活動標記的 android:name 屬性設為 NativeActivity

    <activity android:name="android.app.NativeActivity"
              android:label="@string/app_name">
    

    meta-data 標記的 android:value 屬性會指定含有應用程式進入點的共享程式庫名稱 (例如 C/C++ main),同時會省略程式庫名稱中的 lib 前置字串和 .so 後置字串。

    <manifest>
      <application>
        <activity>
          <meta-data android:name="android.app.lib_name"
                     android:value="native-activity" />
          <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
        </activity>
      </application>
    </manifest>
    
  3. 建立用於原生活動的檔案,並實作 ANativeActivity_onCreate 變數中指定的函式。應用程式會在原生活動啟動時呼叫此函式。此函式與 C/C++ 中的 main 相似,它會接收 ANativeActivity 結構的指標,而此結構中包含需要編寫的各個回呼實作的函式指標。在 ANativeActivity->callbacks 中,將適用的回呼函式指標設為回呼的實作。

  4. ANativeActivity->instance 欄位設為您要使用的任何特定資料的執行個體位址。

  5. 實作您希望活動在啟動時執行的其他操作。

  6. 實作您在 ANativeActivity->callbacks 中設定的其他回呼。如要進一步瞭解系統呼叫回呼的時機,請參閱管理活動生命週期

  7. 開發應用程式的其他部分。

  8. 在專案的 jni/ 目錄中建立 Android.mk file 以向建構系統描述原生模組。詳情請參閱 Android.mk

  9. 取得 Android.mk 檔案後,請透過 ndk-build 指令編譯您的原生程式碼。

    cd <path>/<to>/<project>
    $NDK/ndk-build
    
  10. 依照平常的方式建立及安裝 Android 專案。如果原生程式碼位於 jni/ 目錄中,則建立指令碼會自動將根據原生程式碼建立的 .so 檔案封裝至 APK。

其他程式碼範例

如要下載 NDK 範例,請參閱 NDK 範例