דוגמה: hello-jni

בדוגמה הזו נסביר על hello-jni, אפליקציה מינימלית ב-C/C++ שנוצרה באמצעות NDK. הדוגמה הזו נמצאת בתיקייה hello-jni במאגר ndk-samples, בתוך ההסתעפות android-mk.

Android.mk

בשתי השורות הבאות מופיע שם קובץ המקור המקורי, יחד עם שם הספרייה המשותפת ליצירה. השם המלא של הספרייה שנוצרה הוא libhello-jni.so, אחרי שמערכת ה-build מוסיפה את הקידומת lib והסיומת .so.

LOCAL_SRC_FILES := hello-jni.c
LOCAL_MODULE    := hello-jni

למידע נוסף על הפונקציות של הקובץ Android.mk ועל אופן השימוש בו, קראו את המאמר Android.mk.

Application.mk

השורה הזו מנחה את מערכת ה-build לגבי המעבד (CPU) והארכיטקטורה שמהם יש לבנות. בדוגמה הזו, מערכת ה-build יוצרת גרסאות לכל הארכיטקטורות הנתמכות.

APP_ABI := all

למידע נוסף על הקובץ Application.mk ועל אופן השימוש בו, ראו Application.mk.

הטמעה בצד Java

הקובץ helloJNI.java נמצא ב-hellojni/src/com/example/hellojni/. הוא קורא לפונקציה כדי לאחזר מחרוזת מהצד המקורי, ואז מציג אותה במסך.

קוד המקור מכיל שלוש שורות שמעניינות במיוחד את משתמשי NDK. הן מוצגות כאן לפי הסדר שבו משתמשים בהן, ולא לפי סדר השורות.

קריאת הפונקציה הזו טוענת את הקובץ .so בזמן הפעלת האפליקציה.

Kotlin

System.loadLibrary("hello-jni")

Java

System.loadLibrary("hello-jni");

מילת המפתח native בהצהרה על השיטה הזו מאפשרת למכונה הווירטואלית לדעת שהפונקציה נמצאת בספרייה המשותפת (כלומר, שהיא מיושמת בצד המקורי).

Kotlin

external fun stringFromJNI(): String

Java

public native String stringFromJNI();

מסגרת Android קוראת לפונקציה שנטענה והוצהרה בשלבים הקודמים, ומציגה את המחרוזת במסך.

Kotlin

tv.text = stringFromJNI()

Java

tv.setText( stringFromJNI() );

הטמעה בצד C

הקובץ hello-jni.c נמצא ב-hello-jni/jni/. הוא מכיל פונקציה שמחזירה מחרוזת שצד Java ביקש). הצהרת הפונקציה היא:

JNIEXPORT jstring JNICALL
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )

ההצהרה הזו תואמת לפונקציה המקומית שהוגדרה בקוד המקור של Java. הסוג המוחזר, jstring, הוא סוג נתונים שמוגדר במפרט הממשק של Java Native. זהו לא מחרוזת, אלא פוינטר למחרוזת Java.

אחרי jstring מופיע שם הפונקציה, שמבוסס על שם הפונקציה ב-Java ועל הנתיב לקובץ שמכיל אותה. יוצרים אותו לפי הכללים הבאים:

  • מוסיפים את Java_ בתחילת השם.
  • תיאור נתיב הקובץ ביחס לספריית המקור ברמה העליונה.
  • משתמשים בקו תחתון במקום בקו נטוי קדימה.
  • השמטת את סיומת הקובץ .java.
  • אחרי הקו התחתון האחרון, מוסיפים את שם הפונקציה.

בהתאם לכללים האלו, הדוגמה הזו משתמשת בשם הפונקציה Java_com_example_hellojni_HelloJni_stringFromJNI. השם הזה מתייחס לפונקציית Java‏ stringFromJNI() שנמצאת ב-hellojni/src/com/example/hellojni/HelloJni.java.

JNIEnv* הוא הפונקציה שמצביעה על המכונה הווירטואלית, ו-jobject הוא הפונקציה שמצביעה על אובייקט this המשתמעים שהועברו מצד Java.

השורה הבאה קוראת ל-VM API‏ (*env) ומעבירה לו ערך החזרה: כלומר, המחרוזת שהפונקציה בצד Java ביקשה.

return (*env)->NewStringUTF(env, "Hello from JNI !
Compiled with ABI " ABI ".");