מושגים

לפני שמתחילים

המדריך הזה מניח שאתם כבר מכירים את המושגים שטבועים ב- בתכנות נייטיב ובפיתוח Android.

מבוא

בקטע הזה יש הסבר כללי על אופן הפעולה של ה-NDK. Android NDK הוא קבוצה של שיעזרו לכם להטמיע את C או C++ ("קוד מקורי") באפליקציות שלכם ל-Android. היכולת להשתמש קוד מקורי באפליקציות Android יכול להיות שימושי במיוחד למפתחים שרוצים לבצע אחת או יותר הבאים:

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

איך זה עובד

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

רכיבים עיקריים

אתם צריכים להבין את הרכיבים הבאים בזמן שאתם יוצרים את app:

  • ספריות משותפות מקוריות: ה-NDK יוצר את הספריות האלה, או .so קבצים, מ- את קוד המקור C/C++

  • ספריות סטטיות נייטיב: ה-NDK יכול גם ליצור ספריות סטטיות, או .a קבצים, שאותם ניתן לקשר לספריות אחרות.

  • Java Native Interface (JNI): ה-JNI הוא הממשק שדרכו ה-Java רכיבי C++ מדברים זה עם זה. המדריך הזה מבוסס על ההנחה שיש לכם ידע על ה-JNI. כדי לקבל מידע נוסף, אפשר לעיין במפרט ממשק ה-Native של Java.

  • Application Binary Interface (ABI): ה-ABI מגדיר בדיוק את האופן שבו האפליקציה הוא אמור לקיים אינטראקציה עם המערכת בזמן הריצה. ה-NDK יוצרת .so קבצים בהתאם להגדרות האלה. ממשקי ABI שונים מתאימים ארכיטקטורות שונות: ה-NDK כולל תמיכת ABI עבור 32-bit ARM, AArch64, x86 ו-x86-64. אפשר למצוא מידע נוסף במאמר Android ממשקי ABI.

  • מניפסט: אם אתם כותבים אפליקציה שאין בה רכיב Java, צריך להצהיר על המחלקה NativeActivity ב מניפסט. אפשר לעיין בקטע שימוש Native_activity.h Interface לקבלת פרטים נוספים על האופן שבו ניתן לעשות זאת.

קצב הזרימה

התהליך הכללי לפיתוח אפליקציה מותאמת ל-Android הוא:

  1. לעצב את האפליקציה ולקבוע אילו חלקים להטמיע ב-Java ואילו חלקים להטמעה כקוד Native.

  2. יוצרים פרויקט של אפליקציה ל-Android כמו שעושים לכל פרויקט אחר ב-Android.

  3. אם אתם כותבים אפליקציה מותאמת בלבד, צריך להצהיר על הכיתה NativeActivity ב AndroidManifest.xml. אפשר לקרוא מידע נוסף בקטע פעילויות מותאמות .

  4. יוצרים קובץ Android.mk שמתאר את ספריית הנייטיב, כולל השם, דגלים, ספריות מקושרות וקובצי מקור שיקודמו ב-"JNI"

  5. אפשר גם ליצור קובץ Application.mk להגדרת היעד ממשקי ABI , Toolchain, מצב גרסה/ניפוי באגים ו-STL. בכל אחת מהפעולות האלה לא לציין, נעשה שימוש בערכי ברירת המחדל הבאים, בהתאמה:

    • ABI: כל ממשקי ה-ABI שלא הוצאו משימוש
    • מצב: השקה
    • STL: מערכת
  6. מציבים את המקור המקורי בספריית jni של הפרויקט.

  7. צריך להשתמש ב-ndk-build כדי להדר את ספריות ה-Native (.so, .a).

  8. יוצרים את רכיב ה-Java ומפיקים את קובץ ההפעלה .dex.

  9. אפשר לאחסן הכול בקובץ APK שמכיל את .so, .dex ועוד הקבצים הדרושים להפעלת האפליקציה.

פעילויות ואפליקציות מקוריות

ב-Android SDK יש מחלקה עוזרת, NativeActivity, שמאפשרת לכם: לכתוב פעילות מקומית לחלוטין. NativeActivity מטפל בתקשורת בין ה-framework של Android לבין קוד ה-Native, כך שאתם לא צריכים לתת לו סיווג משנה או לקרוא לשיטות שלו. כל מה שצריך לעשות הוא להצהיר על הבקשה להיות מקורי בקובץ AndroidManifest.xml שלך, ולהתחיל ליצור תרגום מכונה.

אפליקציה ל-Android שמשתמשת ב-NativeActivity עדיין פועלת בסביבה וירטואלית משלה במחשב, בארגז חול מאפליקציות אחרות. לכן אתם עדיין יכולים לגשת ממשקי API של Android framework דרך ה-JNI. במקרים מסוימים, למשל במקרה של חיישנים, אירועי קלט ונכסים, ה-NDK מספק ממשקים מותאמים שאפשר להשתמש בהם במקום להתקשר אל ה-JNI. לקבלת מידע נוסף על תמיכה, ראו ממשקי API נייטיב.

לא משנה אם אתם מפתחים פעילות מקומית, מומלץ שאפשר ליצור פרויקטים באמצעות כלי ה-build המסורתיים של Android. אם עושים את זה עוזר להבטיח יצירה ואריזה של אפליקציות ל-Android שלנו.

ב-Android NDK יש שתי אפשרויות להטמעת הפעילות המותאמת:

  • הכותרת native_activity.h מגדיר את הגרסה המקורית של המחלקה NativeActivity. הוא מכיל את ממשק קריאה חוזרת ומבני נתונים שנדרשים כדי ליצור את פעילות. מכיוון שה-thread הראשי של האפליקציה מטפל בקריאות החוזרות (callback), אסור שההטמעות של הקריאה החוזרת חוסמות. אם הוא יחסום, ייתכן לקבל שגיאות ANR (האפליקציה לא מגיבה) כי ה-thread הראשי התגובה לא מגיבה עד שהקריאה החוזרת תחזור.
  • הקובץ android_native_app_glue.h מגדיר ספריית עזרה סטטית שמבוססת על בחלק העליון של הממשק native_activity.h. זה יצר שרשור נוסף, מטפל בדברים כמו קריאות חוזרות (callback) או אירועי קלט בלולאת אירועים. מעבר השרשורים האלו בשרשור נפרד מונעים קריאות חוזרות (callback) וחסימה של ה-thread הראשי.

<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/ בתיקיית השורש של הפרויקט. הספרייה הזו שומר את כל קודי ה-Native שלכם.

  2. יש להצהיר על הפעילות המותאמת בקובץ AndroidManifest.xml.

    צריך להגדיר את android:hasCode לערך false כי לאפליקציה שלך אין קוד Java.

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

    צריך להגדיר את המאפיין android:name של תג הפעילות כ- NativeActivity.

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

    המאפיין android:value של התג meta-data מציין את השם של לספרייה המשותפת שמכילה את נקודת הכניסה לאפליקציה (למשל 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. האפליקציה מפעילה את הפונקציה הזו כאשר הפעילות של הנייטיב מתחילה. הפונקציה הזו, שמקבילה ל-main ב-C/C++, מקבלת מצביע למבנה של ANativeActivity, שמכיל סמנים של פונקציות. לאפליקציות השונות של קריאה חוזרת (callback) שצריך לכתוב. מגדירים את המצביעים הרלוונטיים של פונקציית הקריאה החוזרת ב-ANativeActivity->callbacks אל של הקריאות החוזרות (callback).

  4. מגדירים את השדה ANativeActivity->instance לכתובת של כל מופע של של הנתונים הספציפיים שבהם רוצים להשתמש.

  5. ישם כל דבר נוסף שאתם רוצים שהפעילות שלכם תבצע כשמתחילים.

  6. הטמעה של שאר הקריאות החוזרות שהגדרת ANativeActivity->callbacks כדי לקבל מידע נוסף על המועדים של הקריאות החוזרות (callback) שנקראו במאמר ניהול מחזור החיים של פעילות.

  7. מפתחים את שאר האפליקציות.

  8. צריך ליצור Android.mk file בספרייה jni/ של הפרויקט כדי לתאר את המודול המקורי למערכת ה-build. מידע נוסף זמין במאמר הבא: Android.mk

  9. לאחר שיש לך קובץ Android.mk, הידור את קוד ה-Native שלך באמצעות הפקודה ndk-build.

    cd <path>/<to>/<project>
    $NDK/ndk-build
    
  10. יוצרים ומתקינים את פרויקט Android כרגיל. אם קוד ה-Native שלכם הוא הספרייה jni/, סקריפט ה-build מקבץ באופן אוטומטי את קובץ ה-.so קבצים שנוצרו ממנו ב-APK.

קוד לדוגמה נוסף

כדי להוריד דוגמאות NDK, אפשר לעיין בדגימות NDK.