完成 NDK(Native Development Kit)的安裝和設置,便可以使用編程測試 NDK 功能。首先是要創建一個新的支持 C++ 空項目開始,這樣是相對簡單直接,並且要添加 C++ 庫的話,這個就稍微麻煩一點,需要自行添加相關的幾個文件了,可以參見下面比較這兩種工程之間的不同。
Android Studio + NDK 測試程式 |
- 操作系統:Windows 7 64-bit 版本
- 開發環境:Android Studio 4.0.1 版本
- Gradle 版本:6.1.1
- 手機測試版本:API 19
- 原程式:C:\Development\Development_Android\Android_Project\NDK
- 程式:C:\Development\Development_Android\Android_Project\NDK
- NDK 版本:NDK 21.0.6113669 版本 Android
1﹒首先是創建新 Native C++ 項目
Start a new Android Studio project→Native C++→Next→Name=NDK→Next→C++11(可選擇Toolchain / C++11 / C++14 / C++17)→Finish
創建新 Native C++ 項目 |
2﹒完成創建新 Native C++ 項目後,Android Studio 會自動產生完整的 Jave 呼叫 C++ 的程式,包括 CMakeLists.txt、native-lib.cpp、MainActivity.java 和 active_main.xml 文件,馬上 Run App 便可以測試 NDK。
app / java / MainActivity.java:
package bugworkshop.blogspot.ndk;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle; import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib"); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// Example of a call to a native method TextView tv = findViewById(R.id.sample_text); tv.setText(stringFromJNI()); }
/** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native String stringFromJNI(); } |
app / res / layout / active_main.xml:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<TextView android:id="@+id/sample_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> |
app / cpp / native-lib.cpp:
#include <jni.h> #include <string>
extern "C" JNIEXPORT jstring JNICALL Java_bugworkshop_blogspot_ndk_MainActivity_stringFromJNI( JNIEnv* env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } |
簡單說明 native-lib.cpp:
- extern "C":實現 C 和 C++ 的混合程式設計,用於 C++ 代碼調用 C 的函數。
- JNIEXPORT 和 JNICALL,用於標識函數用途的兩個巨集。
- jstring,JNI 中的資料類型,對應 Java 中 String 類型,還有 8 種基底資料型別 jbyte、jchar、jshort、jint、jlong、jfloat、jdouble、jboolean,引用資料類型 jintArray、jshortArray、jlongArray 等。
- 函數命名規則:Java_類全路徑_方法名,這裡的類是那個調用 C 或 C++ 的類,像這裡的Java_bugworkshop_blogspot_ndk_MainActivity_stringFromJNI。 函數至少有兩個參數,第一個參數 :JNIEnv* 是定義任意 native 函數的第一個參數(包括調用 JNI 的 RegisterNatives 函數註冊的函數),指向 JVM 函數表的指標,函數表中的每一個入口指向一個 JNI 函數,每個函數用於訪問 JVM 中特定的資料結構;第二個參數:調用 Java 中 native 方法的實例或 Class 物件,如果這個 native 方法是實例方法,則該參數是 jobject,如果是靜態方法,則是 jclass。
沒有留言:
張貼留言