Google Play ملزم میکند که APK فشردهشدهای که کاربران بارگیری میکنند بیشتر از ۱۰۰ مگابایت نباشد. برای اکثر برنامهها، این فضا برای همه کدها و داراییهای برنامه کافی است. اما برخیاز برنامهها برای گرافیکهای با کیفیت بالا، فایلهای رسانهای، یا دیگر داراییهای بزرگ به فضای بیشتری نیاز دارند. قبلاً اگر حجم بارگیری فشردهشده برنامهتان از ۱۰۰ مگابایت بیشتر میشد، باید منابع اضافی را خودتان میزبانی و بارگیری میکردید تا وقتی کاربر برنامه را باز میکند، این منابع دردسترس باشند. میزبانی و ارائه فایلهای اضافی میتواند پرهزینه باشد و تجربه کاربری اغلب ایدهآل نیست. برای آسانتر کردن این فرایند برای شما و لذتبخشتر کردن آن برای کاربران، Google Play به شما اجازه میدهد دو فایل توسعه بزرگ را که مکمل APK شما هستند پیوست کنید.
Google Play فایلهای توسعه را برای برنامه شما میزبانی میکند و آنها را بدون هیچ هزینهای برای شما به دستگاه ارائه میدهد. فایلهای توسعه در مکان فضای ذخیرهسازی مشترک دستگاه (کارت SD یا پارتیشن قابلنصب USB؛ که بهعنوان فضای ذخیرهسازی «خارجی» نیز شناخته میشود) ذخیره میشوند، جایی که برنامهتان میتواند به آنها دسترسی داشته باشد. در اکثر دستگاهها، Google Play فایل(های) توسعه را همزمان با بارگیری APK بارگیری میکند، بنابراین وقتی کاربر برای اولینبار برنامه را باز میکند، برنامه همه چیزهایی را که نیاز دارد دراختیار دارد. بااینحال، در برخی موارد، برنامهتان باید فایلها را از Google Play بارگیری کند وقتی برنامهتان شروع میشود.
اگر میخواهید از فایلهای توسعه استفاده نکنید و اندازه بارگیری فشردهشده برنامهتان بزرگتر از ۱۰۰ مگابایت است، باید برنامهتان را بااستفاده از Android App Bundles بارگذاری کنید که امکان بارگیری فشردهشده تا ۵۰۰ مگابایت را فراهم میکند. علاوهبراین، چون استفاده از بستههای برنامه، تولید و امضای APK را به Google Play واگذار میکند، کاربران APKهای بهینهشده را فقط با کد و منابعی که برای اجرای برنامهتان نیاز دارند بارگیری میکنند. لازم نیست چندین APK یا فایل توسعه بسازید، امضا کنید، و مدیریت کنید و کاربران بارگیریهای کوچکتر و بهینهتری دریافت میکنند.
نمای کلی
هر بار که APK را بااستفاده از «کنسول Google Play» بارگذاری میکنید، این گزینه را دارید که یک یا دو فایل تکمیلی به APK اضافه کنید. هر فایل میتواند تا ۲ گیگابایت باشد و میتواند هر قالبی که انتخاب میکنید باشد، اما توصیه میکنیم از فایل فشرده استفاده کنید تا پهنای باند را درطول بارگیری حفظ کنید. ازنظر مفهومی، هر فایل توسعه نقش متفاوتی ایفا میکند:
- فایل توسعه اصلی، فایل توسعه اولیه برای منابع اضافی موردنیاز برنامهتان است.
- فایل توسعه وصله اختیاری است و برای بهروزرسانیهای کوچک در فایل توسعه اصلی درنظر گرفته شده است.
درحالیکه میتوانید از دو فایل توسعه به هر روشی که میخواهید استفاده کنید، توصیه میکنیم که فایل توسعه اصلی داراییهای اصلی را ارائه دهد و بهندرت، اگر اصلاً، بهروز شود؛ فایل توسعه وصله باید کوچکتر باشد و بهعنوان «حامل وصله» عمل کند و با هر انتشار اصلی یا درصورت لزوم بهروز شود.
بااینحال، حتی اگر بهروزرسانی برنامه شما فقط به یک فایل توسعه وصله جدید نیاز داشته باشد، همچنان باید
یک APK جدید با versionCode بهروزشده در مانیفست بارگذاری کنید. («کنسول Play» به شما اجازه نمیدهد فایل توسعه را در APK موجود بارگذاری کنید.)
توجه: فایل توسعه وصله ازنظر معنایی مشابه فایل توسعه اصلی است—میتوانید از هر فایل به هر روشی که میخواهید استفاده کنید.
قالب نام فایل
هر فایل توسعهای که بارگذاری میکنید میتواند هر قالبی که انتخاب میکنید (ZIP، PDF، MP4، و غیره) داشته باشد. همچنین میتوانید از ابزار JOBB برای کپسولهسازی و رمزگذاری مجموعهای از فایلهای منبع و وصلههای بعدی برای آن مجموعه استفاده کنید. صرفنظر از نوع فایل، Google Play آنها را بهعنوان حبابهای دودویی مات درنظر میگیرد و نام فایلها را بااستفاده از طرح زیر تغییر میدهد:
[main|patch].<expansion-version>.<package-name>.obb
این طرح سه مؤلفه دارد:
mainیاpatch- مشخص میکند که فایل، فایل توسعه اصلی است یا وصله. برای هر APK فقط یک فایل اصلی و یک فایل وصله میتواند وجود داشته باشد.
<expansion-version>- این عدد صحیحی است که با کد نسخه APK که افزونه
ابتدا با آن مرتبط شده است مطابقت دارد (با مقدار
android:versionCodeبرنامه مطابقت دارد).«اولین» مورد تأکید قرار گرفته است زیرا اگرچه «کنسول Play» به شما اجازه میدهد از فایل تکمیلی بارگذاریشده با فایل APK جدید مجدداً استفاده کنید، نام فایل تکمیلی تغییر نمیکند— نسخه اعمالشده بر آن را هنگام اولین بارگذاری فایل حفظ میکند.
<package-name>- نام بسته برنامه شما به سبک Java.
برای مثال، فرض کنید نسخه APK شما ۳۱۴۱۵۹ و نام بسته شما 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 (سطح API 19)، برنامهها میتوانند فایلهای توسعه OBB را بدون اجازه فضای ذخیرهسازی خارجی
بخوانند. بااینحال، برخیاز پیادهسازیهای Android 6.0 (سطح میانای برنامهسازی کاربردی ۲۳) و نسخههای جدیدتر همچنان به
اجازه نیاز دارند، بنابراین باید اجازه
READ_EXTERNAL_STORAGE را در مانیفست برنامه اعلام کنید و در زمان اجرا
بهصورت زیر درخواست اجازه کنید:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
برای Android نسخه ۶ و بالاتر، اجازه فضای ذخیرهسازی خارجی باید در زمان اجرا درخواست شود. بااینحال، برخیاز پیادهسازیهای Android برای خواندن فایلهای OBB به اجازه نیاز ندارند. تکهکد زیر نشان میدهد که چگونه قبلاز درخواست اجازه فضای ذخیرهسازی خارجی، دسترسی خواندن را بررسی کنید:
کاتلین
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() }
جاوا
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() ذخیره کنید. بااینحال،
درصورت امکان، بهتر است از قالب فایل گسترشی استفاده کنید که به شما امکان میدهد بهجای اینکه لازم باشد دادهها را از حالت فشرده خارج کنید، مستقیماً از
فایل بخوانید. برای مثال، ما یک پروژه کتابخانه بهنام کتابخانه ZIP فایلهای تکمیلی APK ارائه کردهایم که دادههای شما را مستقیماً از فایل ZIP میخواند.
احتیاط: برخلاف فایلهای APK، هر فایلی که در فضای ذخیرهسازی مشترک ذخیره شده باشد میتواند توسط کاربر و برنامههای دیگر خوانده شود.
نکته: اگر فایلهای رسانهای را در یک فایل ZIP بستهبندی میکنید، میتوانید از تماسهای بازپخش رسانه روی فایلها با کنترلهای آفست و طول (مانند MediaPlayer.setDataSource() و SoundPool.load()) بدون نیاز به باز کردن فایل ZIP استفاده کنید. برای اینکه این کار انجام شود، نباید هنگام ایجاد بستههای ZIP، فشردهسازی اضافی روی فایلهای رسانه انجام دهید. برای مثال، هنگام استفاده از ابزار zip،
باید از گزینه -n برای مشخص کردن پسوندهای فایلی که نباید
فشرده شوند استفاده کنید:
zip -n .mp4;.ogg main_expansion media_files
فرایند بارگیری
در بیشتر مواقع، Google Play فایلهای توسعه را همزمان با بارگیری APK در دستگاه، بارگیری و ذخیره میکند. بااینحال، در برخی موارد Google Play نمیتواند فایلهای توسعه را بارگیری کند یا ممکن است کاربر فایلهای توسعهای را که قبلاً بارگیری شدهاند حذف کرده باشد. برای مدیریت این شرایط، برنامهتان باید بتواند فایلها را خودش هنگام شروع فعالیت اصلی بااستفاده از نشانی وب ارائهشده توسط Google Play بارگیری کند.
فرایند بارگیری از سطح بالا به این شکل است:
- کاربر انتخاب میکند که برنامهتان را از Google Play نصب کند.
- اگر Google Play بتواند فایلهای توسعه را بارگیری کند (که برای اکثر دستگاهها اینگونه است)، آنها را همراه با APK بارگیری میکند.
اگر Google Play نتواند فایلهای توسعه را بارگیری کند، فقط APK را بارگیری میکند.
- وقتی کاربر برنامهتان را راهاندازی میکند، برنامهتان باید بررسی کند که آیا فایلهای توسعه ازقبل در دستگاه ذخیره شدهاند یا نه.
- اگر بله، برنامهتان آماده است.
- اگر نه، برنامهتان باید فایلهای توسعه را ازطریق HTTP از Google Play بارگیری کند. برنامه شما باید بااستفاده از سرویس صدور پروانه برنامه Google Play، درخواستی به مشتری Google Play ارسال کند که با نام، اندازه فایل، و نشانی وب برای هر فایل توسعه پاسخ میدهد. سپس با این اطلاعات، فایلها را بارگیری میکنید و آنها را در مکان ذخیرهسازی مناسب ذخیره میکنید.
احتیاط: بسیار مهم است که کد لازم برای بارگیری فایلهای توسعه از Google Play را درصورتیکه فایلها ازقبل در دستگاه موجود نباشند، هنگام شروع برنامه اضافه کنید. همانطور که در بخش زیر درباره بارگیری فایلهای توسعه بحث شد، کتابخانهای را برای شما دردسترس قرار دادهایم که این فرایند را بسیار ساده میکند و بارگیری را از سرویسی با حداقل مقدار کد ازجانب شما انجام میدهد.
بازبینه توسعه
در اینجا خلاصهای از کارهایی که باید برای استفاده از فایلهای توسعه با برنامهتان انجام دهید آورده شده است:
- ابتدا تعیین کنید که آیا اندازه بارگیری فشرده برنامه شما باید بیشتر از ۱۰۰ مگابایت باشد یا نه. فضا ارزشمند است و باید اندازه کل بارگیری را تا حد امکان کوچک نگه دارید. اگر برنامهتان برای ارائه نسخههای متعدد از داراییهای گرافیکیتان برای تراکمهای متعدد صفحهنمایش از بیشاز ۱۰۰ مگابایت استفاده میکند، بهجای آن، چند APK منتشر کنید که هر APK فقط حاوی داراییهای موردنیاز برای صفحهنمایشهایی باشد که هدف قرار میدهد. برای دریافت بهترین نتایج هنگام انتشار در Google Play، یک بسته ترکیبی برنامه Android بارگذاری کنید که شامل همه کدها و منابع کامپایلشده برنامهتان است، اما تولید و امضای APK را به Google Play واگذار میکند.
- تعیین کنید کدام منابع برنامه از APK شما جدا شود و آنها را در یک فایل بستهبندی کنید تا بهعنوان فایل توسعه اصلی استفاده شود.
معمولاً فقط هنگام بهروزرسانی فایل توسعه اصلی باید از فایل توسعه وصله دوم استفاده کنید. بااینحال، اگر منابع شما از حد مجاز ۲ گیگابایت برای فایل توسعه اصلی فراتر رفت، میتوانید از فایل وصله برای بقیه داراییهایتان استفاده کنید.
- برنامهتان را طوری توسعه دهید که از منابع فایلهای توسعه در مکان فضای ذخیرهسازی مشترک دستگاه استفاده کند.
بهخاطر داشته باشید که نباید فایلهای توسعه را حذف کنید، جابهجا کنید، یا نام آنها را تغییر دهید.
اگر برنامه شما به قالب خاصی نیاز ندارد، پیشنهاد میکنیم فایلهای ZIP را برای فایلهای توسعه خود ایجاد کنید، سپس آنها را بااستفاده از کتابخانه Zip توسعه APK بخوانید.
- منطقی به فعالیت اصلی برنامهتان اضافه کنید که بررسی کند آیا فایلهای توسعه
هنگام راهاندازی در دستگاه وجود دارند یا نه. اگر فایلها در دستگاه نیستند، از سرویس صدور پروانه برنامه Google Play برای درخواست نشانیهای وب
فایلهای توسعه استفاده کنید، سپس آنها را بارگیری و ذخیره کنید.
برای کاهش قابلتوجه مقدار کدی که باید بنویسید و اطمینان از تجربه کاربری خوب درطول بارگیری، توصیه میکنیم از کتابخانه بارگیری برای پیادهسازی رفتار بارگیری خود استفاده کنید.
اگر بهجای استفاده از کتابخانه، سرویس بارگیری خودتان را میسازید، توجه داشته باشید که نباید نام فایلهای توسعه را تغییر دهید و باید آنها را در مکان ذخیرهسازی مناسب ذخیره کنید.
پساز تکمیل توسعه برنامه، راهنمای آزمایش کردن فایلهای توسعه را دنبال کنید.
قوانین و محدودیتها
افزودن فایلهای توسعه APK ویژگیای است که هنگام بارگذاری برنامه بااستفاده از «کنسول Play» دردسترس است. هنگام بارگذاری برنامه برای اولینبار یا بهروزرسانی برنامهای که از فایلهای توسعه استفاده میکند، باید از قوانین و محدودیتهای زیر آگاه باشید:
- هر فایل توسعه نباید بیشتر از ۲ گیگابایت باشد.
- برای بارگیری فایلهای توسعه از Google Play، کاربر باید برنامه شما را از Google Play دریافت کرده باشد. اگر برنامه ازطریق دیگری نصب شده باشد، Google Play نشانیهای وب فایلهای توسعه را ارائه نخواهد کرد.
- هنگام انجام بارگیری از داخل برنامه، نشانی وبی که Google Play برای هر فایل ارائه میدهد برای هر بارگیری منحصربهفرد است و هرکدام مدت کوتاهی پساز ارائه به برنامه منقضی میشود.
- اگر برنامهتان را با APK جدیدی بهروز کنید یا چندین APK برای همان برنامه بارگذاری کنید، میتوانید فایلهای توسعهای را که برای APK قبلی بارگذاری کردهاید انتخاب کنید. نام فایل توسعه تغییر نمیکند—نسخه دریافتی APK را که فایل در ابتدا با آن مرتبط بوده است حفظ میکند.
- اگر از فایلهای توسعه در ترکیب با چند APK استفاده میکنید تا
فایلهای توسعه متفاوتی برای دستگاههای مختلف ارائه دهید، همچنان باید APKهای جداگانهای
برای هر دستگاه بارگذاری کنید تا مقدار
versionCodeمنحصربهفردی ارائه دهید و فیلترهای متفاوتی برای هر APK اعلام کنید. - نمیتوانید فقط با تغییر دادن فایلهای توسعه، بهروزرسانی برای برنامهتان صادر کنید—باید فایل APK جدیدی بارگذاری کنید تا برنامهتان بهروز شود. اگر تغییرات شما فقط مربوط به داراییهای موجود در فایلهای توسعه است، میتوانید فایل APK خود را بهسادگی با تغییر دادن
versionCode(و شاید همچنینversionName) بهروز کنید. - دادههای دیگر را در
obb/فهرست راهنما ذخیره نکنید. اگر باید برخیاز دادهها را از حالت فشرده خارج کنید، آنها را در مکان مشخصشده توسطgetExternalFilesDir()ذخیره کنید. - فایل توسعه
.obbرا حذف نکنید یا نام آن را تغییر ندهید (مگر اینکه درحال انجام بهروزرسانی باشید). این کار باعث میشود Google Play (یا خود برنامهتان) بهطور مکرر فایل توسعه را بارگیری کند. - هنگام بهروزرسانی دستی فایل توسعه، باید فایل توسعه قبلی را حذف کنید.
درحال بارگیری فایلهای توسعه
در بیشتر موارد، Google Play فایلهای افزونه شما را همزمان با نصب یا بهروزرسانی APK در دستگاه بارگیری و ذخیره میکند. بهاینترتیب، فایلهای توسعه زمانیکه برنامهتان برای اولینبار راهاندازی میشود دردسترس هستند. بااینحال، در برخی موارد برنامهتان باید خودش فایلهای تکمیلی را با درخواست کردن آنها از نشانی وبی که در پاسخ از سرویس صدور پروانه برنامه Google Play به شما ارائه شده است بارگیری کند.
منطق اصلی که برای بارگیری فایلهای توسعه نیاز دارید به شرح زیر است:
- وقتی برنامهتان شروع میشود، فایلهای توسعه را در مکان فضای ذخیرهسازی مشترک (در دایرکتوری
Android/obb/<package-name>/) جستجو کنید.- اگر فایلهای توسعه آنجا باشند، همهچیز آماده است و برنامهتان میتواند ادامه دهد.
- اگر فایلهای توسعه آنجا نیستند:
- بااستفاده از صدور پروانه برنامه Google Play درخواستی ارسال کنید تا نام، اندازه، و نشانی وب فایلهای توسعه برنامهتان را دریافت کنید.
- از نشانیهای وب ارائهشده توسط Google Play برای بارگیری فایلهای توسعه و ذخیره
فایلهای توسعه استفاده کنید. باید فایلها را در مکان فضای ذخیرهسازی مشترک (
Android/obb/<package-name>/) ذخیره کنید و دقیقاً از همان نام فایلی که در پاسخ Google Play ارائه شده است استفاده کنید.توجه: نشانی وبی که Google Play برای فایلهای توسعه شما ارائه میدهد برای هر بارگیری منحصربهفرد است و هرکدام مدت کوتاهی پساز ارائه به برنامه شما منقضی میشود.
اگر برنامهتان رایگان است (برنامه پولی نیست)، احتمالاً از سرویس صدور پروانه برنامه استفاده نکردهاید. این میانای برنامهسازی کاربردی در درجه اول برای شما طراحی شده است تا خطمشیهای صدور پروانه را برای برنامهتان اجرا کنید و مطمئن شوید که کاربر حق استفاده از برنامهتان را دارد (بهطور قانونی هزینه آن را در Google Play پرداخت کرده است). برای تسهیل عملکرد فایل توسعه، سرویس صدور پروانه بهبود یافته است تا پاسخی به برنامه شما ارائه دهد که شامل نشانی وب فایلهای توسعه برنامه شما است که در Google Play میزبانی میشوند. بنابراین، حتی اگر برنامهتان برای کاربران رایگان است، برای استفاده از فایلهای توسعه APK باید «کتابخانه درستیسنجی پروانه» (LVL) را اضافه کنید. البته اگر برنامهتان رایگان است، نیازی به اجرای درستیسنجی پروانه ندارید—فقط به کتابخانه نیاز دارید تا درخواستی را اجرا کند که نشانی وب فایلهای توسعهتان را برمیگرداند.
توجه: چه برنامهتان رایگان باشد چه نباشد، Google Play نشانیهای وب فایل توسعه را فقط درصورتی برمیگرداند که کاربر برنامهتان را از Google Play دریافت کرده باشد.
علاوهبر LVL، به مجموعهای از کدها نیاز دارید که فایلهای تکمیلی را ازطریق اتصال HTTP بارگیری کند و آنها را در مکان مناسب در فضای ذخیرهسازی مشترک دستگاه ذخیره کند. هنگام ساختن این رویه در برنامهتان، چند مشکل وجود دارد که باید آنها را درنظر بگیرید:
- ممکن است دستگاه فضای کافی برای فایلهای توسعه نداشته باشد، بنابراین باید قبلاز شروع بارگیری بررسی کنید و اگر فضای کافی وجود ندارد به کاربر هشدار دهید.
- بارگیری فایل باید در سرویس پسزمینهای انجام شود تا از مسدود شدن تعامل کاربر جلوگیری شود و کاربر بتواند درحین تکمیل بارگیری، از برنامه شما خارج شود.
- ممکن است خطاهای مختلفی درطول درخواست و بارگیری رخ دهد که باید آنها را بهدرستی مدیریت کنید.
- اتصال شبکه میتواند درطول بارگیری تغییر کند، بنابراین باید چنین تغییراتی را مدیریت کنید و درصورت قطع شدن، بارگیری را درصورت امکان ازسر بگیرید.
- وقتی بارگیری در پسزمینه انجام میشود، باید اعلانی ارائه دهید که پیشرفت بارگیری را نشان دهد، وقتی بارگیری تمام شد به کاربر اطلاع دهد، و وقتی انتخاب شد کاربر را به برنامهتان برگرداند.
برای ساده کردن این کار برای شما، کتابخانه بارگیری را ساختهایم که نشانیهای وب فایل توسعه را ازطریق سرویس صدور پروانه درخواست میکند، فایلهای توسعه را بارگیری میکند، همه کارهای فهرستشده در بالا را انجام میدهد، و حتی به فعالیت شما اجازه میدهد بارگیری را موقتاً متوقف و ازسر بگیرد. با افزودن «کتابخانه بارگیری» و چند قلاب کد به برنامهتان، تقریباً همه کارهای لازم برای بارگیری فایلهای توسعه ازقبل برای شما کدگذاری شده است. بنابراین، برای ارائه بهترین تجربه کاربری با حداقل تلاش ازجانب شما، توصیه میکنیم از «کتابخانه بارگیری» برای بارگیری فایلهای توسعه استفاده کنید. اطلاعات بخشهای زیر نحوه ادغام کردن کتابخانه را در برنامهتان توضیح میدهد.
اگر ترجیح میدهید راهکار خودتان را برای بارگیری فایلهای توسعه بااستفاده از نشانیهای وب Google Play توسعه دهید، باید از سند صدور پروانه برنامه پیروی کنید تا درخواست پروانه را انجام دهید، سپس نام، اندازه، و نشانی وب فایل توسعه را از موارد اضافی پاسخ بازیابی کنید. باید از کلاس APKExpansionPolicy (موجود در «کتابخانه درستیسنجی پروانه») بهعنوان خطمشی صدور پروانه استفاده کنید، که نام، اندازه، و نشانی وب فایلهای توسعه را از سرویس صدور پروانه دریافت میکند.
درباره کتابخانه بارگیری
برای استفاده از فایلهای توسعه APK با برنامهتان و ارائه بهترین تجربه کاربری با حداقل تلاش ازجانب شما، توصیه میکنیم از «کتابخانه بارگیری» که در بسته «کتابخانه توسعه APK» در Google Play گنجانده شده است استفاده کنید. این کتابخانه فایلهای توسعه شما را در یک سرویس پسزمینه بارگیری میکند، یک اعلان کاربر با وضعیت بارگیری نشان میدهد، قطع اتصال شبکه را مدیریت میکند، بارگیری را درصورت امکان ازسر میگیرد، و غیره.
برای پیادهسازی بارگیریهای فایل توسعه بااستفاده از «کتابخانه بارگیری»، تنها کاری که باید انجام دهید این است:
- یک زیرکلاس ویژه
Serviceو زیرکلاسBroadcastReceiverرا گسترش دهید که هرکدام فقط به چند خط کد از شما نیاز دارند. - Add some logic to your main activity that checks whether the expansion files have already been downloaded and, if not, invokes the download process and displays a progress UI.
- میانای بازخوانی را با چند روش در فعالیت اصلیتان پیادهسازی کنید که بهروزرسانیهای مربوط به پیشرفت بارگیری را دریافت میکند.
بخشهای زیر نحوه راهاندازی برنامه بااستفاده از «کتابخانه بارگیری» را توضیح میدهد.
آمادهسازی برای استفاده از «کتابخانه بارگیریکننده»
برای استفاده از «کتابخانه بارگیری»، باید دو بسته را از «مدیر SDK» بارگیری کنید و کتابخانههای مناسب را به برنامهتان اضافه کنید.
ابتدا مدیر SDK Android (ابزارها > مدیر SDK) را باز کنید و در بخش ظاهر و رفتار > تنظیمات سیستم > SDK Android، برگه ابزارهای SDK را برای انتخاب و بارگیری انتخاب کنید:
- بسته کتابخانه صدور پروانه Google Play
- بسته کتابخانه توسعه APK در Google Play
یک ماژول کتابخانه جدید برای «کتابخانه درستیسنجی پروانه» و «کتابخانه بارگیری» ایجاد کنید. برای هر کتابخانه:
- فایل > جدید > ماژول جدید را انتخاب کنید.
- در پنجره ایجاد واحد جدید، کتابخانه Android را انتخاب کنید، و سپس بعدی را انتخاب کنید.
- نام برنامه/کتابخانه را مشخص کنید، مثلاً «کتابخانه پروانه Google Play» و «کتابخانه بارگیری Google Play»، حداقل سطح کیت توسعه نرمافزار را انتخاب کنید، سپس پایان را انتخاب کنید.
- فایل > ساختار پروژه را انتخاب کنید.
- برگه Properties (ویژگیها) را انتخاب کنید و در Library
Repository (مخزن کتابخانه)، کتابخانه را از فهرست راهنمای
<sdk>/extras/google/وارد کنید (play_licensing/برای License Verification Library (کتابخانه درستیسنجی پروانه) یاplay_apk_expansion/downloader_library/برای 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 شامل یک برنامه نمونه است که نحوه استفاده از Downloader Library را در برنامه نشان میدهد. این نمونه از کتابخانه سومی که در بسته Apk Expansion دردسترس است و APK Expansion Zip Library نام دارد استفاده میکند. اگر قصد دارید از فایلهای ZIP برای فایلهای توسعهتان استفاده کنید، پیشنهاد میکنیم «کتابخانه ZIP توسعه APK» را نیز به برنامهتان اضافه کنید. برای اطلاعات بیشتر، بخش زیر را درباره استفاده از کتابخانه ZIP توسعه APK ببینید.
اعلام اجازههای کاربر
برای بارگیری فایلهای توسعه، «کتابخانه بارگیریکننده» به چندین اجازه نیاز دارد که باید آنها را در فایل مانیفست برنامهتان اعلام کنید. آنها عبارتاند از:
<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>
توجه: بهطور پیشفرض، Downloader Library به سطح ۴ میانای برنامهسازی کاربردی نیاز دارد، اما APK Expansion Zip Library به سطح ۵ میانای برنامهسازی کاربردی نیاز دارد.
درحال پیادهسازی سرویس بارگیری
برای انجام بارگیریها در پسزمینه، «کتابخانه بارگیری»
زیرکلاس Service خودش را با نام DownloaderService ارائه میدهد که باید آن را گسترش دهید. علاوهبر بارگیری فایلهای توسعه برای شما، DownloaderService کارهای زیر را نیز انجام میدهد:
- یک
BroadcastReceiverرا ثبت میکند که تغییرات اتصال شبکه دستگاه (پخشCONNECTIVITY_ACTION) را گوش میدهد تا درصورت لزوم (مثلاً بهدلیل قطع اتصال) بارگیری را موقتاً متوقف کند و درصورت امکان (برقراری اتصال) بارگیری را ازسر بگیرد. - زنگ هشداری برای
RTC_WAKEUPزمانبندی میکند تا بارگیری را برای مواردی که سرویس ازبین میرود دوباره امتحان کند. Notificationسفارشی میسازد که پیشرفت بارگیری و هرگونه خطا یا تغییر وضعیت را نمایش میدهد.- به برنامه شما اجازه میدهد بارگیری را بهصورت دستی موقتاً متوقف و ازسر بگیرد.
- تأیید میکند که فضای ذخیرهسازی مشترک سوار شده و دردسترس است، فایلها ازقبل وجود ندارند، و فضای کافی وجود دارد، همه اینها قبلاز بارگیری فایلهای توسعه انجام میشود. سپس اگر هرکدام از این موارد درست نباشد به کاربر اطلاع میدهد.
تنها کاری که باید انجام دهید این است که کلاسی در برنامهتان ایجاد کنید که کلاس DownloaderService را گسترش دهد و سه روش را برای ارائه جزئیات خاص برنامه لغو کند:
getPublicKey()- این باید رشتهای را برگرداند که کلید عمومی RSA کدگذاریشده با Base64 برای حساب ناشر شما است، که از صفحه نمایه در «کنسول Play» دردسترس است (به راهاندازی برای صدور پروانه مراجعه کنید).
getSALT()- این باید آرایهای از بایتهای تصادفی را برگرداند که صدور پروانه
Policyاز آن برای ایجادObfuscatorاستفاده میکند. نمک تضمین میکند که فایلSharedPreferencesمبهمشده شما که دادههای پروانهتان در آن ذخیره شده است، منحصربهفرد و غیرقابلکشف خواهد بود. getAlarmReceiverClassName()- این باید نام کلاس
BroadcastReceiverرا در برنامهتان برگرداند که باید هشدار نشاندهنده اینکه بارگیری باید بازراهاندازی شود را دریافت کند (که ممکن است درصورت توقف غیرمنتظره سرویس بارگیریکننده اتفاق بیفتد).
برای مثال، در اینجا پیادهسازی کامل DownloaderService آورده شده است:
کاتلین
// 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 }
جاوا
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() را فراخوانی کنید.
برای مثال:
کاتلین
class SampleAlarmReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { try { DownloaderClientMarshaller.startDownloadServiceIfRequired( context, intent, SampleDownloaderService::class.java ) } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } } }
جاوا
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» روش زیر را در روش
onCreate()فعالیت فراخوانی میکند تا بررسی کند آیا فایلهای افزونه ازقبل در دستگاه وجود دارند یا نه:کاتلین
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 }
جاوا
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برنامه نمونه را ببینید.)اگر این روش مقدار نادرست برگرداند، برنامه باید بارگیری را شروع کند.
- با فراخوانی روش ایستا
DownloaderClientMarshaller.startDownloadServiceIfRequired(Context c, PendingIntent notificationClient, Class<?> serviceClass)، بارگیری را شروع کنید.این روش پارامترهای زیر را میگیرد:
context:Contextبرنامهتان.-
notificationClient:PendingIntentبرای شروع فعالیت اصلی شما. این درNotificationکهDownloaderServiceبرای نشان دادن پیشرفت بارگیری ایجاد میکند استفاده میشود. وقتی کاربر اعلان را انتخاب میکند، سیستمPendingIntentرا که در اینجا ارائه میدهید فراخوانی میکند و باید فعالیتی را باز کند که پیشرفت بارگیری را نشان میدهد (معمولاً همان فعالیتی که بارگیری را شروع کرده است). -
serviceClass: شیءClassبرای پیادهسازی شما ازDownloaderService، که برای شروع سرویس و آغاز بارگیری درصورت لزوم لازم است.
این روش عدد صحیحی را برمیگرداند که نشان میدهد آیا بارگیری لازم است یا نه. مقادیر ممکن عبارتاند از:
-
NO_DOWNLOAD_REQUIRED: اگر فایلها ازقبل وجود داشته باشند یا بارگیری درحال انجام باشد، برگردانده میشود. LVL_CHECK_REQUIRED: اگر درستیسنجی پروانه برای دریافت نشانیهای وب فایل توسعه لازم باشد، برگردانده میشود.-
DOWNLOAD_REQUIRED: اگر نشانیهای وب فایل توسعه ازقبل شناخته شده باشند، اما بارگیری نشده باشند، برگردانده میشود.
رفتار
LVL_CHECK_REQUIREDوDOWNLOAD_REQUIREDاساساً یکسان است و معمولاً لازم نیست نگران آنها باشید. در فعالیت اصلیتان کهstartDownloadServiceIfRequired()را فراخوانی میکند، میتوانید بهسادگی بررسی کنید که آیا پاسخNO_DOWNLOAD_REQUIREDاست یا نه. اگر پاسخ چیزی غیرازNO_DOWNLOAD_REQUIREDباشد، «کتابخانه بارگیری» بارگیری را شروع میکند و باید میانای کاربر فعالیتتان را بهروز کنید تا پیشرفت بارگیری را نمایش دهد (مرحله بعدی را ببینید). اگر پاسخNO_DOWNLOAD_REQUIREDباشد، فایلها دردسترس هستند و برنامهتان میتواند شروع شود.برای مثال:
کاتلین
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 }
جاوا
@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()چیزی غیرازNO_DOWNLOAD_REQUIREDبرمیگرداند، با فراخوانیDownloaderClientMarshaller.CreateStub(IDownloaderClient client, Class<?> downloaderService)، نمونهای ازIStubایجاد کنید.IStubاتصالی بین فعالیت شما و سرویس بارگیری ایجاد میکند تا فعالیت شما بازخوانیهایی درباره پیشرفت بارگیری دریافت کند.برای نمونهسازی
IStubبا فراخوانیCreateStub()، باید پیادهسازی میانایIDownloaderClientو پیادهسازیDownloaderServiceرا به آن منتقل کنید. بخش بعدی درباره دریافت پیشرفت بارگیری به بحث درباره میانایIDownloaderClientمیپردازد که معمولاً باید آن را در کلاسActivityپیادهسازی کنید تا بتوانید میانای کاربر فعالیت را هنگام تغییر وضعیت بارگیری بهروز کنید.توصیه میکنیم
CreateStub()را برای نمونهسازیIStubدرطول روشonCreate()فعالیتتان فراخوانی کنید، پساز اینکهstartDownloadServiceIfRequired()بارگیری را شروع کرد.برای مثال، در نمونه کد قبلی برای
onCreate()، میتوانید به نتیجهstartDownloadServiceIfRequired()اینگونه پاسخ دهید:کاتلین
// 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 }
جاوا
// 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()فعالیتتان فراخوانی کنید.کاتلین
override fun onResume() { downloaderClientStub?.connect(this) super.onResume() } override fun onStop() { downloaderClientStub?.disconnect(this) super.onStop() }
جاوا
@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متصل به سرویس را دریافت کنید.پیادهسازی توصیهشده به این شکل است:
کاتلین
private var remoteService: IDownloaderService? = null ... override fun onServiceConnected(m: Messenger) { remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply { downloaderClientStub?.messenger?.also { messenger -> onClientUpdated(messenger) } } }
جاوا
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 متصل باشد. شاید بخواهید اولویت کاربر را برای فعال کردن بارگیری ازطریق شبکه تلفن همراه ارائه دهید. در این صورت، میتوانید با این شماره تماس بگیرید:کاتلین
remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply { ... setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR) }
جاوا
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() برای ساختن مسیر فایلهایتان استفاده کنید.
در اینجا روشی آورده شده است که میتوانید در برنامهتان برای دریافت آرایهای حاوی مسیر کامل به هر دو فایل توسعهتان استفاده کنید:
کاتلین
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() }
جاوا
// 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
بسته Google Market Apk Expansion شامل کتابخانهای بهنام APK
Expansion Zip Library (واقع در <sdk>/extras/google/google_market_apk_expansion/zip_file/) است. این کتابخانه اختیاری است و
به شما کمک میکند فایلهای توسعهتان را وقتی بهصورت فایل ZIP ذخیره شدهاند
بخوانید. استفاده از این کتابخانه به شما امکان میدهد بهراحتی منابع را از
فایلهای توسعه ZIP خود بهعنوان یک سیستم فایل مجازی بخوانید.
«کتابخانه فشردهسازی افزونه APK» شامل کلاسها و میاناهای برنامهسازی کاربردی زیر است:
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مرتب میکند تا دسترسی به فایل را برای برخی از APIهای Android که انتظار دسترسیUriبه فایلهای رسانهای را دارند، فراهم کند. برای مثال، این ویژگی زمانی مفید است که بخواهید ویدیویی را باVideoView.setVideoURI()پخش کنید.
درحال رد شدن از فشردهسازی ZIP فایلهای رسانهای
اگر از فایلهای توسعه برای ذخیره فایلهای رسانهای استفاده میکنید، فایل ZIP همچنان به شما امکان میدهد
از تماسهای بازپخش رسانه Android که کنترلهای آفست و طول را ارائه میدهند (مانند MediaPlayer.setDataSource() و
SoundPool.load()) استفاده کنید. برای اینکه
این کار انجام شود، نباید هنگام ایجاد بستههای ZIP، فشردهسازی اضافی روی فایلهای رسانهای انجام دهید. برای مثال، هنگام استفاده از ابزار zip، باید از گزینه -n برای مشخص کردن پسوندهای فایلی که نباید فشرده شوند استفاده کنید:
zip -n .mp4;.ogg main_expansion media_files
درحال خواندن از فایل ZIP
هنگام استفاده از «کتابخانه فایل فشرده افزونه APK»، خواندن فایل از فایل ZIP معمولاً به موارد زیر نیاز دارد:
کاتلین
// 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 { ... }
جاوا
// 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 با مسیر فایل گسترش موردنظر استفاده کنید:
کاتلین
// 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 { ... }
جاوا
// 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، باید توانایی برنامهتان را برای خواندن فایلها از فضای ذخیرهسازی مشترک آزمایش کنید. تنها کاری که باید انجام دهید این است که فایلها را به مکان مناسب در فضای ذخیرهسازی مشترک دستگاه اضافه کنید و برنامهتان را راهاندازی کنید:
- در دستگاهتان، فهرست راهنمای مناسب را در فضای ذخیرهسازی مشترک ایجاد کنید تا Google
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()ذخیره کنید.
درحال آزمایش بارگیری فایل
ازآنجاییکه برنامهتان گاهی باید فایلهای تکمیلی را هنگام اولین باز شدن بهصورت دستی بارگیری کند، مهم است که این فرایند را آزمایش کنید تا مطمئن شوید برنامهتان میتواند با موفقیت برای نشانیهای وب پُرسمان کند، فایلها را بارگیری کند، و آنها را در دستگاه ذخیره کند.
برای آزمایش پیادهسازی برنامه از روش بارگیری دستی، میتوانید آن را در دسته هدف آزمایشی داخلی منتشر کنید تا فقط برای آزمونگران مجاز دردسترس باشد. اگر همه چیز طبق انتظار کار کند، برنامهتان باید بهمحض شروع فعالیت اصلی، بارگیری فایلهای توسعه را آغاز کند.
توجه: قبلاً میتوانستید با بارگذاری نسخه «پیشنویس» منتشرنشده، برنامه را آزمایش کنید. دیگر از این عملکرد پشتیبانی نمیشود. درعوض، باید آن را در دسته هدف آزمایشی داخلی، بسته، یا باز منتشر کنید. برای اطلاعات بیشتر، برنامههای پیشنویس دیگر پشتیبانی نمیشوند را ببینید.
بهروزرسانی برنامه
یکیاز مزایای بزرگ استفاده از فایلهای توسعه در Google Play، امکان بهروزرسانی برنامه بدون بارگیری مجدد همه داراییهای اصلی است. چون Google Play به شما اجازه میدهد دو فایل تکمیلی با هر APK ارائه دهید، میتوانید از فایل دوم بهعنوان «وصله» استفاده کنید که بهروزرسانیها و داراییهای جدید را ارائه میدهد. انجام این کار باعث میشود نیازی به بارگیری مجدد فایل توسعه اصلی نباشد که ممکن است بزرگ و برای کاربران پرهزینه باشد.
فایل توسعه وصله ازنظر فنی همانند فایل توسعه اصلی است و نه سیستم Android و نه Google Play وصله واقعی را بین فایلهای توسعه اصلی و وصله شما انجام نمیدهند. کد برنامه شما باید هرگونه وصله لازم را خودش انجام دهد.
اگر از فایلهای ZIP بهعنوان فایلهای توسعه استفاده میکنید، کتابخانه Zip توسعه APK که در بسته «توسعه APK» گنجانده شده است، قابلیت ادغام فایل وصله با فایل توسعه اصلی را دارد.
توجه: حتی اگر فقط لازم باشد تغییراتی در فایل توسعه وصله ایجاد کنید، همچنان باید APK را بهروز کنید تا Google Play بتواند بهروزرسانی را انجام دهد.
اگر به تغییر کد در برنامه نیاز ندارید، باید بهسادگی versionCode را در مانیفست بهروز کنید.
تا زمانی که فایل توسعه اصلی مرتبط با APK را در «کنسول Play» تغییر ندهید، کاربرانی که قبلاً برنامهتان را نصب کردهاند فایل توسعه اصلی را بارگیری نخواهند کرد. کاربران فعلی فقط APK بهروزشده و فایل توسعه وصله جدید را دریافت میکنند (فایل توسعه اصلی قبلی حفظ میشود).
در اینجا چند مشکل وجود دارد که باید در رابطه با بهروزرسانی فایلهای توسعه درنظر داشته باشید:
- در هر زمان فقط دو فایل توسعه میتواند برای برنامهتان وجود داشته باشد. یک فایل توسعه اصلی و یک فایل توسعه وصله. درطول بهروزرسانی فایل، Google Play نسخه قبلی را حذف میکند (و برنامه شما نیز باید هنگام انجام بهروزرسانیهای دستی همین کار را انجام دهد).
- هنگام افزودن فایل توسعه وصله، سیستم Android درواقع برنامه یا فایل توسعه اصلی شما را وصله نمیکند. باید برنامهتان را طوری طراحی کنید که از دادههای وصله پشتیبانی کند. بااینحال، بسته Apk Expansion شامل کتابخانهای برای استفاده از فایلهای ZIP بهعنوان فایلهای توسعه است که دادهها را از فایل وصله در فایل توسعه اصلی ادغام میکند تا بتوانید بهراحتی همه دادههای فایل توسعه را بخوانید.