نصائح لمورّدي البرمجيات الوسيطة

يؤدي توزيع البرمجيات الوسيطة التي تم إنشاؤها بواسطة NDK إلى بعض المشكلات الإضافية التي مطوري التطبيقات لا داعي للقلق بشأنها. تفرض المكتبات المنشأة مسبقًا بعضًا من خيارات التنفيذ الخاصة بهم على مستخدميها.

اختيار مستويات واجهة برمجة التطبيقات وإصدارات NDK

لا يمكن للمستخدمين استخدام إصدار minSdkVersion أقل من إصدارك. إذا كانت تجربة المستخدمين تطبيقات قيد التشغيل على واجهة برمجة التطبيقات 21، ولا يمكنك إنشاؤها لواجهة برمجة التطبيقات 24. لا بأس في إنشاء المكتبة على مستوى واجهة برمجة تطبيقات أقل من المستخدمين. يمكنك إنشاء واجهة برمجة تطبيقات 16 والحفاظ على التوافق مع مستخدمي واجهة برمجة التطبيقات 21.

إصدارات NDK متوافقة إلى حد كبير مع بعضها البعض، ولكن في بعض الأحيان تكون هناك تغييرات تضعف التوافق. إذا كنت تعلم أن جميع المستخدمين لديك يستخدمون نفس الإصدار من NDK، فمن الأفضل استخدام نفس الإصدار الذي يستخدمونه. أو يمكنك استخدام أحدث إصدار.

استخدام STL

إذا كنت تكتب C++ وتستخدم STL، فالخيار لك بين libc++_shared يؤثر libc++_static في المستخدمين في حال توزيع مكتبة مشتركة. إذا كنت لتوزيع مكتبة مشتركة، يجب إما استخدام libc++_shared أو التأكد من لا تعرض مكتبتك رموز libc++. أفضل طريقة للقيام بذلك هي أعلن عن واجهة ABI بشكل صريح باستخدام نص برمجي للإصدار (ويساعد ذلك أيضًا في الحفاظ على تفاصيل التنفيذ بشكل خاص). على سبيل المثال، يمكن استخدام مكتبة حسابية بسيطة النص البرمجي للإصدار التالي:

LIBMYMATH {
global:
    add;
    sub;
    mul;
    div;
    # C++ symbols in an extern block will be mangled automatically. See
    # https://stackoverflow.com/a/21845178/632035 for more examples.
    extern "C++" {
        "pow(int, int)";
    }
local:
    *;
};

يجب أن يكون النص البرمجي للإصدار هو الخيار المفضل لأنه الأقوى للتحكم في مستوى رؤية الرموز. وهذه أفضل ممارسةلجميع أو البرامج الوسيطة أو غير ذلك، إذ إنّها تمنع تفاصيل التنفيذ الكشف عنها وتحسِّن من وقت التحميل.

ويتوفّر خيار آخر أقل فعالية وهو استخدام -Wl,--exclude-libs,libc++_static.a -Wl,--exclude-libs,libc++abi.a عند الربط. وهذا أقل قوة لأنه سيتم فقط إخفاء الرموز في المكتبات ذات الأسماء الواضحة، يتم الإبلاغ عن بيانات التشخيص للمكتبات غير المستخدمة (خطأ إملائي في المكتبة الاسم ليس خطأ، وتقع على عاتق المستخدم عبء الحفاظ على قائمة المكتبة كذلك حتى الآن). ولا تُخفي هذه الطريقة أيضًا تفاصيل التنفيذ الخاصة بك.

توزيع المكتبات الأصلية في AAR

يمكن للمكوّن الإضافي لنظام Gradle المتوافق مع Android استيراد التبعيات الأصلية الموزعة في الاقتراحات المطبّقة تلقائيًا: إذا كان المستخدمون يستخدمون المكوّن الإضافي لنظام Gradle المتوافق مع Android، سيكون هذا هو أسهل طريقة لهم للاطّلاع على مكتبتك.

يمكن تجميع المكتبات الأصلية في ملف AAR من خلال AGP. سيكون هذا الخيار الأسهل إذا كان قد تم إنشاء مكتبتك باستخدام externalNativeBuild.

يمكن للإصدارات التي لا تستخدم AGP استخدام ndkports أو تنفيذ حزمة يدويًا من خلال اتّباع وثائق Prefab لإنشاء الدليل الفرعي prefab/ في AAR.

برمجيات Java الوسيطة مع مكتبات JNI

مكتبات Java التي تتضمن مكتبات JNI (بمعنى آخر، ملفات AAR التي تحتوي على jniLibs) إلى توخي الحذر من عدم تضمين مكتبات JNI التي تتضمنها تتداخل مع المكتبات الأخرى في تطبيق المستخدم. على سبيل المثال، إذا كانت ميزة "التطبيق التلقائي للاقتراحات" تتضمّن libc++_shared.so، ولكن إصدار libc++_shared.so مختلف عن التطبيق سيتم تثبيت تطبيق واحد فقط على حزمة APK، ما قد يؤدي إلى مخاطر السلوك.

الحل الأكثر موثوقية هو ألا تتضمن مكتبات Java أكثر من ملف واحد مكتبة JNI (هذه نصيحة جيدة للتطبيقات أيضًا). تُعد جميع التبعيات بما في ذلك يجب ربط STL بشكلٍ ثابت بمكتبة التنفيذ، النص البرمجي لفرض واجهة ABI. على سبيل المثال، مكتبة Java على com.example.foo التي تتضمن مكتبة JNI libfooimpl.so استخدام البرنامج النصي للإصدار التالي:

LIBFOOIMPL {
global:
    JNI_OnLoad;
local:
    *;
};

يستخدم هذا المثال registerNatives من خلال JNI_OnLoad كما هو موضّح في نصائح مبادرة أخبار Google. لضمان الكشف عن الحد الأدنى من سطح واجهة التطبيق الثنائية (ABI) وأن مدة تحميل المكتبة هي تم تصغيرها.