يتطلب 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.
تبدو عملية التنزيل من مستوى عالٍ كما يلي:
- يختار المستخدم تثبيت تطبيقك من Google Play.
- إذا كان Google Play قادرًا على تنزيل ملفات البيانات الموسّعة (هذا هو الحال في معظم
الأجهزة)، يتم تنزيلها مع APK.
إذا تعذّر على Google Play تنزيل ملفات البيانات الموسّعة، سيتم تنزيل حزمة APK فقط.
- عندما يشغِّل المستخدم تطبيقك، يجب أن يتحقّق التطبيق مما إذا كانت ملفات البيانات الموسّعة متاحة.
سبق أن تم حفظه على الجهاز.
- إذا كانت الإجابة بنعم، يعني ذلك أنّ تطبيقك جاهز للاستخدام.
- إذا لم يكن الأمر كذلك، يجب أن ينزِّل تطبيقك ملفات البيانات الموسّعة عبر HTTP من Google Play. تطبيقك إرسال طلب إلى برنامج Google Play باستخدام خدمة ترخيص التطبيقات من Google Play، بالاسم وحجم الملف وعنوان URL لكل ملف بيانات موسّعة. باستخدام هذه المعلومات، يمكنك فنزِّل الملفات واحفظها في موقع التخزين المناسب.
تنبيه: من الضروري تضمين الرمز اللازم تنزيل ملفات البيانات الموسّعة من Google Play في حال لم تكن هذه الملفات متوفّرة في الجهاز عند تشغيل تطبيقك. وقد وفّرنا لك مكتبة تضم ما سبق وذكرنا في القسم التالي حول تنزيل ملفات البيانات الموسّعة. يعمل على تبسيط هذه العملية بشكل كبير وإجراء التنزيل من خدمة بأقل قدر من التعليمات البرمجية منك.
قائمة التحقق من التطوير
في ما يلي ملخّص للمهام التي يجب تنفيذها لاستخدام ملفات البيانات الموسّعة مع التطبيق:
- عليك أولاً تحديد ما إذا كان حجم تنزيل التطبيق المضغوط يجب أن يتجاوز 100 ميغابايت. المساحة ثمينة لذا يجب أن يبقى إجمالي حجم التنزيل صغيرًا قدر الإمكان. إذا كان تطبيقك يستخدم أكثر من 100 ميغابايت لتوفير إصدارات متعددة من أصول الرسومات لشاشات متعددة لذا يمكنك نشر ملفات APK متعددة، حيث يمكن استخدام كل ملف APK بدلاً من ذلك. يحتوي فقط على الأصول المطلوبة للشاشات التي يستهدفها. للحصول على أفضل النتائج عند النشر على Google Play، حمِّل مجموعة حزمات تطبيق Android التي تتضمّن جميع الموارد والرموز التي تم تجميعها لتطبيقك، ولكنها تؤخّر إنشاء ملفات APK وتسجيل الدخول إلى Google اللعب.
- تحديد موارد التطبيقات التي تريد فصلها عن حزمة APK وتجميعها في
ملف لاستخدامه كملف بيانات موسّعة رئيسي.
وفي العادة، يجب ألا تستخدم سوى ملف البيانات الموسّعة الثاني عند إجراء تحديثات ملف البيانات الموسّعة الرئيسي. ومع ذلك، إذا تجاوزت مواردك الحد الأقصى البالغ 2 غيغابايت لنظام التشغيل يمكنك استخدام ملف التصحيح لباقي مواد العرض.
- طوِّر تطبيقك بحيث يستخدم الموارد من ملفات البيانات الموسّعة في
موقع مساحة التخزين المشتركة للجهاز.
وتذكَّر أنه لا يجب حذف ملفات البيانات الموسّعة أو نقلها أو إعادة تسميتها.
إذا لم يكن تطبيقك يتطلب تنسيقًا معيّنًا، ننصحك بإنشاء ملفات ZIP ملفات البيانات الموسّعة، ثم اقرأها باستخدام ملف ضغط APK المضغوط المكتبة.
- إضافة منطق إلى النشاط الرئيسي لتطبيقك الذي يتحقّق مما إذا كانت ملفات البيانات الموسّعة
موجودة على الجهاز عند بدء التشغيل. إذا لم تكن الملفات على الجهاز، استخدِم خدمة ترخيص التطبيقات في Google Play لطلب عناوين URL
لملفات البيانات الموسّعة، ثم تنزيلها وحفظها.
لتقليل مقدار التعليمات البرمجية بشكل كبير، يجب عليك كتابة وضمان تجربة مستخدم جيدة أثناء التنزيل، ننصحك باستخدام أداة التنزيل "المكتبة" لتنفيذ سلوك التنزيل.
فإذا أنشأت خدمة تنزيل خاصة بك بدلاً من استخدام المكتبة، فاعلم أنك يجب ألا يغير اسم ملفات البيانات الموسّعة وأن تحفظها في المجلد مكان التخزين.
بعد الانتهاء من تطوير التطبيق، اتّبِع دليل اختبار. ملفات البيانات الموسّعة
القواعد والقيود
يمكنك إضافة ملفات البيانات الموسّعة الخاصة بحزمة APK ميزة متاحة عند تحميل تطبيقك باستخدام Play Console: عند تحميل تطبيقك للمرة الأولى أو تحديث تطبيق يستخدم ملفات البيانات الموسّعة، يجب أن تكون على دراية بالقواعد والقيود التالية:
- يجب ألا يزيد حجم كل ملف بيانات موسّعة عن 2 غيغابايت.
- لتنزيل ملفات البيانات الموسّعة من Google Play، يجب أن يكون لدى المستخدم احصل على تطبيقك من Google Play. لن يتمكن Google Play من تقديم عناوين URL لملفات البيانات الموسّعة إذا تم تثبيت التطبيق بطريقة أخرى
- عنوان URL الذي تستخدمه Google Play عند إجراء عملية التنزيل من داخل التطبيق لكل ملف تكون فريدة لكل عملية تنزيل، وتنتهي صلاحية كل ملف بعد فترة وجيزة من منحه. إلى تطبيقك.
- في حال تحديث تطبيقك باستخدام حزمة APK جديدة أو تحميل عدة حِزم APK لها فيمكنك تحديد ملفات البيانات الموسّعة التي حمّلتها إلى حزمة APK سابقة. عدم تغيير اسم ملف البيانات الموسّعة، فهو يحتفظ بالإصدار الذي تم استلامه بواسطة حزمة APK الذي كان الملف مرتبطًا به في الأصل.
- إذا كنت تستخدم ملفات البيانات الموسّعة مع حِزم APK متعددة من أجل
تقديم ملفات بيانات موسّعة لأجهزة مختلفة، ولكن يجب تحميل حِزم APK منفصلة.
لكل جهاز من أجل توفير سمة
versionCode
فريدة وأعلِن عن فلاتر مختلفة في لكل ملف APK. - لا يمكنك تحديث تطبيقك من خلال تغيير ملفات البيانات الموسّعة.
فقط، عليك تحميل حزمة APK جديدة لتحديث تطبيقك. في حال كانت التغييرات فقط
بالنسبة إلى مواد العرض الواردة في ملفات البيانات الموسّعة، يمكنك تحديث حزمة APK ببساطة عن طريق تغيير الرمز
versionCode
( وربما أيضًاversionName
). - عدم حفظ البيانات الأخرى في
obb/
الدليل. وإذا كان عليك فك ضغط بعض البيانات، عليك حفظها في الموقع الجغرافي الذي تحدِّده السياسةgetExternalFilesDir()
. - لا تحذف ملف البيانات الموسّعة
.obb
أو أعِد تسميته (ما لم تكن إجراء تحديث). سيؤدي إجراء ذلك إلى تكرّر Google Play (أو تطبيقك نفسه) فقم بتنزيل ملف البيانات الموسّعة. - عند تعديل ملف بيانات موسّعة يدويًا، يجب حذف ملف البيانات الموسّعة السابق.
تنزيل ملفات البيانات الموسّعة
في معظم الحالات، ينزِّل Google Play ملفات البيانات الموسّعة ويحفظها على الجهاز نفسه. وقت تثبيت حزمة APK أو تحديثها. بهذه الطريقة، تتوفر ملفات البيانات الموسّعة عندما تطبيقك لأول مرة. ومع ذلك، في بعض الحالات، على تطبيقك تنزيل ملف البيانات الموسّعة نفسه عن طريق طلبها من عنوان URL يتم توفيره لك في رد من خدمة ترخيص التطبيقات في Google Play.
المنطق الأساسي الذي تحتاج إليه لتنزيل ملفات البيانات الموسّعة هو ما يلي:
- عند بدء تشغيل تطبيقك، ابحث عن ملفات البيانات الموسّعة في موقع مساحة التخزين المشتركة (في قسم
الدليل
Android/obb/<package-name>/
).- إذا كانت ملفات البيانات الموسّعة متاحة، يعني ذلك أنّ تطبيقك أصبح جاهزًا ويمكن استخدامه لمواصلة العمل.
- إذا لم تكن ملفات البيانات الموسّعة متاحة:
- نفِّذ طلب باستخدام ترخيص التطبيق في Google Play للحصول على أسماء ملفات توسيع التطبيق وأحجامها وعناوين URL الخاصة بها.
- استخدِم عناوين 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
إنشاء وحدة مكتبة جديدة لكل من "مكتبة التحقّق من التراخيص" و"أداة التنزيل" المكتبة. لكل مكتبة:
- حدد ملف > جديد > وحدة جديدة:
- في النافذة إنشاء وحدة جديدة، اختَر مكتبة Android. ثم انقر على التالي.
- حدِّد اسم التطبيق أو المكتبة، مثل "مكتبة تراخيص Google Play" و"مكتبة أداة تنزيل Google Play"، اختَر الحد الأدنى لمستوى حزمة تطوير البرامج (SDK)، ثم اختَر إنهاء
- حدد ملف > بنية المشروع:
- انقر على علامة التبويب الخصائص وفي المكتبة.
المستودع، أدخِل المكتبة من الدليل
<sdk>/extras/google/
(play_licensing/
لمكتبة إثبات الملكية أوplay_apk_expansion/downloader_library/
لمكتبة أدوات التنزيل). - اختَر حسنًا لإنشاء الوحدة الجديدة.
ملاحظة: تعتمد مكتبة "أداة التنزيل" على الترخيص مكتبة إثبات الملكية تأكَّد من إضافة الترخيص. مكتبة إثبات الملكية إلى مواقع مشروع مكتبة التنزيل.
أو يمكنك من سطر الأوامر تحديث مشروعك لتضمين المكتبات:
- تغيير الأدلة إلى الدليل
<sdk>/tools/
- نفِّذ
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>
بدء التنزيل
أن يكون النشاط الرئيسي في تطبيقك (الذي يبدأه رمز مشغّل التطبيقات) هو التحقق مما إذا كانت ملفات البيانات الموسّعة موجودة بالفعل على الجهاز وبدء بالتنزيل إذا لم تكن كذلك.
يتطلب بدء التنزيل باستخدام مكتبة أداة التنزيل ما يلي: الإجراءات:
- تحقّق مما إذا تم تنزيل الملفات.
تحتوي "مكتبة أدوات التنزيل" على بعض واجهات برمجة التطبيقات في الفئة
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، حينئذٍ يجب أن يبدأ التطبيق عملية التنزيل.
- ابدأ التنزيل باستدعاء الطريقة الثابتة
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 }
- عندما تعرض الطريقة
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، عليك تنفيذ ما يلي: اختبار قدرة تطبيقك على قراءة الملفات من مساحة التخزين المشتركة. كل ما عليك فعله هي إضافة الملفات إلى الموقع المناسب على مساحة التخزين المشتركة على الجهاز وتشغيل التطبيق:
- أنشِئ على جهازك الدليل المناسب في مساحة التخزين المشتركة حيث يمكن
سيحفظ Play ملفاتك.
على سبيل المثال، إذا كان اسم الحزمة هو
com.example.android
، يجب إنشاء الدليلAndroid/obb/com.example.android/
في مساحة التخزين المشتركة. (التوصيل بمصدر طاقة جهاز الاختبار إلى الكمبيوتر لتثبيت مساحة التخزين المشتركة وإنشاء وحدة التخزين هذه يدويًا الدليل). - أضِف ملفات البيانات الموسّعة إلى هذا الدليل يدويًا. تأكد من إعادة تسمية ملفاتك إلى
أن تتطابق مع تنسيق اسم الملف الذي سيستخدمه Google Play.
على سبيل المثال، يجب أن يكون ملف البيانات الموسّعة الرئيسي لتطبيق
com.example.android
هوmain.0300110.com.example.android.obb
، بغض النظر عن نوع الملف. يمكن أن يكون رمز الإصدار بأي قيمة تريدها. تذكير:- يبدأ ملف البيانات الموسّعة الرئيسي دائمًا بـ
main
ويبدأ ملف التصحيحpatch
- يتطابق اسم الحزمة دائمًا مع اسم حزمة APK التي يتم إرفاق الملف بها Google Play.
- يبدأ ملف البيانات الموسّعة الرئيسي دائمًا بـ
- الآن بعد أن تم تثبيت ملفات البيانات الموسّعة على الجهاز، يمكنك تثبيت تطبيقك وتشغيله لاختبار ملفات البيانات الموسّعة.
في ما يلي بعض التذكيرات عن التعامل مع ملفات البيانات الموسّعة:
- عدم حذف أو إعادة تسمية ملفات البيانات الموسّعة
.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. كملفات بيانات موسّعة، تدمج البيانات من ملف التصحيح في ملف البيانات الموسّعة الرئيسي يمكنك قراءة كل بيانات ملف البيانات الموسّعة بسهولة.