ملفات توسيع حزمة APK

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

يستضيف Google Play ملفات البيانات الموسّعة لتطبيقك ويعرضها على الجهاز في بدون تكلفة. وتُحفظ ملفات البيانات الموسّعة في موقع مساحة التخزين المشتركة للجهاز ( بطاقة SD أو قسم قابل للتركيب على USB والمعروفة أيضًا باسم "المصادر الخارجية" مساحة التخزين) التي يمكن لتطبيقك الوصول إليها معهم. على معظم الأجهزة، ينزِّل Google Play ملفات البيانات الموسّعة في الوقت نفسه. لتنزيل حزمة APK، لكي يحتوي التطبيق على كل ما يحتاج إليه عند فتحه لأول مرة. ومع ذلك، يجب أن ينزِّل تطبيقك الملفات من Google Play في بعض الحالات. عندما يبدأ تشغيل تطبيقك.

إذا أردت تجنُّب استخدام ملفات البيانات الموسّعة وكان حجم تنزيل التطبيق المضغوط أكبر من 100 ميغابايت، يجب تحميل التطبيق باستخدام تطبيق Android حِزم البيانات التي تسمح بحجم تنزيل مضغوط يصل إلى 200 ميغابايت. بالإضافة إلى ذلك، لأن استخدام تساعد حِزم التطبيقات في تأجيل إنشاء ملفات APK وتسجيل الدخول إليها على Google Play، ويمكن للمستخدمين تنزيل حِزم APK المحسَّنة باستخدام فقط الرمز والموارد التي يحتاجونها لتشغيل التطبيق. لست مضطرًا لإنشاء إدارة حزم APK متعددة أو ملفات بيانات موسّعة، والحصول على عمليات تنزيل أصغر وأكثر تحسينًا.

نظرة عامة

في كل مرة تحمّل فيها حزمة APK باستخدام Google Play Console، يتوفر لك خيار عليك إضافة ملف توسيع واحد أو ملفين إلى حزِمة APK. يمكن أن يصل حجم كل ملف إلى 2 غيغابايت ويمكن أن يكون بأي تنسيق إلا أننا ننصحك باستخدام ملف مضغوط للحفاظ على النطاق الترددي أثناء التنزيل. من الناحية النظرية، يلعب كل ملف بيانات موسّعة دورًا مختلفًا:

  • ملف البيانات الموسّعة الرئيسي هو ملف بيانات موسّعة أساسي للموارد الإضافية التي يتطلبها تطبيقك.
  • ملف البيانات الموسّعة التصحيحي اختياري ومُصمَّم لإجراء تعديلات بسيطة على ملف البيانات الموسّعة الرئيسي.

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

مع ذلك، حتى إذا كان تحديث تطبيقك يتطلب ملف تصحيح جديدًا فقط، يجب عليك تحميل حزمة APK جديدة تتضمّن versionCode جديدًا في البيان ( لا تسمح لك Play Console بتحميل ملف بيانات موسّعة إلى حِزمة APK حالية).

ملاحظة: يتطابق ملف البيانات الموسّعة الاختياري مع ملف ملف البيانات الموسّعة الرئيسي - يمكنك استخدام كل ملف بالطريقة التي تريدها.

تنسيق اسم الملف

يمكن تحميل أي ملف بيانات موسّعة بأي تنسيق تختاره (ZIP أو PDF أو MP4 أو غير ذلك). يمكنك أيضًا استخدام أداة JOBB لتغليف مجموعة وتشفيرها من ملفات الموارد والتصحيحات اللاحقة لهذه المجموعة. بغض النظر عن نوع الملف، يمكن لخدمة Google Play تعتبرها وحدات ثنائية غير شفافة وإعادة تسمية الملفات باستخدام المخطط التالي:

[main|patch].<expansion-version>.<package-name>.obb

هناك ثلاثة مكونات لهذا النظام:

main أو patch
يحدد هذا الإعداد ما إذا كان الملف هو الملف الرئيسي أو ملف التصحيح الرئيسي. يمكن أن يكون هناك ملف رئيسي واحد وملف تصحيح واحد لكل حِزمة APK
<expansion-version>
هذا عدد صحيح يتطابق مع رمز إصدار حِزمة APK التي يتم بها التوسيع الأول المرتبط به (يتطابق مع android:versionCode الخاص بالتطبيق ).

"الأول" هذا المنتج أمرًا هامًا لأنه على الرغم من أن أداة Play Console تتيح لك إعادة استخدام ملف بيانات موسّعة تم تحميله مع حزمة APK جديدة، مع عدم تغيير اسم ملف البيانات الموسّعة، بالنسخة المطبقة عليه عند تحميل الملف لأول مرة.

<package-name>
اسم حزمة تطبيقك بنمط Java

على سبيل المثال، لنفترض أنّ إصدار ملف APK هو 314159 واسم الحزمة هو com.example.app. إذا كنت تحميل ملف بيانات موسّعة رئيسي، ستتم إعادة تسمية الملف إلى:

main.314159.com.example.app.obb

مكان التخزين

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

تعرض الطريقة getObbDir() الموقع الجغرافي المحدّد. لملفات البيانات الموسّعة بالتنسيق التالي:

<shared-storage>/Android/obb/<package-name>/
  • <shared-storage> هو المسار إلى مساحة التخزين المشتركة، المتاحة من getExternalStorageDirectory()
  • <package-name> هو اسم حزمة تطبيقك بنمط Java، وهو متاح ابتداءً من getPackageName()

بالنسبة إلى كل تطبيق، لا يتوفر أكثر من ملفي بيانات موسّعة في هذا الدليل. أحدهما هو ملف البيانات الموسّعة الرئيسي والآخر ملف البيانات الموسّعة الاختيارية (إذا لزم الأمر). الْلِّي قَبْلْ كِدَهْ يتم استبدال الإصدارات عند تحديث تطبيقك بملفات بيانات موسّعة جديدة. منذ Android 4.4 (المستوى 19 من واجهة برمجة التطبيقات)، يمكن للتطبيقات قراءة ملفات بيانات موسّعة على OBB بدون مساحة تخزين خارجية إذن. ومع ذلك، لا تزال بعض عمليات تنفيذ الإصدار Android 6.0 (المستوى 23 من واجهة برمجة التطبيقات) والإصدارات الأحدث تتطلب لذلك، عليك الإفصاح عن إذن READ_EXTERNAL_STORAGE في بيان التطبيق وطلب الإذن من خلال على النحو التالي:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

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

Kotlin

val obb = File(obb_filename)
var open_failed = false

try {
    BufferedReader(FileReader(obb)).also { br ->
        ReadObbFile(br)
    }
} catch (e: IOException) {
    open_failed = true
}

if (open_failed) {
    // request READ_EXTERNAL_STORAGE permission before reading OBB file
    ReadObbFileWithPermission()
}

Java

File obb = new File(obb_filename);
 boolean open_failed = false;

 try {
     BufferedReader br = new BufferedReader(new FileReader(obb));
     open_failed = false;
     ReadObbFile(br);
 } catch (IOException e) {
     open_failed = true;
 }

 if (open_failed) {
     // request READ_EXTERNAL_STORAGE permission before reading OBB file
     ReadObbFileWithPermission();
 }

إذا كان يجب فك ضغط محتوى ملفات البيانات الموسّعة، لا تحذف ملف OBB ملف بيانات موسّعة بعد ذلك وعدم حفظ البيانات المجمّعة في الدليل نفسه. يجب حفظ الملفات غير المضغوطة في الدليل. المحددة بواسطة getExternalFilesDir(). ومع ذلك، فمن الأفضل استخدام تنسيق ملف بيانات موسّعة يسمح لك بالقراءة مباشرةً من للملف بدلاً من أن يطلب منك فك حزمة البيانات. على سبيل المثال، قدّمنا مكتبة ويُطلق عليه مكتبة APK Expansion Zip Library التي تقرأ بياناتك مباشرةً من ملف ZIP.

تنبيه: على عكس ملفات APK، يتم حفظ أي ملفات. في وحدة التخزين المشتركة، يمكن للمستخدم قراءتها والتطبيقات الأخرى.

ملاحظة: إذا كنت بصدد وضع ملفات الوسائط في ملف ZIP، يمكنك استخدام الوسائط تشغيل المكالمات على الملفات التي تتضمن عناصر تحكّم في الإزاحة والطول (مثل MediaPlayer.setDataSource() SoundPool.load()) بدون تحتاج إلى فك ضغط ملف ZIP. ولكي ينجح ذلك، يجب عدم إجراء ضغط إضافي على ملفات الوسائط عند إنشاء حزم ZIP. على سبيل المثال، عند استخدام أداة zip، يجب عليك استخدام الخيار -n لتحديد لاحقات الملفات التي يجب عدم مضغوط:
zip -n .mp4;.ogg main_expansion media_files

عملية التنزيل

في أغلب الأحيان، يُنزِّل Google Play ملفات البيانات الموسّعة ويحفظها في الوقت نفسه. لتنزيل حزمة APK على الجهاز. إلا أنّ Google Play في بعض الحالات يتعذر على تنزيل ملفات البيانات الموسّعة أو ربما حذف المستخدم البيانات الموسّعة التي تم تنزيلها سابقًا الملفات. لمعالجة هذه الحالات، يجب أن يتمكّن تطبيقك من تنزيل الملفات. نفسها عند بدء النشاط الرئيسي، باستخدام عنوان URL يوفّره Google Play.

تبدو عملية التنزيل من مستوى عالٍ كما يلي:

  1. يختار المستخدم تثبيت تطبيقك من Google Play.
  2. إذا كان Google Play قادرًا على تنزيل ملفات البيانات الموسّعة (هذا هو الحال في معظم الأجهزة)، يتم تنزيلها مع APK.

    إذا تعذّر على Google Play تنزيل ملفات البيانات الموسّعة، سيتم تنزيل حزمة APK فقط.

  3. عندما يشغِّل المستخدم تطبيقك، يجب أن يتحقّق التطبيق مما إذا كانت ملفات البيانات الموسّعة متاحة. سبق أن تم حفظه على الجهاز.
    1. إذا كانت الإجابة بنعم، يعني ذلك أنّ تطبيقك جاهز للاستخدام.
    2. إذا لم يكن الأمر كذلك، يجب أن ينزِّل تطبيقك ملفات البيانات الموسّعة عبر HTTP من Google Play. تطبيقك إرسال طلب إلى برنامج Google Play باستخدام خدمة ترخيص التطبيقات من Google Play، بالاسم وحجم الملف وعنوان URL لكل ملف بيانات موسّعة. باستخدام هذه المعلومات، يمكنك فنزِّل الملفات واحفظها في موقع التخزين المناسب.

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

قائمة التحقق من التطوير

في ما يلي ملخّص للمهام التي يجب تنفيذها لاستخدام ملفات البيانات الموسّعة مع التطبيق:

  1. عليك أولاً تحديد ما إذا كان حجم تنزيل التطبيق المضغوط يجب أن يتجاوز 100 ميغابايت. المساحة ثمينة لذا يجب أن يبقى إجمالي حجم التنزيل صغيرًا قدر الإمكان. إذا كان تطبيقك يستخدم أكثر من 100 ميغابايت لتوفير إصدارات متعددة من أصول الرسومات لشاشات متعددة لذا يمكنك نشر ملفات APK متعددة، حيث يمكن استخدام كل ملف APK بدلاً من ذلك. يحتوي فقط على الأصول المطلوبة للشاشات التي يستهدفها. للحصول على أفضل النتائج عند النشر على Google Play، حمِّل مجموعة حزمات تطبيق Android التي تتضمّن جميع الموارد والرموز التي تم تجميعها لتطبيقك، ولكنها تؤخّر إنشاء ملفات APK وتسجيل الدخول إلى Google اللعب.
  2. تحديد موارد التطبيقات التي تريد فصلها عن حزمة APK وتجميعها في ملف لاستخدامه كملف بيانات موسّعة رئيسي.

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

  3. طوِّر تطبيقك بحيث يستخدم الموارد من ملفات البيانات الموسّعة في موقع مساحة التخزين المشتركة للجهاز.

    وتذكَّر أنه لا يجب حذف ملفات البيانات الموسّعة أو نقلها أو إعادة تسميتها.

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

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

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

    فإذا أنشأت خدمة تنزيل خاصة بك بدلاً من استخدام المكتبة، فاعلم أنك يجب ألا يغير اسم ملفات البيانات الموسّعة وأن تحفظها في المجلد مكان التخزين.

بعد الانتهاء من تطوير التطبيق، اتّبِع دليل اختبار. ملفات البيانات الموسّعة

القواعد والقيود

يمكنك إضافة ملفات البيانات الموسّعة الخاصة بحزمة APK ميزة متاحة عند تحميل تطبيقك باستخدام Play Console: عند تحميل تطبيقك للمرة الأولى أو تحديث تطبيق يستخدم ملفات البيانات الموسّعة، يجب أن تكون على دراية بالقواعد والقيود التالية:

  1. يجب ألا يزيد حجم كل ملف بيانات موسّعة عن 2 غيغابايت.
  2. لتنزيل ملفات البيانات الموسّعة من Google Play، يجب أن يكون لدى المستخدم احصل على تطبيقك من Google Play. لن يتمكن Google Play من تقديم عناوين URL لملفات البيانات الموسّعة إذا تم تثبيت التطبيق بطريقة أخرى
  3. عنوان URL الذي تستخدمه Google Play عند إجراء عملية التنزيل من داخل التطبيق لكل ملف تكون فريدة لكل عملية تنزيل، وتنتهي صلاحية كل ملف بعد فترة وجيزة من منحه. إلى تطبيقك.
  4. في حال تحديث تطبيقك باستخدام حزمة APK جديدة أو تحميل عدة حِزم APK لها فيمكنك تحديد ملفات البيانات الموسّعة التي حمّلتها إلى حزمة APK سابقة. عدم تغيير اسم ملف البيانات الموسّعة، فهو يحتفظ بالإصدار الذي تم استلامه بواسطة حزمة APK الذي كان الملف مرتبطًا به في الأصل.
  5. إذا كنت تستخدم ملفات البيانات الموسّعة مع حِزم APK متعددة من أجل تقديم ملفات بيانات موسّعة لأجهزة مختلفة، ولكن يجب تحميل حِزم APK منفصلة. لكل جهاز من أجل توفير سمة versionCode فريدة وأعلِن عن فلاتر مختلفة في لكل ملف APK.
  6. لا يمكنك تحديث تطبيقك من خلال تغيير ملفات البيانات الموسّعة. فقط، عليك تحميل حزمة APK جديدة لتحديث تطبيقك. في حال كانت التغييرات فقط بالنسبة إلى مواد العرض الواردة في ملفات البيانات الموسّعة، يمكنك تحديث حزمة APK ببساطة عن طريق تغيير الرمز versionCode ( وربما أيضًا versionName).

  7. عدم حفظ البيانات الأخرى في obb/ الدليل. وإذا كان عليك فك ضغط بعض البيانات، عليك حفظها في الموقع الجغرافي الذي تحدِّده السياسة getExternalFilesDir().
  8. لا تحذف ملف البيانات الموسّعة .obb أو أعِد تسميته (ما لم تكن إجراء تحديث). سيؤدي إجراء ذلك إلى تكرّر Google Play (أو تطبيقك نفسه) فقم بتنزيل ملف البيانات الموسّعة.
  9. عند تعديل ملف بيانات موسّعة يدويًا، يجب حذف ملف البيانات الموسّعة السابق.

تنزيل ملفات البيانات الموسّعة

في معظم الحالات، ينزِّل Google Play ملفات البيانات الموسّعة ويحفظها على الجهاز نفسه. وقت تثبيت حزمة APK أو تحديثها. بهذه الطريقة، تتوفر ملفات البيانات الموسّعة عندما تطبيقك لأول مرة. ومع ذلك، في بعض الحالات، على تطبيقك تنزيل ملف البيانات الموسّعة نفسه عن طريق طلبها من عنوان URL يتم توفيره لك في رد من خدمة ترخيص التطبيقات في Google Play.

المنطق الأساسي الذي تحتاج إليه لتنزيل ملفات البيانات الموسّعة هو ما يلي:

  1. عند بدء تشغيل تطبيقك، ابحث عن ملفات البيانات الموسّعة في موقع مساحة التخزين المشتركة (في قسم الدليل Android/obb/<package-name>/).
    1. إذا كانت ملفات البيانات الموسّعة متاحة، يعني ذلك أنّ تطبيقك أصبح جاهزًا ويمكن استخدامه لمواصلة العمل.
    2. إذا لم تكن ملفات البيانات الموسّعة متاحة:
      1. نفِّذ طلب باستخدام ترخيص التطبيق في Google Play للحصول على أسماء ملفات توسيع التطبيق وأحجامها وعناوين URL الخاصة بها.
      2. استخدِم عناوين URL التي يوفّرها Google Play لتنزيل ملفات البيانات الموسّعة وحفظها. ملفات البيانات الموسّعة. يجب حفظ الملفات في موقع مساحة التخزين المشتركة. (Android/obb/<package-name>/) واستخدِم اسم الملف المحدد بالضبط حسب ردّ Google Play

        ملاحظة: عنوان URL الذي يوفّره Google Play تكون ملفات البيانات الموسّعة فريدة لكل عملية تنزيل، وتنتهي صلاحية كل ملف بعد وقت قصير من منحه إلى تطبيقك.

إذا كان تطبيقك مجانيًا (وليس تطبيقًا مدفوعًا)، هذا يعني أنّك على الأرجح لم تستخدم خدمة ترخيص التطبيق. وهي في الأساس مصممة لك لفرض سياسات ترخيص تطبيقك والتأكّد من أنّ المستخدم لديه الحق في استخدام تطبيقك (أي أنه دفع ثمنه على Google Play) من أجل تسهيل وظيفة ملف بيانات موسّعة، تم تحسين خدمة الترخيص لتقديم استجابة إلى تطبيقك الذي يتضمّن عنوان URL الخاص بملفات البيانات الموسّعة الخاصة بتطبيقك والتي تتم استضافتها على Google Play. لذلك، حتى إذا كان تطبيقك مجانيًا للمستخدمين، عليك تضمين مكتبة إثبات صحة الترخيص (LVL) لاستخدام ملفات البيانات الموسّعة لحِزم APK بالطبع، إذا كان تطبيقك مجاني، ولن تحتاج إلى فرض التحقق من الترخيص—ما عليك سوى لتنفيذ الطلب الذي يعرض عنوان URL لملفات بيانات موسّعة.

ملاحظة: سواء كان تطبيقك مجانيًا أم لا، سيكون Google Play عناوين URL لملف البيانات الموسّعة فقط إذا حصل المستخدم على تطبيقك من Google Play.

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

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

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

إذا كنت تفضّل تطوير حل خاص بك لتنزيل ملفات البيانات الموسّعة باستخدام واجهة برمجة التطبيقات Play URL، يجب أن تتبع تطبيق مستندات الترخيص لتنفيذ طلب الترخيص، ثم استرداد أسماء ملفات البيانات الموسّعة والأحجام وعناوين URL من الميزات الإضافية للاستجابة. عليك استخدام الفئة APKExpansionPolicy (المضمّنة في "مكتبة التحقّق من التراخيص") كترخيص لك. التي تسجِّل أسماء ملفات البيانات الموسّعة وأحجامها وعناوين URL من خدمة الترخيص.

معلومات عن مكتبة "أداة التنزيل"

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

لتنفيذ عمليات تنزيل ملفات البيانات الموسّعة باستخدام مكتبة أداة التنزيل، كل ما عليك فعله هو:

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

توضّح الأقسام التالية كيفية إعداد تطبيقك باستخدام مكتبة أداة التنزيل.

جارٍ التحضير لاستخدام مكتبة أدوات التنزيل

لاستخدام مكتبة "أداة التنزيل"، يجب: نزِّل حزمتَين من "مدير حِزم SDK" وأضِف المكتبات المناسبة إلى التطبيق.

أولاً، افتح مدير حزمة تطوير البرامج (SDK) لنظام التشغيل Android. (الأدوات > مدير حِزم تطوير البرامج (SDK))، وضمن المظهر السلوك > إعدادات النظام > حزمة تطوير البرامج (SDK) لنظام التشغيل Android، اختَر في علامة التبويب أدوات حزمة تطوير البرامج (SDK) لاختيار ما يلي وتنزيله:

  • حزمة Google Play Licensing Library (مكتبة تراخيص Google Play)
  • حزمة توسيع مكتبة APK في Google Play

إنشاء وحدة مكتبة جديدة لكل من "مكتبة التحقّق من التراخيص" و"أداة التنزيل" المكتبة. لكل مكتبة:

  1. حدد ملف > جديد > وحدة جديدة:
  2. في النافذة إنشاء وحدة جديدة، اختَر مكتبة Android. ثم انقر على التالي.
  3. حدِّد اسم التطبيق أو المكتبة، مثل "مكتبة تراخيص Google Play" و"مكتبة أداة تنزيل Google Play"، اختَر الحد الأدنى لمستوى حزمة تطوير البرامج (SDK)، ثم اختَر إنهاء
  4. حدد ملف > بنية المشروع:
  5. انقر على علامة التبويب الخصائص وفي المكتبة. المستودع، أدخِل المكتبة من الدليل <sdk>/extras/google/ (play_licensing/ لمكتبة إثبات الملكية أو play_apk_expansion/downloader_library/ لمكتبة أدوات التنزيل).
  6. اختَر حسنًا لإنشاء الوحدة الجديدة.

ملاحظة: تعتمد مكتبة "أداة التنزيل" على الترخيص مكتبة إثبات الملكية تأكَّد من إضافة الترخيص. مكتبة إثبات الملكية إلى مواقع مشروع مكتبة التنزيل.

أو يمكنك من سطر الأوامر تحديث مشروعك لتضمين المكتبات:

  1. تغيير الأدلة إلى الدليل <sdk>/tools/
  2. نفِّذ android update project باستخدام الخيار --library لإضافة كل من LVL ومكتبة أداة التنزيل إلى مشروعك. مثل:
    android update project --path ~/Android/MyApp \
    --library ~/android_sdk/extras/google/market_licensing \
    --library ~/android_sdk/extras/google/market_apk_expansion/downloader_library
    

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

ملاحظة: تتضمّن حزمة Apk Expansion عيّنة. تطبيق واحد يوضح كيفية استخدام مكتبة "أدوات التنزيل" في أحد التطبيقات. يستخدم العيّنة مكتبة ثالثة المتوفر في حزمة Apk Expansion التي تحمل اسم مكتبة APK Expansion Zip Library. في حال حذف تخطط باستخدام ملفات ZIP لملفات البيانات الموسّعة، ننصحك أيضًا بإضافة مكتبة APK Expansion Zip Library إلى تطبيقك. لمزيد من المعلومات، يُرجى الاطّلاع على القسم أدناه. حول استخدام مكتبة APK Expansion Zip Library

إعلان أذونات المستخدمين

لتنزيل ملفات البيانات الموسّعة، يجب أن تستخدم مكتبة التنزيل يتطلّب استخدام التطبيق عدة أذونات يجب الإفصاح عنها في ملف البيان الخاص بتطبيقك. هم هي:

<manifest ...>
    <!-- Required to access Google Play Licensing -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />

    <!-- Required to download files from Google Play -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Required to keep CPU alive while downloading files
        (NOT to keep screen awake) -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <!-- Required to poll the state of the network connection
        and respond to changes -->
    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- Required to check whether Wi-Fi is enabled -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <!-- Required to read and write the expansion files on shared storage -->
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

ملاحظة: تتطلب "مكتبة أدوات التنزيل" تلقائيًا واجهة برمجة تطبيقات المستوى 4، ولكن تتطلب مكتبة APK Expansion Zip Library المستوى 5 من واجهة برمجة التطبيقات.

تنفيذ خدمة أدوات التنزيل

لإجراء عمليات تنزيل في الخلفية، توفر مكتبة التنزيل الفئة الفرعية Service الخاصة بك المسماة DownloaderService والتي يجب تمديدها. ضِمن بالإضافة إلى تنزيل ملفات البيانات الموسّعة الخاصة بك، تعمل DownloaderService أيضًا على:

  • تسجيل BroadcastReceiver الذي يستمع إلى التغييرات التي تطرأ على اتصالاً بالشبكة للجهاز (CONNECTIVITY_ACTION البث) لإيقاف التنزيل مؤقتًا عند الضرورة (مثلاً بسبب فقدان الاتصال) استئناف التنزيل عندما يكون ذلك ممكنًا (يتم اكتساب إمكانية الاتصال)
  • تعمل هذه السياسة على جدولة منبّه الساعة RTC_WAKEUP لإعادة محاولة التنزيل لمدة الحالات التي يتم فيها إنهاء الخدمة.
  • تنشئ Notification مخصّصة تعرض مستوى تقدّم عملية التنزيل أي أخطاء أو تغييرات في الحالة.
  • يسمح هذا الإذن لتطبيقك بإيقاف التنزيل مؤقتًا واستئناف التنزيل يدويًا.
  • التحقق من أن وحدة التخزين المشتركة مثبتة ومتاحة، وأن الملفات غير موجودة، وتوفُّر مساحة كافية، كل ذلك قبل تنزيل ملفات البيانات الموسّعة. بعد ذلك، يتم إشعار المستخدم إذا كان أي منها غير صحيح.

ما عليك سوى إنشاء فئة في تطبيقك توسّع فئة DownloaderService وإلغاء الطرق الثلاث لتقديم تفاصيل محدَّدة عن التطبيق:

getPublicKey()
يجب أن يعرض هذا سلسلة تمثّل المفتاح العام RSA المشفر بترميز Base64 للناشر. متاح من صفحة الملف الشخصي على Play Console (راجِع الإعداد للترخيص).
getSALT()
يجب أن يعرض هذا مصفوفة من وحدات البايت العشوائية التي يستخدمها الترخيص Policy. إنشاء Obfuscator ويضمن القيم الملحة أن تكون قيمة SharedPreferences التي تم تشويشها. يكون الملف الذي يتم حفظ بيانات الترخيص فيه فريدًا وغير قابل للاكتشاف.
getAlarmReceiverClassName()
يجب أن يعرض هذا اسم فئة BroadcastReceiver في تطبيقك الذي من المفترَض أن يتلقّى منبّهًا يشير إلى أنّ التنزيل يجب أن يكون إعادة تشغيل (ما قد يحدث في حالة توقف خدمة التنزيل بشكل غير متوقع).

على سبيل المثال، إليك التنفيذ الكامل لـ DownloaderService:

Kotlin

// You must use the public key belonging to your publisher account
const val BASE64_PUBLIC_KEY = "YourLVLKey"
// You should also modify this salt
val SALT = byteArrayOf(
        1, 42, -12, -1, 54, 98, -100, -12, 43, 2,
        -8, -4, 9, 5, -106, -107, -33, 45, -1, 84
)

class SampleDownloaderService : DownloaderService() {

    override fun getPublicKey(): String = BASE64_PUBLIC_KEY

    override fun getSALT(): ByteArray = SALT

    override fun getAlarmReceiverClassName(): String = SampleAlarmReceiver::class.java.name
}

Java

public class SampleDownloaderService extends DownloaderService {
    // You must use the public key belonging to your publisher account
    public static final String BASE64_PUBLIC_KEY = "YourLVLKey";
    // You should also modify this salt
    public static final byte[] SALT = new byte[] { 1, 42, -12, -1, 54, 98,
            -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84
    };

    @Override
    public String getPublicKey() {
        return BASE64_PUBLIC_KEY;
    }

    @Override
    public byte[] getSALT() {
        return SALT;
    }

    @Override
    public String getAlarmReceiverClassName() {
        return SampleAlarmReceiver.class.getName();
    }
}

إشعار: عليك تعديل قيمة BASE64_PUBLIC_KEY. ليكون المفتاح العام الذي ينتمي إلى حساب الناشر الخاص بك. يمكنك العثور على المفتاح في صفحة "مطوّر البرامج". وحدة التحكم ضمن معلومات ملفك الشخصي. وهذا ضروري حتى عند الاختبار تنزيلاتك.

يجب الإفصاح عن الخدمة في ملف البيان:

<app ...>
    <service android:name=".SampleDownloaderService" />
    ...
</app>

تنفيذ جهاز استقبال المنبّه

لمراقبة تقدم تنزيلات الملفات وإعادة التنزيل إذا لزم الأمر، يجدول "DownloaderService" منبّه "RTC_WAKEUP" الذي تسليم Intent إلى BroadcastReceiver في التطبيق. يجب تحديد BroadcastReceiver لطلب واجهة برمجة تطبيقات. من مكتبة أدوات التنزيل التي تتحقّق من حالة التنزيل وتعيد تشغيله إذا لزم الأمر.

ما عليك سوى إلغاء طريقة onReceive() لاستدعاء DownloaderClientMarshaller.startDownloadServiceIfRequired().

مثلاً:

Kotlin

class SampleAlarmReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        try {
            DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    context,
                    intent,
                    SampleDownloaderService::class.java
            )
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
    }
}

Java

public class SampleAlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            DownloaderClientMarshaller.startDownloadServiceIfRequired(context,
                intent, SampleDownloaderService.class);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}

لاحظ أن هذه هي الفئة التي يجب أن تعرض الاسم لها في طريقة getAlarmReceiverClassName() الخاصة بالخدمة (راجِع القسم السابق).

تذكَّر الإفصاح عن المستلِم في ملف البيان:

<app ...>
    <receiver android:name=".SampleAlarmReceiver" />
    ...
</app>

بدء التنزيل

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

يتطلب بدء التنزيل باستخدام مكتبة أداة التنزيل ما يلي: الإجراءات:

  1. تحقّق مما إذا تم تنزيل الملفات.

    تحتوي "مكتبة أدوات التنزيل" على بعض واجهات برمجة التطبيقات في الفئة Helper من أجل في هذه العملية:

    • getExpansionAPKFileName(Context, c, boolean mainFile, int versionCode)
    • doesFileExist(Context c, String fileName, long fileSize)

    على سبيل المثال، يستدعي نموذج التطبيق المُقدَّم في حزمة Apk Expansion في طريقة onCreate() الخاصة بالنشاط للتحقّق من ما إذا كانت ملفات البيانات الموسّعة متوفّرة على الجهاز حاليًا:

    Kotlin

    fun expansionFilesDelivered(): Boolean {
        xAPKS.forEach { xf ->
            Helpers.getExpansionAPKFileName(this, xf.isBase, xf.fileVersion).also { fileName ->
                if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false))
                    return false
            }
        }
        return true
    }
    

    Java

    boolean expansionFilesDelivered() {
        for (XAPKFile xf : xAPKS) {
            String fileName = Helpers.getExpansionAPKFileName(this, xf.isBase,
                xf.fileVersion);
            if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false))
                return false;
        }
        return true;
    }
    

    في هذه الحالة، يحمل كل عنصر XAPKFile رقم الإصدار وحجم ملفّ معروفَين ملف بيانات موسّعة وقيمة منطقية لتحديد ما إذا كان ملف البيانات الموسّعة الرئيسي. (اطّلِع على العيّنة فئة SampleDownloaderActivity في التطبيق لمعرفة التفاصيل).

    وفي حال عرضت هذه الطريقة القيمة false، حينئذٍ يجب أن يبدأ التطبيق عملية التنزيل.

  2. ابدأ التنزيل باستدعاء الطريقة الثابتة DownloaderClientMarshaller.startDownloadServiceIfRequired(Context c, PendingIntent notificationClient, Class<?> serviceClass).

    تستخدم الطريقة المعلمات التالية:

    • context: Context الخاص بتطبيقك
    • notificationClient: PendingIntent لبدء تشغيل المفتاح الرئيسي الأخرى. ويتم استخدام هذه المعلومات في Notification التي تمت فيها سياسة DownloaderService لإظهار مدى تقدم التنزيل. عندما يحدد المستخدم الإشعار، يوقف النظام يستدعي PendingIntent الذي تقدمه هنا ويجب أن يفتح النشاط يعرض مستوى تقدّم عملية التنزيل (يكون عادةً هو النشاط نفسه الذي بدأ عملية التنزيل).
    • serviceClass: الهدف Class لتنفيذ DownloaderService، مطلوب لبدء الخدمة وبدء التنزيل إذا لزم الأمر.

    تُرجع الطريقة عددًا صحيحًا يشير إلى وما إذا كان التنزيل مطلوبًا أم لا. القيم المتاحة:

    • NO_DOWNLOAD_REQUIRED: يتم عرضه إذا سبق أن تم عرض الملفات أو هناك عملية تنزيل قيد التقدم.
    • LVL_CHECK_REQUIRED: يتم عرضه إذا كان التحقق من الترخيص المطلوبة للحصول على عناوين URL لملفات البيانات الموسّعة.
    • DOWNLOAD_REQUIRED: يتم عرضه إذا كانت عناوين URL لملفات البيانات الموسّعة معروفة من قبل، ولكن لم يتم تنزيلها.

    يُعد سلوك LVL_CHECK_REQUIRED وDOWNLOAD_REQUIRED في الأساس نفسها، ولا داعي عادةً للقلق حيالها. في نشاطك الرئيسي الذي يتّصل بـ "startDownloadServiceIfRequired()"، يمكنك ببساطة التحقّق ممّا إذا كان الردّ NO_DOWNLOAD_REQUIRED أم لا. إذا كان الردّ هو أي شيء بخلاف NO_DOWNLOAD_REQUIRED، تبدأ مكتبة أداة التنزيل عملية التنزيل وعليك تعديل واجهة مستخدم نشاطك إلى عرض تقدم التنزيل (راجع الخطوة التالية). إذا كانت الاستجابة هي NO_DOWNLOAD_REQUIRED، يعني ذلك أنّ الملفات متاحة ويمكن لتطبيقك بدء تشغيلها.

    مثلاً:

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        // Check if expansion files are available before going any further
        if (!expansionFilesDelivered()) {
            val pendingIntent =
                    // Build an Intent to start this activity from the Notification
                    Intent(this, MainActivity::class.java).apply {
                        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
                    }.let { notifierIntent ->
                        PendingIntent.getActivity(
                                this,
                                0,
                                notifierIntent,
                                PendingIntent.FLAG_UPDATE_CURRENT
                        )
                    }
    
    
            // Start the download service (if required)
            val startResult: Int = DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    this,
                    pendingIntent,
                    SampleDownloaderService::class.java
            )
            // If download has started, initialize this activity to show
            // download progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // This is where you do set up to display the download
                // progress (next step)
                ...
                return
            } // If the download wasn't necessary, fall through to start the app
        }
        startApp() // Expansion files are available, start the app
    }
    

    Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Check if expansion files are available before going any further
        if (!expansionFilesDelivered()) {
            // Build an Intent to start this activity from the Notification
            Intent notifierIntent = new Intent(this, MainActivity.getClass());
            notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                                    Intent.FLAG_ACTIVITY_CLEAR_TOP);
            ...
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                    notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    
            // Start the download service (if required)
            int startResult =
                DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                            pendingIntent, SampleDownloaderService.class);
            // If download has started, initialize this activity to show
            // download progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // This is where you do set up to display the download
                // progress (next step)
                ...
                return;
            } // If the download wasn't necessary, fall through to start the app
        }
        startApp(); // Expansion files are available, start the app
    }
    
  3. عندما تعرض الطريقة startDownloadServiceIfRequired() أي عنصر other من NO_DOWNLOAD_REQUIRED، قم بإنشاء مثيل لـ IStub بواسطة يَتِمُّ الْآنَ الِاتِّصَالْ بِـ DownloaderClientMarshaller.CreateStub(IDownloaderClient client, Class<?> downloaderService). يوفّر IStub ربطًا بين نشاطك بأداة التنزيل. لكي يتلقّى نشاطك استدعاءات حول تقدّم التنزيل.

    لإنشاء مثيل IStub عن طريق الاتصال بـ CreateStub()، يجب تمريره. تنفيذ واجهة IDownloaderClient وDownloaderService التنفيذ. يناقش القسم التالي حول استلام مستوى تقدّم التنزيل. واجهة IDownloaderClient التي يجب تنفيذها عادةً في فئة Activity لتتمكّن من تعديل واجهة مستخدم النشاط عند تغيُّر حالة التنزيل

    ننصحك بالاتصال بـ CreateStub() لإنشاء مثيل لـ IStub أثناء استخدام طريقة onCreate() لنشاطك، بعد startDownloadServiceIfRequired(). بدء التنزيل.

    على سبيل المثال، في نموذج الرمز السابق الخاص بـ onCreate()، يمكنك الرد على نتيجة startDownloadServiceIfRequired() على النحو التالي:

    Kotlin

            // Start the download service (if required)
            val startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
                    this@MainActivity,
                    pendingIntent,
                    SampleDownloaderService::class.java
            )
            // If download has started, initialize activity to show progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // Instantiate a member instance of IStub
                downloaderClientStub =
                        DownloaderClientMarshaller.CreateStub(this, SampleDownloaderService::class.java)
                // Inflate layout that shows download progress
                setContentView(R.layout.downloader_ui)
                return
            }
    

    Java

            // Start the download service (if required)
            int startResult =
                DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                            pendingIntent, SampleDownloaderService.class);
            // If download has started, initialize activity to show progress
            if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                // Instantiate a member instance of IStub
                downloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
                        SampleDownloaderService.class);
                // Inflate layout that shows download progress
                setContentView(R.layout.downloader_ui);
                return;
            }
    

    بعد إرجاع طريقة onCreate()، يتم تسجيل نشاطك تلقي مكالمة مع onResume()، وهو المكان الذي ينبغي لك بعد ذلك الاتصال بـ connect() على IStub، وضبط رقم Context الخاص بتطبيقك على العكس، يجب عليك استدعاء disconnect() في معاودة الاتصال بالرقم onStop() لنشاطك.

    Kotlin

    override fun onResume() {
        downloaderClientStub?.connect(this)
        super.onResume()
    }
    
    override fun onStop() {
        downloaderClientStub?.disconnect(this)
        super.onStop()
    }
    

    Java

    @Override
    protected void onResume() {
        if (null != downloaderClientStub) {
            downloaderClientStub.connect(this);
        }
        super.onResume();
    }
    
    @Override
    protected void onStop() {
        if (null != downloaderClientStub) {
            downloaderClientStub.disconnect(this);
        }
        super.onStop();
    }
    

    يؤدي الاتصال بالرقم connect() على IStub إلى ربط نشاطك بـ DownloaderService لكي يتلقّى نشاطك استدعاءات بشأن التغييرات التي طرأت على عملية التنزيل. من خلال واجهة IDownloaderClient.

جارٍ تلقّي تقدُّم التنزيل

لتلقّي آخر الأخبار المتعلقة بمدى تقدّم عملية التنزيل والتفاعل مع DownloaderService، يجب تنفيذ واجهة IDownloaderClient في مكتبة أداة التنزيل. وعادةً، يجب أن يعمل النشاط الذي تستخدمه لبدء التنزيل على تنفيذ هذه الواجهة من أجل عرض تقدم التنزيل وإرسال الطلبات إلى الخدمة.

طرق الواجهة المطلوبة لتطبيق IDownloaderClient هي:

onServiceConnected(Messenger m)
بعد إنشاء مثيل لـ IStub في نشاطك، ستتلقّى مكالمة على هذا التي تمرِّر كائن Messenger المرتبط بالمثيل من DownloaderService. لإرسال طلبات إلى الخدمة، مثل الإيقاف المؤقت والاستئناف للتنزيل، يجب الاتصال بـ DownloaderServiceMarshaller.CreateProxy() للحصول على واجهة IDownloaderService المتصلة بالخدمة.

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

Kotlin

private var remoteService: IDownloaderService? = null
...

override fun onServiceConnected(m: Messenger) {
    remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply {
        downloaderClientStub?.messenger?.also { messenger ->
            onClientUpdated(messenger)
        }
    }
}

Java

private IDownloaderService remoteService;
...

@Override
public void onServiceConnected(Messenger m) {
    remoteService = DownloaderServiceMarshaller.CreateProxy(m);
    remoteService.onClientUpdated(downloaderClientStub.getMessenger());
}

عند إعداد كائن IDownloaderService، يمكنك إرسال الأوامر إلى خدمة التنزيل، مثل إيقاف التنزيل مؤقتًا واستئنافه (requestPauseDownload() وrequestContinueDownload()).

onDownloadStateChanged(int newState)
تستدعي خدمة التنزيل هذا الإجراء عند حدوث تغيير في حالة التنزيل، مثل يبدأ التنزيل أو تكتمل.

ستكون قيمة newState واحدة من القيم العديدة المحتملة المحددة في في أحد ثوابت STATE_* لفئة IDownloaderClient.

لتقديم رسالة مفيدة للمستخدمين، يمكنك طلب سلسلة مقابلة. لكل ولاية من خلال الاتصال بالرقم Helpers.getDownloaderStringResourceIDFromState(). هذا النمط لعرض معرّف المورد لإحدى السلاسل المرفقة مع "أداة التنزيل" المكتبة. على سبيل المثال، لا يمكن استخدام السلسلة "تم إيقاف التنزيل مؤقتًا بسبب التجوال" يتجاوب مع STATE_PAUSED_ROAMING.

onDownloadProgress(DownloadProgressInfo progress)
تستدعي خدمة التنزيل هذا لإرسال كائن DownloadProgressInfo، الذي يصف معلومات مختلفة حول تقدّم التنزيل، بما في ذلك الوقت المقدَّر المتبقي والسرعة الحالية والتقدم العام والإجمالي حتى تتمكن من تحديث واجهة مستخدم تقدم التنزيل.

ملاحظة: للحصول على أمثلة على عمليات معاودة الاتصال هذه التي تعدِّل التنزيل واجهة المستخدم الخاصة بالتقدم، اطّلِع على SampleDownloaderActivity في نموذج التطبيق المقدَّم مع حزمة Apk Expansion

في ما يلي بعض الطرق العامة لاستخدام واجهة IDownloaderService التي قد تجدها مفيدة:

requestPauseDownload()
إيقاف التنزيل مؤقتًا.
requestContinueDownload()
استئناف عملية تنزيل متوقّفة مؤقتًا.
setDownloadFlags(int flags)
يضبط هذا الإعداد إعدادات المستخدم المفضّلة لأنواع الشبكات التي يمكن تنزيل الملفات عليها. تشير رسالة الأشكال البيانية ويتيح التنفيذ الحالي علامة واحدة، وهي FLAGS_DOWNLOAD_OVER_CELLULAR، ولكن يمكنك إضافة آخرون. لا يتم تفعيل هذه العلامة تلقائيًا، لذلك يجب أن يكون المستخدم متصلاً بشبكة Wi-Fi لتنزيل التطبيق. ملفات البيانات الموسّعة. قد ترغب في تقديم تفضيل للمستخدم لتفعيل عمليات التنزيل عبر شبكة الجوّال. في هذه الحالة، يمكنك استدعاء:

Kotlin

remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply {
    ...
    setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR)
}

Java

remoteService
    .setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR);

استخدام APKExpansionPolicy

إذا قررت إنشاء خدمة تنزيل خاصة بك بدلاً من استخدام Google Play مكتبة أدوات التنزيل، يجب مواصلة استخدام APKExpansionPolicy المتوفرة في مكتبة إثبات ملكية التراخيص. تتطابق الفئة APKExpansionPolicy تقريبًا مع الفئة ServerManagedPolicy (متوفّرة في مكتبة التحقّق من تراخيص Google Play) ولكنها تتضمّن معالجة إضافية لتوسيع حزمة APK الميزات الإضافية للاستجابة للملفات.

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

تتضمن الفئة طرقًا لمساعدتك في الحصول على المعلومات الضرورية حول الطرق المتاحة ملفات البيانات الموسّعة:

  • getExpansionURLCount()
  • getExpansionURL(int index)
  • getExpansionFileName(int index)
  • getExpansionFileSize(int index)

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

قراءة ملف التوسيع

بعد حفظ ملفات البيانات الموسّعة الخاصة بحزمة APK على الجهاز، تعرَّف على طريقة قراءة الملفات. على نوع الملف الذي استخدمته. كما تمت مناقشته في النظرة العامة، فإن أي نوع من الملفات التي تريد يريدونها، ولكن تتم إعادة تسميتها باستخدام تنسيق اسم ملف معين ويتم حفظها في <shared-storage>/Android/obb/<package-name>/

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

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

الحصول على أسماء الملفات

كما هو موضّح في النظرة العامة، يتم حفظ ملفات البيانات الموسّعة لحزمة APK باستخدام تنسيق اسم ملف محدد:

[main|patch].<expansion-version>.<package-name>.obb

لمعرفة موقع ملفات البيانات الموسّعة وأسمائها، يجب استخدام getExternalStorageDirectory() وgetPackageName() لإنشاء المسار إلى ملفاتك.

إليك طريقة يمكنك استخدامها في تطبيقك للحصول على مصفوفة تحتوي على المسار الكامل إلى كل من ملفي البيانات الموسّعة:

Kotlin

fun getAPKExpansionFiles(ctx: Context, mainVersion: Int, patchVersion: Int): Array<String> {
    val packageName = ctx.packageName
    val ret = mutableListOf<String>()
    if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
        // Build the full path to the app's expansion files
        val root = Environment.getExternalStorageDirectory()
        val expPath = File(root.toString() + EXP_PATH + packageName)

        // Check that expansion file path exists
        if (expPath.exists()) {
            if (mainVersion > 0) {
                val strMainPath = "$expPath${File.separator}main.$mainVersion.$packageName.obb"
                val main = File(strMainPath)
                if (main.isFile) {
                    ret += strMainPath
                }
            }
            if (patchVersion > 0) {
                val strPatchPath = "$expPath${File.separator}patch.$mainVersion.$packageName.obb"
                val main = File(strPatchPath)
                if (main.isFile) {
                    ret += strPatchPath
                }
            }
        }
    }
    return ret.toTypedArray()
}

Java

// The shared path to all app expansion files
private final static String EXP_PATH = "/Android/obb/";

static String[] getAPKExpansionFiles(Context ctx, int mainVersion,
      int patchVersion) {
    String packageName = ctx.getPackageName();
    Vector<String> ret = new Vector<String>();
    if (Environment.getExternalStorageState()
          .equals(Environment.MEDIA_MOUNTED)) {
        // Build the full path to the app's expansion files
        File root = Environment.getExternalStorageDirectory();
        File expPath = new File(root.toString() + EXP_PATH + packageName);

        // Check that expansion file path exists
        if (expPath.exists()) {
            if ( mainVersion > 0 ) {
                String strMainPath = expPath + File.separator + "main." +
                        mainVersion + "." + packageName + ".obb";
                File main = new File(strMainPath);
                if ( main.isFile() ) {
                        ret.add(strMainPath);
                }
            }
            if ( patchVersion > 0 ) {
                String strPatchPath = expPath + File.separator + "patch." +
                        mainVersion + "." + packageName + ".obb";
                File main = new File(strPatchPath);
                if ( main.isFile() ) {
                        ret.add(strPatchPath);
                }
            }
        }
    }
    String[] retArray = new String[ret.size()];
    ret.toArray(retArray);
    return retArray;
}

يمكنك استدعاء هذه الطريقة من خلال تمريرها إلى تطبيقك Context وإصدار ملف البيانات الموسّعة المطلوب.

هناك العديد من الطرق التي يمكنك من خلالها تحديد رقم إصدار ملف البيانات الموسّعة. تتمثل إحدى الطرق البسيطة في احفظ النسخة في ملف SharedPreferences عند بدء التنزيل، من خلال الاستعلام عن اسم ملف البيانات الموسّعة باستخدام طريقة getExpansionFileName(int index) للفئة APKExpansionPolicy. يمكنك بعد ذلك الحصول على رمز الإصدار من خلال قراءة ملف SharedPreferences عندما تريد الوصول إلى التوسيع. الملف.

لمزيد من المعلومات حول القراءة من مساحة التخزين المشتركة، يُرجى الاطّلاع على قسم مساحة تخزين البيانات التوثيق.

استخدام مكتبة APK Expansion Zip Library

تتضمن حزمة Google Market Apk Expansion مكتبة تسمى APK مكتبة موسّعة بتنسيق Zip (متوفّرة في "<sdk>/extras/google/google_market_apk_expansion/zip_file/") هذه مكتبة اختيارية في قراءة التوسيع الملفات عند حفظها كملفات ZIP. يتيح لك استخدام هذه المكتبة قراءة الموارد بسهولة من ملفات توسيع ZIP كنظام ملفات افتراضي.

تشتمل مكتبة APK Expansion Zip Library على الفئات وواجهات برمجة التطبيقات التالية:

APKExpansionSupport
توفّر بعض الطرق للوصول إلى أسماء ملفات البيانات الموسّعة وملفات ZIP:
getAPKExpansionFiles()
الطريقة نفسها الموضّحة أعلاه والتي تعرض المسار الكامل للملف في كلتا المجموعتَين الملفات.
getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion)
عرض ZipResourceFile الذي يمثل مجموع كل من الملف الرئيسي ملف التصحيح. بمعنى آخر، إذا حددت كلاً من mainVersion و patchVersion، يؤدي ذلك إلى عرض خطأ ZipResourceFile يوفّر إمكانية الوصول للقراءة إلى كل البيانات، مع دمج بيانات ملف التصحيح في أعلى الملف الرئيسي.
ZipResourceFile
يمثل ملف ZIP على مساحة التخزين المشتركة وتنفيذ كل الأعمال لتوفير ملف افتراضي. نظام الملفات بناءً على ملفات ZIP. يمكنك الحصول على مثيل باستخدام APKExpansionSupport.getAPKExpansionZipFile() أو من خلال ZipResourceFile من خلال تمريره المسار إلى ملف البيانات الموسّعة. تتضمن هذه الفئة مجموعة متنوعة من الطرق المفيدة، لكنك عمومًا ولست بحاجة إلى الوصول إلى معظمها. هناك طريقتان مهمتان:
getInputStream(String assetPath)
يوفر InputStream لقراءة ملف داخل ملف ZIP. تشير رسالة الأشكال البيانية يجب أن يكون assetPath هو المسار إلى الملف المطلوب، نسبةً إلى جذر محتويات ملف ZIP.
getAssetFileDescriptor(String assetPath)
يوفر AssetFileDescriptor لملف داخل ZIP. يجب أن يكون assetPath هو المسار إلى الملف المطلوب، نسبةً إلى جذر محتويات ملف ZIP. ويُفيد ذلك في بعض واجهات برمجة تطبيقات Android التي تتطلّب AssetFileDescriptor، مثل بعض واجهات برمجة تطبيقات MediaPlayer.
APEZProvider
معظم التطبيقات لا تحتاج إلى استخدام هذا الصف. تحدِّد هذه الفئة عنصر ContentProvider الذي ينظِّم البيانات من ملفات ZIP في محتوى. Uri لتوفير إمكانية الوصول إلى الملفات في بعض واجهات برمجة تطبيقات Android التي تتوقع وصول Uri إلى ملفات الوسائط. على سبيل المثال، يعد ذلك مفيدًا إذا كنت تريد تشغيل فيديو باستخدام VideoView.setVideoURI()

تخطّي ضغط ZIP لملفات الوسائط

إذا كنت تستخدم ملفات البيانات الموسّعة لتخزين ملفات الوسائط، سيظل ملف ZIP يسمح لك استخدام طلبات تشغيل وسائط Android التي توفّر عناصر تحكّم في المدة أو التعويض (مثل MediaPlayer.setDataSource() SoundPool.load()). من أجل لكي تعمل هذه الطريقة، يجب عدم تنفيذ ضغط إضافي على ملفات الوسائط عند إنشاء ملف ZIP حزم. على سبيل المثال، عند استخدام أداة zip، عليك استخدام -n. خيار لتحديد لاحقات الملفات التي يجب عدم ضغطها:

zip -n .mp4;.ogg main_expansion media_files

القراءة من ملف ZIP

عند استخدام مكتبة APK Expansion Zip Library، تتطلّب قراءة ملف من ملف ZIP عادةً التالي:

Kotlin

// Get a ZipResourceFile representing a merger of both the main and patch files
val expansionFile =
        APKExpansionSupport.getAPKExpansionZipFile(appContext, mainVersion, patchVersion)

// Get an input stream for a known file inside the expansion file ZIPs
expansionFile.getInputStream(pathToFileInsideZip).use {
    ...
}

Java

// Get a ZipResourceFile representing a merger of both the main and patch files
ZipResourceFile expansionFile =
    APKExpansionSupport.getAPKExpansionZipFile(appContext,
        mainVersion, patchVersion);

// Get an input stream for a known file inside the expansion file ZIPs
InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);

يوفر الرمز أعلاه إمكانية الوصول إلى أي ملف موجود في ملف البيانات الموسّعة الرئيسي أو تصحيح ملف بيانات موسّعة، عن طريق قراءة جميع الملفات من كلا الملفين من خريطة مدمجة. ما عليك سوى يلزم توفير طريقة getAPKExpansionFile() هي تطبيقك android.content.Context ورقم الإصدار لكل من ملف البيانات الموسّعة الرئيسي والتصحيح ملف بيانات موسّعة.

إذا كنت تفضّل القراءة من ملف بيانات موسّعة محدّد، يمكنك استخدام الدالة الإنشائية ZipResourceFile مع المسار إلى ملف البيانات الموسّعة المطلوب:

Kotlin

// Get a ZipResourceFile representing a specific expansion file
val expansionFile = ZipResourceFile(filePathToMyZip)

// Get an input stream for a known file inside the expansion file ZIPs
expansionFile.getInputStream(pathToFileInsideZip).use {
    ...
}

Java

// Get a ZipResourceFile representing a specific expansion file
ZipResourceFile expansionFile = new ZipResourceFile(filePathToMyZip);

// Get an input stream for a known file inside the expansion file ZIPs
InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);

لمزيد من المعلومات حول استخدام هذه المكتبة لملفات البيانات الموسّعة، يُرجى الاطّلاع على لفئة SampleDownloaderActivity من التطبيق، والتي تتضمّن رمزًا إضافيًا والتحقق من الملفات التي تم تنزيلها باستخدام CRC. كن حذرًا أنه إذا استخدمت هذا النموذج كأساس إلا أنه يتطلب منك تعريف حجم البايت بالبايت الملفات في مصفوفة xAPKS.

اختبار ملفات البيانات الموسّعة

قبل نشر التطبيق، هناك أمران يجب اختبارهما: قراءة ملفات بيانات موسّعة وتنزيل الملفات.

قراءات ملف الاختبار

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

  1. أنشِئ على جهازك الدليل المناسب في مساحة التخزين المشتركة حيث يمكن سيحفظ Play ملفاتك.

    على سبيل المثال، إذا كان اسم الحزمة هو com.example.android، يجب إنشاء الدليل Android/obb/com.example.android/ في مساحة التخزين المشتركة. (التوصيل بمصدر طاقة جهاز الاختبار إلى الكمبيوتر لتثبيت مساحة التخزين المشتركة وإنشاء وحدة التخزين هذه يدويًا الدليل).

  2. أضِف ملفات البيانات الموسّعة إلى هذا الدليل يدويًا. تأكد من إعادة تسمية ملفاتك إلى أن تتطابق مع تنسيق اسم الملف الذي سيستخدمه Google Play.

    على سبيل المثال، يجب أن يكون ملف البيانات الموسّعة الرئيسي لتطبيق com.example.android هو main.0300110.com.example.android.obb، بغض النظر عن نوع الملف. يمكن أن يكون رمز الإصدار بأي قيمة تريدها. تذكير:

    • يبدأ ملف البيانات الموسّعة الرئيسي دائمًا بـ main ويبدأ ملف التصحيح patch
    • يتطابق اسم الحزمة دائمًا مع اسم حزمة APK التي يتم إرفاق الملف بها Google Play.
  3. الآن بعد أن تم تثبيت ملفات البيانات الموسّعة على الجهاز، يمكنك تثبيت تطبيقك وتشغيله لاختبار ملفات البيانات الموسّعة.

في ما يلي بعض التذكيرات عن التعامل مع ملفات البيانات الموسّعة:

  • عدم حذف أو إعادة تسمية ملفات البيانات الموسّعة .obb (حتى في حال فك ضغط حزمة البيانات إلى موقع مختلف). وسيؤدي ذلك إلى إيقاف Google Play (أو تطبيقك نفسه) تنزيل ملف البيانات الموسّعة بشكل متكرر.
  • عدم حفظ البيانات الأخرى في obb/ الدليل. وإذا كان عليك فك ضغط بعض البيانات، عليك حفظها في الموقع الجغرافي الذي تحدِّده السياسة getExternalFilesDir().

اختبار عمليات تنزيل الملفات

لأنّ تطبيقك يجب أحيانًا أن ينزِّل ملفات البيانات الموسّعة يدويًا عند أول مرة من المهم أن تختبر هذه العملية للتأكد من أن تطبيقك يمكنه الاستعلام بنجاح لعناوين URL، وتنزيل الملفات وحفظها على الجهاز.

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

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

تحديث تطبيقك

إحدى أبرز فوائد استخدام ملفات البيانات الموسّعة على Google Play هي إمكانية تحديث تطبيقك بدون إعادة تنزيل جميع مواد العرض الأصلية. لأنّ Google Play تقديم ملفي بيانات موسّعة لكل ملف APK، ويمكنك استخدام الملف الثاني "كتصحيح" توفّر تحديثات ومواد عرض جديدة وسيؤدي القيام بذلك إلى تجنب إلى إعادة تنزيل ملف البيانات الموسّعة الرئيسي الذي قد يكون كبيرًا ومكلفًا للمستخدمين.

ملف البيانات الموسّعة الاختياري من الناحية الفنية هو نفسه ملف البيانات الموسّعة الرئيسي، وليس أن يجري نظام Android أو Google Play عملية تصحيح فعلية بين توسيع نطاق التصحيح الرئيسي وتوسيع نطاق التصحيح الملفات. يجب أن ينفّذ رمز التطبيق أي رموز تصحيح ضرورية بنفسه.

في حال استخدام ملفات ZIP كملفات بيانات موسّعة، يتم استخدام ملف Zip لتوسيع حِزم APK. المكتبة المضمّنة في حزمة Apk Expansion تتضمن إمكانية دمج على ملف التصحيح يحتوي على ملف البيانات الموسّعة الرئيسي.

ملاحظة: حتى إذا كنت بحاجة إلى إجراء تغييرات على رمز التصحيح فقط فقط، إلا أنه يجب تحديث APK حتى يتمكن Google Play من إجراء تحديث. إذا لم تكن تطلب إجراء تغييرات على الرموز البرمجية في التطبيق، ما عليك سوى تحديث versionCode في البيان.

ما دمت لا تغيّر ملف البيانات الموسّعة الرئيسي المرتبط بحزمة APK في Play Console، لن يتمكّن المستخدمون الذين ثبَّتوا تطبيقك في السابق فقم بتنزيل ملف البيانات الموسّعة الرئيسي. يتلقّى المستخدمون الحاليون حزمة APK المعدّلة والرمز البرمجي الجديد فقط ملف بيانات موسّعة (مع الاحتفاظ بملف البيانات الموسّعة الرئيسي السابق).

في ما يلي بعض المشاكل التي يجب وضعها في الاعتبار في ما يتعلق بالتحديثات على ملفات البيانات الموسّعة:

  • لا يمكن تضمين أكثر من ملفي بيانات موسّعة لتطبيقك في كل مرة. توسع رئيسي واحد وملف توسيع واحد للتصحيح. أثناء تعديل ملف، يحذف Google Play الإصدار السابق (وكذلك يجب تحديث تطبيقك عند إجراء تحديثات يدوية).
  • عند إضافة ملف تصحيح توسيعي، لا يصحح نظام Android التطبيق أو ملف البيانات الموسّعة الرئيسي. يجب تصميم تطبيقك بحيث يتوافق مع بيانات رمز التصحيح. ومع ذلك، تتضمن حزمة Apk Expansion مكتبة لاستخدام ملفات ZIP. كملفات بيانات موسّعة، تدمج البيانات من ملف التصحيح في ملف البيانات الموسّعة الرئيسي يمكنك قراءة كل بيانات ملف البيانات الموسّعة بسهولة.