دليل التطوير على منصة أندرويد في كوردوفا

من موسوعة حسوب

يوضح هذا الدليل كيفية إعداد بيئة SDK لنشر تطبيقات كوردوفا لأجهزة أندرويد، وكيفية استخدام أدوات سطر الأوامر المتمحورة حول أندرويد اختياريًا في سير عمل التطوير الخاص بك. تحتاج إلى تثبيت Android SDK بغض النظر عما إذا كنت تريد استخدام أدوات الصدفة (shell) المتمحورة حول المنصة أو سطر الأوامر العابر للمنصات لأغراض التطوير. للمقارنة بين مساري التطوير، راجع صفحة نظرة عامة التي شُرح فيها كل مسار عمل على حدة. وللحصول على تفاصيل حول سطر الأوامر، انتقل إلى صفحة واجهة سطر الأوامر في كوردوفا.

المتطلبات والدعم

استعمال كوردوفا من أجل أندرويد يتطلب Android SDK الذي يمكن تثبيته على OS X أو لينكس أو ويندوز. راجع متطلبات النظام من أجل تثبيت Android SDK. تدعم أحدث حزمة من أندرويد في كوردوفا المستوى 28 للواجهة البرمجية (Android API-Level). يمكن العثور على مستويات Android API المعتمدة وإصدارات Android لإصدارات كوردوفا-أندرويد الماضية في الجدول التالي:

إصدار كوردوفا-أندرويد مستويات واجهة أندرويد البرمجية المدعومة إصدار أندرويد المقابل
‎8.X.X 1‎9 - 28 ‎4.4 - 9.0.0
‎7.X.X 1‎9 - 27 ‎4.4 - 8.1
6‎.X.X ‎16 - 26 4.1‎ - 8.0.0
5‎.X.X ‎14 - 23 ‎4.0 - 6.0.1
4.1‎.X ‎14 - 22 4.0‎ - 5.1
‎4.0.X ‎10 - 22 2.3.‎3 - 5.1
‎3.7.X ‎10 - 21 ‎2.3.3 - 5.0.2

يرجى ملاحظة أن الإصدارات المذكورة هنا لأجل حزمة كوردوفا-أندرويد (cordova-android) وليس من أجل سطر أوامر كوردوفا. ولأجل تحديد إصدار حزمة أندرويد من كوردوفا المثبت في مشروعك الخاص، قم بتنفيذ الأمر cordova platform ls في المجلد الذي يحتوي على المشروع الخاص بك.

كقاعدة عامة، تصبح إصدارات أندرويد غير مدعومة من قِبل كوردوفا إذا انخفضت إلى أقل من 5٪ على لوحة بيانات التوزيع من Google.

تثبيت المتطلبات

مجموعة تطوير جافا (JDK)

قم بتثبيت مجموعة تطوير جافا الإصدار JDK) 8). عند التثبيت على ويندوز، يجب أيضًا تعيين متغير البيئة JAVA_HOME وفقًا لمسار تثبيت JDK الخاص بك (اطلع على القسم إعداد متغيرات البيئة في الأسفل).

Gradle

بالنسبة لكوردوفا-أندرويد 6.4.0، أصبح Gradle مطلوبًا الآن تثبيته لبناء أندرويد.

عند التثبيت على ويندوز، يجب إضافة Gradle إلى المسار الخاص بك (راجع قسم إعداد متغيرات البيئة في الأسفل).

أندرويد SDK

ثبت Android Studio. توجد إرشادات التثبيت التفصيلية على الموقع بشكل واضح. عندما تفتح Android Studio للمرة الأولى سيتم إرشادك إلى كيفية تثبيت Android SDK.

إضافة حزم SDK

بعد تثبيت Android SDK، يجب أيضًا تثبيت الحزم لأي مستوى من مستويات واجهة برمجة التطبيقات التي ترغب في استهدافها. يوصى بتثبيت أعلى إصدارمن SDK  يدعمه إصدار كوردوفا-أندرويد الخاص بك (راجع قسم المتطلبات والدعم في الأعلى).

افتح Android SDK Manager (عبر الذهاب إلى Tools > SDK Manager في Android Studio أو عبر تنفيذ الأمر sdkmanager من الطرفية) وتأكد من تثبيت ما يلي:

  1. حزم SDK لمنصة أندرويد للنسخة المستهدفة من نظام أندرويد
  2. أدوات بناء حزم SDK لأندرويد الإصدار 19.1.0 أو أحدث
  3. مستودع دعم أندرويد (ستعثر عليه في أسفل التبويب "SDK Tools")

راجع توثيق أندرويد حول تثبيت حزم SDK لمزيد من التفاصيل.

ضبط متغيرات البيئة

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

  1. اضبط متغير البيئة JAVA_HOME على مكان تثبيت JDK الخاص بك.
  2. اضبط متغير البيئة ANDROID_HOME على موقع تثبيت Android SDK.
  3. يوصى أيضًا بإضافة المجلدات tools، و tools/bin، و platform-tools الخاصة بحزم Android SDK إلى PATH.

النظام OS X ولينكس

في النظام ماك أو لينكس، يمكنك استخدام محرر نصي لإنشاء أو تعديل الملف ‎~/.bash_profile. ولتعيين متغير بيئة، أضف خطًا يستخدم export مثل ذلك (استبدل المسار بالتثبيت المحلي):

export ANDROID_HOME=/Development/android-sdk/

لتحديث PATH، أضف خطًا يشبه ما يلي (استبدال المسارات بمواقع تثبيت Android SDK المحلي):

export PATH=${PATH}:/Development/android-sdk/platform-tools:/Development/android-sdk/tools

أعد تشغيل الطرفية لمعرفة سيريان مفعول هذا التغيير أو نفذ الأمر التالي عوضًا عن ذلك:

$ source ~/.bash_profile

نظام ويندوز

قد تختلف هذه الخطوات وفقًا لإصدار ويندوز المثبت. أغلق وأعد تشغيل أية نوافذ مفتوحة لموجه الأوامر (command prompt) بعد إجراء أية تغييرات للتحقق من تطبيقها.

  1. انقر فوق قائمة ابدأ (Start) في الزاوية السفلية اليسرى من سطح المكتب
  2. في شريط البحث، ابحث عن "متغيرات البيئة" (Environment Variables) واختر "تعديل متغيرات بيئة النظام" (Edit the system Environment Variables) من الخيارات التي تظهر لك
  3. في النافذة التي تظهر، انقر فوق زر "متغيرات البيئة" (Environment Variables)

لإنشاء متغيرات بيئة جديدة، انقر فوق "جديد" (New...‎) وأدخل اسم المتغير وقيمته.

لتعيين المتغير PATH، حدده ثم اضغط على "تعديل" (Edit). أضف بعد ذلك المدخلات في المواقع التابع للمتغير PATH. اطلع على المثال التالي (استبدل المسارات بمواقع تثبيت Android SDK المحلي:

C:\Users\[your user]\AppData\Local\Android\Sdk\platform-tools
C:\Users\[your user]\AppData\Local\Android\Sdk\tools

ضبط المشروع

إعداد محاكي

إذا كنت ترغب في تشغيل تطبيق كوردوفا الخاص بك على محاكي أندرويد، فستحتاج أولًا إلى إنشاء جهاز أندرويد افتراضي (AVD، اختصار للعبارة Android Virtual Device). راجع توثيق أندرويد لإدارة الأجهزة الافتراضية وضبط المحاكي وإعداد حساس التسارع.

بمجرد تكوين الجهاز الافتراضي الخاص بك بشكل صحيح، يجب أن تكون قادرًا على نشر تطبيق كوردوفا الخاص بك على المحاكي عن طريق تنفيذ الأمر التالي:

$ cordova run --emulator

ضبط Gradle

اعتبارًا من cordova-android@4.0.0، تم تصميم كوردوفا لمشاريع أندرويد باستخدام Gradle. للحصول على إرشادات حول البناء باستخدام Ant، راجع الإصدارات القديمة من التوثيق. يرجى ملاحظة أن البناء باستعمال Ant أصبح مهملًا بدءًا من الإصدار 25.3.0 لأدوات SDK للأندرويد.

ضبط خاصيات Gradle

من الممكن تكوين Gradle عن طريق تحديد قيم بعض خاصيات Gradle التي تعرضها كوردوفا. الخصائص التالية متاحة لتعيين:

الخاصية الوصف
cdvBuildMultipleApks إذا تم تعيين هذه الخاصية، فسيتم إنشاء ملفات APK متعددة: واحد لكل نظام أساسي مدمج مدعوم بمشاريع المكتبة (x86، ARM، ...إلخ). قد يكون هذا مهمًا إذا كان مشروعك يستخدم مكتبات أصلية كبيرة، مما قد يزيد بشكل كبير من حجم ملف APK الذي تم إنشاؤه. إذا لم يتم تعيينها، فسيتم إنشاء ملف APK واحد يمكن استخدامه على جميع الأجهزة.
cdvVersionCode تستبدل مجموعة كود الإصدار في AndroidManifest.xml.
cdvReleaseSigningPropertiesFile القيمة الافتراضية: release-signing.properties

تحدد هذه الخاصية مسار الملف ‎.properties الذي يحتوي على معلومات التوقيع لبنيات الإصدار (انظر قسم توقيع التطبيق).

cdvDebugSigningPropertiesFile القيمة الافتراضية: debug-signing.properties

تحدد مسار الملف ‎.properties الذي يحتوي على معلومات تسجيل لبنيات التنقيح (انظر قسم توقيع التطبيق). هذه الخاصية مفيدة عندما تحتاج إلى مشاركة مفتاح توقيع مع مطورين آخرين.

cdvMinSdkVersion تستبدل قيمة المجموعة minSdkVersion في الملف AndroidManifest.xml. هذه الخاصية مفيدة عند إنشاء ملفات APK متعددة استنادًا إلى إصدار SDK.
cdvBuildToolsVersion تستبدل القيمة android.buildToolsVersion التي يتم اكتشافها تلقائيًا.
cdvCompileSdkVersion تستبدل القيمة android.compileSdkVersion التي يتم اكتشافها تلقائيًا.

تستطيع أن تضبط هذه الخصائص بواسطة واحدة من هذه الطرق الأربعة:

  • عن طريق ضبط متغيرات البيئة مثل:
$ export ORG_GRADLE_PROJECT_cdvMinSdkVersion=20
$ cordova build android
  • بواسطة استخدام الراية ‎--gradleArg أثناء استعمال الأمر build أو run في سطر أوامر كوردوفا مثل:
 $ cordova run android -- --gradleArg=-PcdvMinSdkVersion=20
  • بواسطة وضع ملف اسمه gradle.properties  في مجلد منصة أندرويد (<your-project>/platforms/android)  وادخال الخصائص فيه بالشكل التالي:
# In <your-project>/platforms/android/gradle.properties
cdvMinSdkVersion=20
  • بواسطة توسيع  build.gradle عن طريق الملف build-extras.gradle وضبط الخاصية بالشكل التالي:
// In <your-project>/platforms/android/build-extras.gradle
ext.cdvMinSdkVersion = 20

يتضمن الخياران الأخيران تضمين ملف إضافي في مجلد منصة أندرويد الخاص بك. وبصفة عامة، لا يمكن تحرير محتويات هذا المجلد لأنه من السهل أن فقدان أو استبدال هذه التغييرات. بدلًا من ذلك، يجب نسخ هذين الملفين من موقع آخر إلى هذا المجلد كجزء من أمر البناء باستخدام الخطاف before_build.

توسيع build.gradle

إذا كنت بحاجة إلى تخصيص build.gradle، بدلًا من تحريره مباشرةً، فيجب إنشاء ملف شقيق باسم build-extras.gradle. سيتم تضمين هذا الملف بواسطة build.gradle الرئيسي عند وجوده. يجب وضع هذا الملف في مجلد منصة أندرويد (‎(<your-project>/platform/android، لذا يُنصح بنسخه عبر برنامج نصي مرفق بالخطاف before_build. إليك هذا المثال:

// build-extras.gradle مثال عن
// `build.gradle` يُضمّن هذا الملف في بداية

// وإعادة تعيين القيم الافتراضية - build.gradle يمكن إعداد بعض الخاصيات - انظر 
// ext.cdvDebugSigningPropertiesFile = '../../android-debug-keys.properties'

// `build.gradle` إعداد عادي لـ
android {
  defaultConfig {
    testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
  }
}
dependencies {
  androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
  }
}

// `build.gradle` تنفيذ الشيفرة في نهاية  `ext.postBuildExtras` عند تعيينها، تتيح الدالة 
ext.postBuildExtras = {
    android.buildTypes.debug.applicationIdSuffix = '.debug'
}

لاحظ أن الإضافات ممكن أن تتضمن ملفات build-extras.gradle  عن طريق:

<framework src="some.gradle" custom="true" type="gradleReference" />

ضبط إصدار الشيفرة

إن أردت تغيير إصدار الشيفرة للتطبيق apk المولد، فاضبط الخاصية android-versionCode في العنصر widget في الملف config.xml الخاص بالتطبيق. إذا لم يتم تعيين الخاصية android-versionCode، فسيتم تحديد رمز الإصدار باستخدام الخاصية version. على سبيل المثال، إذا كان الإصدار هو MAJOR.MINOR.PATCH:

versionCode = MAJOR * 10000 + MINOR * 100 + PATCH

إذا كان التطبيق الخاص بك قد فعَّل خاصية Gradle التي هي CdvBuildMultipleApks (راجع قسم ضبط خاصيات Gradle في الأعلى)، فسيتم ضرب إصدار الشيفرة الخاص بتطبيقك أيضًا بالقيمة 10 بحيث يمكن استخدام آخر رقم من الشيفرة للإشارة إلى البنية التي تم إنشاء apk لها. ستجرى عملية الضرب هذه بغض النظر عما إذا كان رمز الإصدار مأخوذًا من الخاصية android-versionCode أو تم إنشاؤه باستخدام الإصدار. كن على علم بأن بعض الإضافات المضافة إلى مشروعك (بما في ذلك Cordova-plugin-crosswalk-webview) قد تقوم بتعيين خاصية Gradle هذه تلقائيًا.

ملاحظة مهمة: عند تحديث الخاصية android-versionCode، فإنه ليس من الحكمة زيادة إصدار الشيفرة المأخوذ من التطبيقات apk المبنية. فبدلًا من ذلك، يجب زيادة الشيفرة استنادًا إلى القيمة الموجودة في الخاصية android-versionCode في الملف config.xml. ويرجع ذلك إلى أنَّ الخاصية cdvBuildMultipleApks تتسبب في ضرب إصدار الشيفرة المراد ضربه بالقيمة 10 في التطبيقات apk المبنية، وبالتالي فإن استخدام هذه القيمة سيؤدي إلى أن يكون إصدار الشيفرة التالي لديك 100 مرة قدر الأصلي وهكذا دواليك.

توقيع التطبيق

أولاً، يجب قراءة متطلبات توقيع تطبيق أندرويد.

استخدام الرايات

لتوقيع تطبيق، تحتاج إلى المعاملات التالية:

المعامل الراية الوصف
المخزن الرئيسي (المفتاحي) ‎--keystore المسار إلى ملف التنفيذ (binary file) الذي يمكنه الاحتفاظ بمجموعة من المفاتيح.
كلمة المرور للمخزن الرئيسي ‎--storePassword إنشاء كلمة مرور للدخول إلى المخزن الرئيسي (المفتاحي).
الاسم البديل ‎--alias الاسم البديل المعرف الذي يحدد المفتاح الخاص المستخدم الدخول.
كلمة المرور ‎--password كلمة المرور المخصصة لمفتاح خاص.
انواع المخزن الرئيسي (المخزن المفتاحي) ‎--keystoreType القيمة الافتراضية هي: auto-detect أي الاكتشاف التلقائي الذي يستند على لاحقة الملف والتي إما أن تكون pkcs12 أو jks.

يمكن تحديد هذه المعاملات باستخدام وسائط سطر الأوامر أعلاه مع الأمر build والأمر run في سطر أوامر كوردوفا.

ملاحظة: يجب أن تستخدم الرمز -- بشكل مزدوج للإشارة إلى أنها وسائط خاصة بالمنصة. اطلع على المثال التالي:

cordova run android --release -- --keystore=../my-release-key.keystore --storePassword=password --alias=alias_name --password=password

استخدام build.json

بدلاً من ذلك، يمكنك تحديدها في ملف ضبط البناء (الذي هو build.json) باستخدام الوسيط ‎--buildConfig مع نفس الأوامر. إليك نموذجًا من ملف ضبط البناء:

{
    "android": {
        "debug": {
            "keystore": "../android.keystore",
            "storePassword": "android",
            "alias": "mykey1",
            "password" : "password",
            "keystoreType": ""
        },
        "release": {
            "keystore": "../android.keystore",
            "storePassword": "",
            "alias": "mykey2",
            "password" : "password",
            "keystoreType": ""
        }
    }
}

بالنسبة إلى توقيع الإصدار، يمكن استبعاد كلمات المرور وسيصدر نظام الإنشاء نافذة منبثقة تطلب كلمة المرور.

هناك أيضا دعم لدمج ومطابقة وسائط ومعاملات سطر الأوامر في build.json. ستحصل القيم من وسائط سطر الأوامر على الأسبقية. هذا يمكن أن يكون مفيدًا لتحديد كلمات المرور على سطر الأوامر.

استخدام Gradle

يمكنك أيضًا تحديد خصائص التوقيع من خلال تضمين الملف ‎.properties والإشارة إليه باستخدام خاصيات Gradle التي هي cdvReleaseSigningPropertiesFile و cdvDebugSigningPropertiesFile (راجع قسم ضبط خاصيات Gradle في الأعلى). يجب أن يبدو الملف كما يلي:

storeFile=relative/path/to/keystore.p12
storePassword=SECRET1
storeType=pkcs12
keyAlias=DebugSigningKey
keyPassword=SECRET2

الخاصية storePassword و keyPassword اختيارية، وستتم مطالبتك بها إذا تم حذفها.

التنقيح

للحصول على تفاصيل حول أدوات تصحيح الأخطاء (debugging) التي تأتي مجمعة مع Android SDK، راجع توثيق مطوري برامج أندرويد لتصحيح الأخطاء. بالإضافة إلى ذلك، يوفر توثيق مطوري برامج أندرويد لتصحيح الأخطاء لتطبيقات الويب مقدمة لتصحيح أخطاء جزء التطبيق الذي يعمل في عرض الويب.

فتح مشروع في Android Studio

يمكن فتح مشاريع كوردوفا للأندرويد في Android Studio. قد يكون ذلك مفيدًا إذا كنت ترغب في استخدام أدوات التنقيح المدمجة في Android Studio أو إذا كنت تعمل على تطوير إضافات أندرويد. يرجى ملاحظة أنه عند فتح مشروعك في Android Studio، يوصى بعدم تعديل شيفرتك في البيئة التطويرية هنالك (IDE) لأن ذلك سيؤدي إلى تعديل الشيفرة في المجلد platforms في مشروعك (وليس المجلد www) وستكون التغييرات عرضةً للاستبدال. بدلًا من ذلك، قم بتحرير المجلد www ونسخ التغييرات التي أجريتها عن طريق تنفيذ الأمر cordova build.

يجب على مطوري الإضافات الراغبين في تحرير الشيفرة الأصلية في بيئة تطوير Android Studio استخدام الراية ‎--link عند إضافة الإضافة للمشروع عن طريق الأمر  cordova plugin add. سيؤدي هذا إلى ربط الملفات بحيث تلك التغييرات التي تطرأ على ملفات الإضافة في المجلد platforms تنعكس في المجلد المصدري للإضافة (والعكس صحيح).

لفتح مشروع كوردوفا لتطبيق أندرويد في Android Studio، اتبع الخطوات التالية:

  1. شغل Android Studio.
  2. حدد Import Project ‏(Eclipse ADT, Gradle, etc).
    فتح Android Studio ثم تحديد الخيار Import Project من الخيارات الظاهرة لفتح مشروع كوردوفا لتطبيق أندرويد.
    فتح Android Studio ثم تحديد الخيار Import Project من الخيارات الظاهرة لفتح مشروع كوردوفا لتطبيق أندرويد فيه.
  3. حدد مجلد منصة أندرويد في مشروعك (‎<your-project>/platforms/android).
    تحديد مجلد منصة أندرويد في مشروعك الذي أنشئ باستعمال كوردوفا وذلك لفتحه في Android Studio.
    تحديد مجلد منصة أندرويد في مشروعك الذي أنشئ باستعمال كوردوفا وذلك لفتحه في Android Studio.
  4. بالنسبة إلى سؤال Gradle Sync، يمكنك ببساطة الإجابة بنعم.

بمجرد الانتهاء من الاستيراد، يجب أن تكون قادرًا على إنشاء التطبيق وتشغيله مباشرة من Android Studio. راجع صفحة نظرة عامة على Android Studio وصفحة البناء والتشغيل من Android Studio لمزيد من التفاصيل.

اكتمال استيراد تطبيق أندرويد أنشئ باستعمال كوردوفا في Android Studio.
اكتمال استيراد تطبيق أندرويد أنشئ باستعمال كوردوفا في Android Studio.

سير العمل المرتكز على منصة واحدة

يتضمن كوردوفا-أندرويد عددًا من النصوص البرمجية (scripts) التي تسمح باستخدام المنصة بدون سطر أوامر كوردوفا الكامل. قد يوفر لك مسار التطوير هذا مجموعة أكبر من خيارات التطوير في مواقف معينة لا تجدها في سير العمل العابر للمنصات عبر سطر الأوامر. على سبيل المثال، تحتاج إلى استخدام أدوات الصدفة (shell) عند نشر عارض WebView مخصص إلى جانب المكونات الأصلية. قبل استخدام مسار التطوير هذا، يجب عليك تهيئة بيئة Android SDK كما هو موضح في قسم المتطلبات والدعم أعلاه.

لكل من النصوص الموضحة أدناه، ارجع إلى واجهة سطر أوامر كوردوفا للحصول على مزيد من المعلومات حول الوسائط والاستعمالات. يملك كل برنامج نصي اسمًا يطابق أمرًا مقابلًا له في سطر الأوامر. على سبيل المثال،إنَّ Cordova-android/bin/create يعادل الأمر cordova create.

للبدء، قم بتنزيل حزمة أندرويد-كوردوفا من npm أو Github. لإنشاء مشروع باستخدام هذه الحزمة، قم بتشغيل البرنامج النصي create في المجلد bin:

$ cordova-android/bin/create

سيكون للمشروع الذي تم إنشاؤه مجلدًا باسم cordova بداخله يحتوي على برامج نصية لأوامر كوردوفا الخاصة بالمشروع (مثل الأمر run، و build، ...إلخ). بالإضافة إلى ذلك، سيحتوي المشروع على هيكل مختلف عن مشروع كوردوفا العادي. ومن الجدير بالذكر أن المجلد ‎/www نقل إلى ‎/assets/www.

لتثبيت إضافات في هذا المشروع، استخدم الأداة Plugman المساعدة.

الترقية

انتقل إلى هذه الصفحة للحصول على إرشادات لترقية إصدار كوردوفا-أندرويد.

دليل دورة الحياة

كوردوفا وأندرويد

تتكون تطبيقات أندرويد الأصيلة عادةً من سلسلة من النشاطات (Activities) التي يتفاعل معها المستخدم. يمكن اعتبار هذه النشاطات كشاشات فردية تشكل تطبيقًا، إذ إن مهام مختلفة في التطبيق سيكون لها في الغالب نشاطها الخاص حيث تحتوي كل واجهة على دورة حياتها الخاصة التي يتم الحفاظ عليها أثناء دخول الواجهة من واجهة جهاز المستخدم وتركها.

وعلى العكس، يتم تنفيذ تطبيقات كوردوفا على منصة أندرويد داخل عرض الويب المضمّن في واجهة واحدة (أي نشاط أندرويد واحد فقط). يتم تعريض دورة حياة هذه الواجهة إلى التطبيق الخاص بك من خلال أحداث المستند التي يتم إطلاقها. لا يضمن للأحداث أن تتماشى مع دورة حياة أندرويد تمامًا، ولكن يمكنها توفير إرشادات لحفظ واستعادة حالتك. ترتبط هذه الأحداث تقريبًا بردود نداء أندرويد كما يلي:

حدث كوردوفا المكافيء العام لأندرويد المعنى
deviceready onCreate()‎ التطبيق قيد البدء (ليس من جهة الخلفية).
pause onPause()‎ التطبيق قيد الانتقال إلى الخلفية.
resume ‎onResume()‎ التطبيق يعود إلى المقدمة.

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

ما الذي يجعل أندرويد مختلفًا؟

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

متى يمكن أن يحدث هذا؟

التطبيق الخاص بك هو عرضة للتدمير من قبل نظام التشغيل كلما تركته جانبًا. فهناك موقفان رئيسيان يمكن أن يحدث فيهما هذا؛ الحالة الأولى والأكثر وضوحًا هي عندما يضغط المستخدم على زر الصفحة الرئيسية أو يتحول إلى تطبيق آخر.

ومع ذلك، هناك حالة ثانية (وأكثر خفاء) يمكن لبعض الإضافات إدخالها. كما ذكر أعلاه، تقتصر تطبيقات كوردوفا عادة على النشاط الفردي الذي يحتوي على العارض WebView. ومع ذلك، هناك حالات قد يتم فيها تشغيل أنشطة أخرى بواسطة المكونات الإضافية وتدفع نشاط كوردوفا مؤقتًا إلى الخلفية. يتم عادةً تشغيل هذه الأنشطة الأخرى لتنفيذ مهمة محددة باستخدام تطبيق أصلي مثبت على الجهاز. على سبيل المثال، تطلق إضافة الكاميرا في كوردوفا أي واجهة كاميرا مثبتة أصلًا على الجهاز لالتقاط صورة. إن إعادة استخدام تطبيق الكاميرا المثبت بهذه الطريقة يجعل تطبيقك يشبه إلى حد كبير التطبيق الأصلي كلما يحاول المستخدم التقاط صورة. وللأسف أيضًا، عندما تدفع الواجهة المحلية تطبيقك إلى الخلفية، هناك احتمال أن ينهيه نظام التشغيل.

لتحسين فهمنا للحالة الثانية، دعنا نجرب عبر مثال باستخدام إضافة الكاميرا. تخيل أنَّ لديك تطبيقًا يتطلب من المستخدم التقاط صورة للملف الشخصي. سيظهر تدفق الأحداث في التطبيق عندما يسير كل شيء كما هو مخطط له على النحو التالي:

  1. يتفاعل المستخدم مع تطبيقك ويحتاج إلى التقاط صورة.
  2. يُطلَق المكون الإضافي للكاميرا واجهة الكاميرا الأصلية.
    1. يتم دفع واجهة كوردوفا إلى الخلفية (يتم تشغيل الحدث pause).
  3. يأخذ المستخدم صورة.
  4. ينتهي نشاط الكاميرا.
    1. يتم نقل واجهة كوردوفا إلى المقدمة (يتم إطلاق الحدث resume).
  5. يتم إرجاع المستخدم إلى التطبيق الخاص بك حيث توقف.

ومع ذلك، يمكن تعطيل تدفق الأحداث هذا إذا كان الجهاز منخفضًا في الذاكرة. إذا تم إنهاء النشاط بواسطة نظام التشغيل، فسيتم تشغيل تسلسل الأحداث أعلاه على النحو التالي:

  1. يتفاعل المستخدم مع تطبيقك ويلزم التقاط صورة.
  2. يُطلق المكون الإضافي للكاميرا واجهة الكاميرا الأصلية.
    1. نظام التشغيل يدمر واجهة كوردوفا (يتم إطلاق الحدث pause).
  3. يأخذ المستخدم صورة.
  4. تنتهي واجهة الكاميرا.
    1. يقوم نظام التشغيل بإعادة إنشاء نشاط كوردوفا (يتم إطلاق الحدث deviceready والحدث resume)
  5. يشعر المستخدم بالارتباك حول سبب عودته فجأة إلى شاشة تسجيل الدخول إلى تطبيقك.

في هذه الحالة، قام نظام التشغيل بتدمير التطبيق في الخلفية ولم يحافظ التطبيق على حالته كجزء من دورة الحياة. وعندما عاد المستخدم إلى التطبيق، تم إعادة إنشاء العارض WebView وبدا أن التطبيق قد أعيد تشغيله من الصفر (وبالتالي ارتبك المستخدم لحصول ذلك). هذا التسلسل من الأحداث يعادل ما يحدث عندما يتم الضغط على زر الصفحة الرئيسية أو يبدل المستخدم بين التطبيقات. إن المفتاح لمنع التجربة أعلاه هو الاشتراك في الأحداث والحفاظ على الحالة بشكل صحيح كجزء من دورة حياة النشاط.

احترام دورة الحياة

في الأمثلة أعلاه، تتم الإشارة إلى أحداث JavaScript التي يتم إطلاقها بخط مائل. هذه الأحداث هي فرصتك لحفظ واستعادة حالة التطبيق الخاص بك. يجب تسجيل عمليات الاسترجاعات في الدالة bindEvents الخاصة بالتطبيق والتي تستجيب لأحداث دورة الحياة عن طريق حفظ الحالة. يتم ترك المعلومات التي قمت بحفظها وكيفية حفظها لتقديرك، ولكن يجب عليك التأكد من حفظ المعلومات الكافية بحيث يمكنك إعادة المستخدم إلى المكان الذي توقف فيه عند عودته إلى تطبيقك.

هناك عامل إضافي واحد في المثال أعلاه لا ينطبق إلا في الحالة التي تمت مناقشتها ثانيًا (أي عندما تبدأ إضافة ما نشاطًا خارجيًا). حيث لم تكن حالة التطبيق مفقودة فقط عندما انتهى المستخدم من التقاط صورة، ولكن كانت أيضًا خلال التقاطها. عادةً، سيتم تسليم هذه الصورة إلى التطبيق الخاص بك من خلال رد نداء مسجل من قبل في إضافة الكاميرا. ومع ذلك، عندما تم تدمير العارض WebView، فإنَّ رد النداء هذا - ولحسن الحظ - قد فقد إلى الأبد. يوفر الإصدار 5.1.0 وما بعده من كوردوفا-أندرويد وسيلة لجلب النتيجة لاستدعاء تلك الإضافة عند استئناف عمل تطبيقك.

استرداد نتائج رد نداء إضافة (الإصدار 5.1.0 وما بعده من كوردوفا-أندرويد)

عندما يدمر نظام التشغيل نشاط كوردوفا الذي تم دفعه إلى الخلفية عن طريق إضافة، يتم فقدان أي عمليات استرجاع معلقة أيضًا. هذا يعني أنه إذا قمت بتمرير رد نداء إلى الإضافة التي بدأت نشاطًا جديدًا (مثل إضافة الكاميرا)، فلن يتم إطلاق رد النداء هذا عند إعادة إنشاء التطبيق. ومع ذلك، بدءًا من الإصدار 5.1.0 وما بعده من كوردوفا-أندرويد، ستتضمن حمولة الحدث resume أية نتائج معلقة للإضافة من طلب الإضافة الذي بدأ النشاط الخارجي الذي تم إجراؤه قبل تدمير النشاط.

تلتزم حمولة الحدث resume بالتنسيق التالي:

{
    action: "resume",
    pendingResult: {
        pluginServiceName: string,
        pluginStatus: string,
        result: any
    }
}

يتم تعريف حقول هذه الحمولة على النحو التالي:

  • pluginServiceName: اسم الإضافة التي تعيد النتيجة (مثل "Camera" عند استعمال إضافة الكاميرا). يمكن العثور على هذا في الوسم <name> للملف plugin.xml للإضافة.
  • pluginStatus: حالة استدعاء الإضافة (انظر أدناه).
  • result: أيًا كانت نتيجة استدعاء الإضافة.

تتضمن القيم المحتملة للحقل pluginStatus في الحقل pendingResult ما يلي:

  • "OK": ثم استدعاء الإضافة بنجاح.
  • "No Result": انتهى استدعاء الإضافة دون نتيجة.
  • "Error": أدى استدعاء الإضافة إلى حدوث بعض الأخطاء العامة.
  • أخطاء متنوعة أخرى:
    • "Class not found"
    • "Illegal access"
    • "Instantiation error"
    • "Malformed url"
    • "IO error"
    • "Invalid action"
    • "JSON error"

يرجى ملاحظة أن الأمر متروك للإضافة لتقرر ما هو موجود في الحقل result ومعنى الحقل pluginStatus الذي تم إعادته. ويمكنك الرجوع إلى واجهة برمجة التطبيقات للإضافة التي تستخدمها للاطلاع على ما يجب أن تتوقعه من هذه الحقول وكيفية احتوائها على قيمها.

مثال

فيما يلي مثالًا موجزًا لتطبيق يستخدم الحدث resume والحدث pause لإدارة الحالة. ويستخدم البرنامج إضافة الكاميرا كمثال على كيفية استرداد نتائج استدعاء الإضافة من حمولة الحدث resume. ويتطلب الجزء من الشيفرة الذي يتعامل مع الكائن event.pendingResult للحدث resume الذي يتطلب الإصدار 5.1.0 وما بعده من كوردوفا-أندرويد:

// onPause() و  onResume() تمثل هذه الحالة حالة التطبيق وستُخزن وتُسترجع عبر 
var appState = {
    takingPicture: true,
    imageUri: ""
};

var APP_STORAGE_KEY = "exampleAppState";

var app = {
    initialize: function() {
        this.bindEvents();
    },
    bindEvents: function() {
        // سنسجل رد النداء لأحداث دورة الحياة التي تهمنا
        document.addEventListener('deviceready', this.onDeviceReady, false);
        document.addEventListener('pause', this.onPause, false);
        document.addEventListener('resume', this.onResume, false);
    },
    onDeviceReady: function() {
        document.getElementById("take-picture-button").addEventListener("click", function() {
            // لما أطلقت إضافة الكامير نشاطا خارجيا، فهناك احتمال أن يُنهى تطبيقنا قبل أن تُستدعى دوال رد النداء الخاصة
            //  بالفشل أو النجاح
            //  حيث نخزن ونسترجع الحالة لمعالجة هذه الحالة onResume() و  onPause() انظر
            appState.takingPicture = true;

            navigator.camera.getPicture(cameraSuccessCallback, cameraFailureCallback,
                {
                    sourceType: Camera.PictureSourceType.CAMERA,
                    destinationType: Camera.DestinationType.FILE_URI,
                    targetWidth: 250,
                    targetHeight: 250
                }
            );
        });
    },
    onPause: function() {
        // نتحقق هنا إن كنا في طور التقاط صورة. إن كان الأمر كذلك، نرغب في حفظ حالتنا لكي  
        // onResume()  نسترجع نتيجة الإضافة في
        // نرغب كذلك في الحفظ إن كنا قد استرجعنا عنوان الصورة سلفا.
        if(appState.takingPicture || appState.imageUri) {
            window.localStorage.setItem(APP_STORAGE_KEY, JSON.stringify(appState));
        }
    },
    onResume: function(event) {
        // نتحقق هنا من الحلة المحفوظة ونسترجعها إن لزم الأمر.الخيار يعود لك، يمكنك الاستمرار بتعقب المواضع
        // التي تأتي منها نتائج الإضافة المعلقة، أي مواضع الشيفرة البرمجية التي أتي منها الاستدعاء
        // وكذلك الوسائط التي مررتها للإضافة إن لزم الأمر
        var storedState = window.localStorage.getItem(APP_STORAGE_KEY);

        if(storedState) {
            appState = JSON.parse(storedState);
        }

        // التحقق من أننا نحتاج إلى حفظ الصورة التي أخذناها
        if(!appState.takingPicture && appState.imageUri) {
            document.getElementById("get-picture-result").src = appState.imageUri;
        }
        // cordova-android 5.1.0+ يمكننا الآن التحقق إن كانت هناك نتيجة في كائن الحدث، وهذا يتطلب الإصدار
        else if(appState.takingPicture && event.pendingResult) {
            // تعني "OK" التحقق من فشل أو نجاح استدعاء الإضافة، ثم استدعاء رد النداء المناسب. في حالة إضافة الكاميرا،
            // أن النتيجة ناجحة، وأي نتيجة أخرى ستُؤول كفشل
            if(event.pendingResult.pluginStatus === "OK") {
                //  تضع إضافة الكاميرا النتيجة نفسها في كائن الاستئناف، حيث يُمرر إلى   
                // getPictre() رد النداء الخاص بالنجاح والممرر إلى
                // وهكذا يمكننا تمريره إلى رد النداء نفسه. قد تعيد الإَضافات الأخرى نتائج أخرى. 
                // ارجع إلى توثيق الإضافة التي تستعمل لتتعلم كيف تؤول النتائج
                cameraSuccessCallback(event.pendingResult.result);
            } else {
                cameraFailureCallback(event.pendingResult.result);
            }
        }
    }
}

// getPicture() هاذان هما ردا النداء المُمرران إلى 
function cameraSuccessCallback(imageUri) {
    appState.takingPicture = false;
    appState.imageUri = imageUri;
    document.getElementById("get-picture-result").src = imageUri;
}

function cameraFailureCallback(error) {
    appState.takingPicture = false;
    console.log(error);
}

app.initialize();

ملف HTML المقابل:

<!DOCTYPE html>

<html>
    <head>
        <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
        <meta name="format-detection" content="telephone=no">
        <meta name="msapplication-tap-highlight" content="no">
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
        <link rel="stylesheet" type="text/css" href="css/index.css">
        <title>Cordova Android Lifecycle Example</title>
    </head>
    <body>
        <div class="app">
            <div>
                <img id="get-picture-result" />
            </div>
            <Button id="take-picture-button">Take Picture</button>
        </div>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
    </body>
</html>

اختبار دورة حياة الواجهة

يوفر أندرويد إعداد مطور البرامج لاختبار تدمير النشاط على ذاكرة منخفضة. قم بتمكين الضبط "عدم الاحتفاظ بالنشاطات" (Don't keep activities) في قائمة خيارات المطور (Developer Options) على جهازك أو على المحاكي لمحاكاة سيناريوهات الذاكرة المنخفضة. يجب عليك دائمًا إجراء بعض الاختبارات باستخدام هذا الإعداد وذلك للتأكد من أن التطبيق الخاص بك يحتفظ بحالته بشكل صحيح.

انظر أيضًا

مصادر