تعمل هذه المكتبة على تبسيط استخدام مكتبات Kotlin/JS من برامج Kotlin/JVM وKotlin/Native. فهو يجعل جلب التعليمات البرمجية أمرًا سهلاً مثل جلب البيانات:
يعمل Zipline عن طريق تضمين محرك JavaScript QuickJS في برنامج Kotlin/JVM أو Kotlin/Native. إنه محرك JavaScript صغير وسريع ومناسب تمامًا للتضمين في التطبيقات.
(هل تبحث عن Duktape Android؟)
لنصنع لعبة معلومات عامة تحتوي على أسئلة جديدة كل يوم، حتى لو لم يقوم المستخدمون بتحديث تطبيقاتهم. نحدد الواجهة الخاصة بنا بشكل commonMain
حتى نتمكن من استدعائها من Kotlin/JVM وتنفيذها في Kotlin/JS.
interface TriviaService : ZiplineService {
fun games (): List < TriviaGame >
fun answer ( questionId : String , answer : String ): AnswerResult
}
بعد ذلك نقوم بتنفيذه في jsMain
:
class RealTriviaService : TriviaService {
// ...
}
دعونا نربط التنفيذ الذي يعمل في Kotlin/JS بالواجهة التي تعمل في Kotlin/JVM. في jsMain
نحدد دالة مُصدَّرة لربط التنفيذ:
@JsExport
fun launchZipline () {
val zipline = Zipline .get()
zipline.bind< TriviaService >( " triviaService " , RealTriviaService ())
}
يمكننا الآن بدء خادم تطوير لخدمة JavaScript لأي تطبيقات قيد التشغيل تطلب ذلك.
$ ./gradlew -p samples trivia:trivia-js:serveDevelopmentZipline --info --continuous
لاحظ أن هذا Gradle لن يصل أبدًا إلى 100%. هذا متوقع. نريد أن يظل خادم التطوير قيد التشغيل. لاحظ أيضًا أن العلامة --continuous
ستؤدي إلى إعادة الترجمة كلما تغير الكود.
يمكنك رؤية بيان التطبيق المقدم على المضيف المحلي:8080/manifest.zipline.json. يشير إلى كافة وحدات التعليمات البرمجية للتطبيق.
في jvmMain
نحتاج إلى كتابة برنامج يقوم بتنزيل كود Kotlin/JS الخاص بنا ويستدعيه. نحن نستخدم ZiplineLoader
الذي يتعامل مع تنزيل التعليمات البرمجية والتخزين المؤقت والتحميل. نقوم بإنشاء Dispatcher
لتشغيل Kotlin/JS عليه. يجب أن يكون هذا مرسلًا ذو مؤشر ترابط واحد حيث يجب أن يقتصر كل مثيل Zipline على مؤشر ترابط واحد.
suspend fun launchZipline ( dispatcher : CoroutineDispatcher ): Zipline {
val manifestUrl = " http://localhost:8080/manifest.zipline.json "
val loader = ZiplineLoader (
dispatcher,
ManifestVerifier . NO_SIGNATURE_CHECKS ,
OkHttpClient (),
)
return loader.loadOnce( " trivia " , manifestUrl)
}
نقوم الآن ببناء وتشغيل برنامج JVM لتجميعه معًا. قم بذلك في محطة منفصلة عن خادم التطوير!
$ ./gradlew -p samples trivia:trivia-host:shadowJar
java -jar samples/trivia/trivia-host/build/libs/trivia-host-all.jar
تعمل Zipline على تسهيل مشاركة الواجهات مع Kotlin/JS. حدد واجهة في commonMain
، وقم بتنفيذها في Kotlin/JS، واستدعائها من النظام الأساسي المضيف. أو افعل العكس: قم بتنفيذه على النظام الأساسي المضيف واستدعائه من Kotlin/JS.
يجب أن تقوم الواجهات الجسرية بتوسيع ZiplineService
، الذي يحدد طريقة close()
واحدة لتحرير الموارد المحفوظة.
افتراضيًا، تكون الوسيطات وقيم الإرجاع عبارة عن قيمة تمريرية. يستخدم Zipline kotlinx.serialization لتشفير وفك تشفير القيم التي تم تمريرها عبر الحدود.
أنواع الواجهة التي تمتد من ZiplineService
هي عبارة عن مرجع تمريري: قد يقوم جهاز الاستقبال باستدعاء الأساليب في مثيل مباشر.
قد تكون وظائف الواجهة معلقة. داخليًا، تطبق Zipline setTimeout()
لجعل التعليمات البرمجية غير المتزامنة تعمل كما هو مفترض في Kotlin/JS.
يدعم Zipline أيضًا Flow<T>
كمعلمة أو نوع إرجاع. وهذا يجعل من السهل بناء أنظمة تفاعلية.
أحد الاختناقات المحتملة لتضمين JavaScript هو انتظار المحرك لتجميع كود مصدر الإدخال. يقوم Zipline بترجمة JavaScript مسبقًا إلى رمز ثانوي فعال لـ QuickJS للتخلص من عقوبة الأداء هذه.
هناك عنق الزجاجة الآخر وهو انتظار تنزيل الكود. يعالج Zipline هذا الأمر من خلال دعم التطبيقات المعيارية. يتم تنزيل كل وحدة إدخال (مثل مكتبات Kotlin القياسية والتسلسلية والكوروتينية) بشكل متزامن. يتم تخزين كل وحدة تم تنزيلها مؤقتًا. يمكن أيضًا تضمين الوحدات مع التطبيق المضيف لتجنب أي تنزيلات إذا كانت الشبكة غير قابلة للوصول. إذا كانت وحدة التطبيق الخاصة بك تتغير بشكل متكرر أكثر من مكتباتك، فسيقوم المستخدمون بتنزيل ما تم تغييره فقط.
إذا واجهت مشاكل في الأداء في وقت تشغيل QuickJS، فإن Zipline يتضمن ملف تعريف لأخذ العينات. يمكنك استخدام هذا للحصول على تفاصيل لكيفية قضاء تطبيقك لوقت وحدة المعالجة المركزية (CPU).
تطبق Zipline console.log
عن طريق إعادة توجيه الرسائل إلى النظام الأساسي المضيف. ويستخدم android.util.Log
على Android، java.util.logging
على JVM، و stdout
على Kotlin/Native.
يقوم Zipline بدمج خرائط مصدر Kotlin في كود QuickJS الثانوي. إذا تعطلت العملية، فسيقوم نظام التتبع المكدس بطباعة ملفات .kt
وأرقام الأسطر. على الرغم من وجود جافا سكريبت بالأسفل، لا يحتاج المطورون إلى التعامل مع ملفات .js
.
بعد استخدام الواجهة الموصلة، يجب إغلاقها حتى يمكن جمع البيانات المهملة من كائن النظير. يصعب تنفيذ هذا الأمر بشكل صحيح، لذا تستعير Zipline أفكارًا من LeakCanary وتكتشف بقوة عند فقدان مكالمة close()
.
يدعم Zipline توقيعات EdDSA Ed25519 وECDSA P-256 لمصادقة المكتبات التي تم تنزيلها.
الإعداد واضح ومباشر. قم بإنشاء زوج مفاتيح EdDSA. يتم تثبيت مهمة لهذا باستخدام البرنامج المساعد Zipline Gradle.
$ ./gradlew :generateZiplineManifestKeyPairEd25519
...
---------------- ----------------------------------------------------------------
ALGORITHM: Ed25519
PUBLIC KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
PRIVATE KEY: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
---------------- ----------------------------------------------------------------
...
ضع المفتاح الخاص على خادم الإنشاء وقم بتكوينه لتوقيع الإصدارات:
zipline {
signingKeys {
create( " key1 " ) {
privateKeyHex.set( .. .)
algorithmId.set(app.cash.zipline.loader. SignatureAlgorithmId . Ed25519 )
}
}
}
ضع المفتاح العام في كل تطبيق مضيف وقم بتكوينه للتحقق من التوقيعات:
val manifestVerifier = ManifestVerifier . Builder ()
.addEd25519( " key1 " , .. .)
.build()
val loader = ZiplineLoader (
manifestVerifier = manifestVerifier,
.. .
)
يقبل كل من التوقيع والتحقق مفاتيح متعددة لدعم تدوير المفاتيح.
تم تصميم Zipline لتشغيل التعليمات البرمجية الخاصة بمؤسستك في الوقت والمكان الذي تريده. لا يوفر وضع الحماية أو عزل العملية ولا يجب استخدامه لتنفيذ تعليمات برمجية غير موثوقة.
ومن الضروري أن نأخذ في الاعتبار أن هذا التصميم يضع ثقة ضمنية على:
ولا يحمي من أي نوع من التنازلات المذكورة أعلاه.
كما أنه لا يوفر حتى الآن آلية لحظر الإصدارات الأقدم (الموقعة) من التعليمات البرمجية القابلة للتنفيذ والتي بها مشكلات معروفة.
هناك بعض الأشياء التي يمكنك القيام بها للتأكد من أن إعادة التحميل السريع تعمل بأسرع ما يمكن:
kotlin.incremental.js.ir=true
لتمكين الترجمة التزايدية لـ Kotlin/JS.org.gradle.unsafe.configuration-cache=true
لتمكين ذاكرة التخزين المؤقت لتكوين Gradle.tasks.withType(DukatTask::class) { enabled = false }
لإيقاف تشغيل مهمة Dukat إذا كنت لا تستخدم إعلانات نوع TypeScript.يعمل Zipline على Android 4.3+ (مستوى API 18+)، وJava 8+، وKotlin/Native.
يستخدم Zipline واجهات برمجة التطبيقات غير المستقرة في تنفيذه وهو حساس لتحديثات الإصدار لهذه المكونات.
عنصر | النسخة المدعومة | ملحوظات |
---|---|---|
مترجم كوتلين | 2.0.0 | لا تحتوي المكونات الإضافية لمترجم Kotlin على واجهة برمجة تطبيقات مستقرة حتى الآن. |
تسلسل كوتلين | 1.6.3 | بالنسبة إلى decodeFromDynamic() و encodeToDynamic() و ContextualSerializer . |
كوتلين كوروتينس | 1.8.1 | بالنسبة إلى transformLatest() و Deferred.getCompleted() و CoroutineStart.ATOMIC . |
نعتزم استخدام واجهات برمجة التطبيقات الثابتة بمجرد توفرها.
نعتزم الحفاظ على قابلية التشغيل المتبادل لإصدارات مضيف Zipline وإصدارات وقت التشغيل حتى تتمكن من ترقية كل منها بشكل مستقل.
نسخة المضيف Zipline | إصدارات Zipline المدعومة لوقت التشغيل |
---|---|
0.x | بالضبط نفس الإصدار 0.x مثل المضيف. |
1.x | أي إصدار 1.x. |
Copyright 2015 Square, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
كان هذا المشروع يُعرف سابقًا باسم Duktape-Android وقام بتجميع محرك Duktape JavaScript لنظام Android. لا يزال سجل Duktape موجودًا في هذا الريبو وكذلك علامات الإصدار. الإصدارات المتاحة مدرجة في Maven Central.