ماژول های ویژگی به شما این امکان را می دهند که ویژگی ها و منابع خاصی را از ماژول پایه برنامه خود جدا کرده و در بسته نرم افزاری خود قرار دهید. برای مثال، از طریق Play Feature Delivery، کاربران میتوانند بعداً پس از اینکه APK پایه برنامه شما را نصب کردهاند، آن مؤلفهها را برحسب تقاضا دانلود و نصب کنند.
به عنوان مثال، یک برنامه پیام متنی را در نظر بگیرید که شامل قابلیت ضبط و ارسال پیام های تصویری است، اما تنها درصد کمی از کاربران پیام های تصویری ارسال می کنند. ممکن است منطقی باشد که پیامرسانی تصویری را به عنوان یک ماژول ویژگی قابل دانلود اضافه کنید. به این ترتیب، دانلود اولیه برنامه برای همه کاربران کوچکتر است و فقط کاربرانی که پیامهای تصویری ارسال میکنند باید آن مؤلفه اضافی را دانلود کنند.
به خاطر داشته باشید، این نوع ماژولارسازی به تلاش بیشتری نیاز دارد و احتمالاً کدهای موجود برنامه شما را تغییر میدهد، بنابراین به دقت در نظر بگیرید که کدام یک از ویژگیهای برنامه شما از در دسترس قرار گرفتن کاربران در صورت تقاضا بیشترین سود را خواهد داشت. برای درک بهتر موارد استفاده بهینه و دستورالعملهای ویژگیهای درخواستی، بهترین شیوههای UX برای تحویل در صورت تقاضا را بخوانید.
اگر میخواهید به تدریج ویژگیهای برنامه را در طول زمان، بدون فعال کردن گزینههای تحویل پیشرفته، مانند تحویل در صورت تقاضا، مدولار کنید، در عوض تحویل زمان نصب را پیکربندی کنید .
این صفحه به شما کمک می کند یک ماژول ویژگی را به پروژه برنامه خود اضافه کنید و آن را برای تحویل درخواستی پیکربندی کنید. قبل از شروع، مطمئن شوید که از Android Studio نسخه 3.5 یا بالاتر و Android Gradle Plugin نسخه 3.5.0 یا بالاتر استفاده می کنید.
ساده ترین راه برای ایجاد یک ماژول ویژگی جدید استفاده از Android Studio 3.5 یا بالاتر است. از آنجایی که ماژول های ویژگی وابستگی ذاتی به ماژول برنامه پایه دارند، می توانید آنها را فقط به پروژه های برنامه موجود اضافه کنید.
برای افزودن یک ماژول ویژگی به پروژه برنامه خود با استفاده از Android Studio، به صورت زیر عمل کنید:
- اگر قبلاً این کار را نکرده اید، پروژه برنامه خود را در IDE باز کنید.
- File > New > New Module را از نوار منو انتخاب کنید.
- در گفتگوی Create New Module ، Dynamic Feature Module را انتخاب کرده و روی Next کلیک کنید.
- در بخش پیکربندی ماژول جدید ، موارد زیر را تکمیل کنید:
- ماژول برنامه کاربردی پایه را برای پروژه برنامه خود از منوی کشویی انتخاب کنید.
- نام ماژول را مشخص کنید. IDE از این نام برای شناسایی ماژول به عنوان یک پروژه فرعی Gradle در فایل تنظیمات Gradle شما استفاده می کند. هنگامی که بسته برنامه خود را می سازید، Gradle از آخرین عنصر نام پروژه فرعی برای تزریق ویژگی
<manifest split>
در مانیفست ماژول ویژگی استفاده می کند. - نام بسته ماژول را مشخص کنید. به طور پیشفرض، اندروید استودیو نام بستهای را پیشنهاد میکند که نام بسته ریشه ماژول پایه و نام ماژولی را که در مرحله قبل مشخص کردهاید ترکیب میکند.
- حداقل سطح API را که می خواهید ماژول از آن پشتیبانی کند، انتخاب کنید. این مقدار باید با ماژول پایه مطابقت داشته باشد.
- روی Next کلیک کنید.
در قسمت گزینه های دانلود ماژول موارد زیر را تکمیل کنید:
عنوان ماژول را با حداکثر 50 کاراکتر مشخص کنید. این پلتفرم از این عنوان برای شناسایی ماژول برای کاربران استفاده میکند، مثلاً زمانی که تأیید میکند کاربر میخواهد ماژول را دانلود کند یا خیر. به همین دلیل، ماژول پایه برنامه شما باید عنوان ماژول را به عنوان منبع رشته ای داشته باشد که می توانید آن را ترجمه کنید. هنگام ایجاد ماژول با استفاده از Android Studio، IDE منبع رشته را به ماژول پایه برای شما اضافه می کند و ورودی زیر را در مانیفست ماژول ویژگی تزریق می کند:
<dist:module ... dist:title="@string/feature_title"> </dist:module>
در منوی کرکرهای زیر Install-time inclusion ، ماژول در زمان نصب شامل نشود را انتخاب کنید. Android Studio موارد زیر را در مانیفست ماژول تزریق می کند تا انتخاب شما را منعکس کند:
<dist:module ... > <dist:delivery> <dist:on-demand/> </dist:delivery> </dist:module>
اگر میخواهید این ماژول برای دستگاههای دارای Android 4.4 (سطح API 20) و پایینتر در دسترس باشد و در چند APK گنجانده شود، کادر کنار Fusing را علامت بزنید. این بدان معناست که میتوانید رفتار درخواستی را برای این ماژول فعال کنید و فیوزینگ را غیرفعال کنید تا آن را از دستگاههایی که از دانلود و نصب فایلهای APK تقسیمشده پشتیبانی نمیکنند حذف کنید. Android Studio موارد زیر را در مانیفست ماژول تزریق می کند تا انتخاب شما را منعکس کند:
<dist:module ...> <dist:fusing dist:include="true | false" /> </dist:module>
روی Finish کلیک کنید.
پس از اتمام ساخت ماژول اندروید استودیو، محتویات آن را خودتان از پنجره Project بررسی کنید ( مشاهده > ابزار ویندوز > پروژه را از نوار منو انتخاب کنید). کد، منابع و سازمان پیشفرض باید مشابه ماژول برنامه استاندارد باشد.
در مرحله بعد، باید قابلیت نصب بر اساس تقاضا را با استفاده از کتابخانه Play Feature Delivery پیاده سازی کنید.
قبل از شروع، ابتدا باید کتابخانه تحویل ویژگی Play را به پروژه خود اضافه کنید .
هنگامی که برنامه شما نیاز به استفاده از یک ماژول ویژگی دارد، میتواند زمانی که در پیشزمینه است، از طریق کلاس SplitInstallManager
درخواست کند. هنگام درخواست، برنامه شما باید نام ماژول را همانطور که توسط عنصر split
در مانیفست ماژول هدف تعریف شده است، مشخص کند. هنگامی که یک ماژول ویژگی را با استفاده از Android Studio ایجاد می کنید، سیستم ساخت از نام ماژول شما برای تزریق این ویژگی به مانیفست ماژول در زمان کامپایل استفاده می کند. برای اطلاعات بیشتر، درباره مانیفست های ماژول ویژگی بخوانید.
به عنوان مثال، برنامه ای را در نظر بگیرید که دارای یک ماژول درخواستی برای گرفتن و ارسال پیام های تصویری با استفاده از دوربین دستگاه است و این ماژول درخواستی split="pictureMessages"
در مانیفست خود مشخص می کند. نمونه زیر از SplitInstallManager
برای درخواست ماژول pictureMessages
(همراه با یک ماژول اضافی برای برخی از فیلترهای تبلیغاتی) استفاده می کند:
// Creates an instance of SplitInstallManager. val splitInstallManager = SplitInstallManagerFactory.create(context) // Creates a request to install a module. val request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build() splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener { sessionId -> ... } .addOnFailureListener { exception -> ... }
// Creates an instance of SplitInstallManager. SplitInstallManager splitInstallManager = SplitInstallManagerFactory.create(context); // Creates a request to install a module. SplitInstallRequest request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build(); splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener(sessionId -> { ... }) .addOnFailureListener(exception -> { ... });
وقتی برنامه شما ماژول درخواستی درخواست میکند، کتابخانه تحویل ویژگی Play از استراتژی «آتش و فراموش کردن» استفاده میکند. یعنی درخواست دانلود ماژول را به پلتفرم ارسال می کند، اما نظارت نمی کند که آیا نصب با موفقیت انجام شده است یا خیر. برای پیشبرد سفر کاربر پس از نصب یا رسیدگی به خطاها، مطمئن شوید که وضعیت درخواست را زیر نظر دارید .
توجه: اشکالی ندارد که ماژول ویژگی را که قبلاً روی دستگاه نصب شده است درخواست کنید. اگر تشخیص دهد که ماژول قبلاً نصب شده است، API فوراً درخواست را تکمیل شده در نظر می گیرد. علاوه بر این، پس از نصب یک ماژول، Google Play آن را به طور خودکار به روز نگه می دارد. یعنی وقتی نسخه جدیدی از بسته برنامه خود را آپلود می کنید، پلتفرم تمام APK های نصب شده متعلق به برنامه شما را به روز می کند. برای اطلاعات بیشتر، مدیریت بهروزرسانیهای برنامه را بخوانید.
برای دسترسی به کد و منابع ماژول، برنامه شما باید SplitCompat را فعال کند . توجه داشته باشید که SplitCompat برای برنامه های فوری اندروید مورد نیاز نیست.
اگر نیازی ندارید برنامه خود را فوراً یک ماژول درخواستی دانلود و نصب کنید، میتوانید نصب را برای زمانی که برنامه در پسزمینه است به تعویق بیندازید. برای مثال، اگر میخواهید برخی از مواد تبلیغاتی را برای راهاندازی بعدی برنامه خود از قبل بارگیری کنید.
میتوانید با استفاده از متد deferredInstall()
یک ماژول را مشخص کنید که بعداً دانلود شود، همانطور که در زیر نشان داده شده است. و بر خلاف SplitInstallManager.startInstall()
، برنامه شما برای شروع درخواست نصب معوق نیازی به در پیش زمینه بودن ندارد.
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(listOf("promotionalFilters"))
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(Arrays.asList("promotionalFilters"));
درخواست برای نصب به تعویق افتاده بهترین تلاش است و شما نمی توانید پیشرفت آنها را پیگیری کنید. بنابراین، قبل از تلاش برای دسترسی به ماژولی که برای نصب معوق مشخص کردهاید، باید بررسی کنید که ماژول نصب شده است . اگر نیاز دارید که ماژول فوراً در دسترس باشد، در عوض از SplitInstallManager.startInstall()
برای درخواست آن استفاده کنید، همانطور که در بخش قبل نشان داده شده است.
برای اینکه بتوانید نوار پیشرفت را بهروزرسانی کنید، پس از نصب یک intent اجرا کنید، یا بهخوبی خطای درخواست را مدیریت کنید، باید بهروزرسانیهای وضعیت را از وظیفه SplitInstallManager.startInstall()
ناهمزمان گوش کنید. قبل از اینکه بتوانید بهروزرسانیها را برای درخواست نصب خود دریافت کنید، یک شنونده ثبت کنید و شناسه جلسه درخواست را دریافت کنید، همانطور که در زیر نشان داده شده است.
// Initializes a variable to later track the session ID for a given request. var mySessionId = 0 // Creates a listener for request status updates. val listener = SplitInstallStateUpdatedListener { state -> if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } } // Registers the listener. splitInstallManager.registerListener(listener) ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener { sessionId -> mySessionId = sessionId } // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener { exception -> // Handle request errors. } // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener)
// Initializes a variable to later track the session ID for a given request. int mySessionId = 0; // Creates a listener for request status updates. SplitInstallStateUpdatedListener listener = state -> { if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } }; // Registers the listener. splitInstallManager.registerListener(listener); ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener(sessionId -> { mySessionId = sessionId; }) // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener(exception -> { // Handle request errors. }); // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener);
به خاطر داشته باشید که نصب بر اساس درخواست ماژول های ویژگی ممکن است گاهی اوقات با شکست مواجه شود، درست مانند نصب برنامه همیشه با موفقیت. عدم نصب ممکن است به دلیل مشکلاتی مانند حافظه کم دستگاه، عدم اتصال به شبکه، یا عدم ورود کاربر به فروشگاه Google Play باشد. برای پیشنهاداتی در مورد نحوه رسیدگی به این موقعیتها از دیدگاه کاربر، دستورالعملهای UX ما را برای تحویل درخواستی بررسی کنید.
از نظر کد، شما باید در دانلود یا نصب یک ماژول با استفاده از addOnFailureListener()
با شکست مواجه شوید، همانطور که در زیر نشان داده شده است:
splitInstallManager .startInstall(request) .addOnFailureListener { exception -> when ((exception as SplitInstallException).errorCode) { SplitInstallErrorCode.NETWORK_ERROR -> { // Display a message that requests the user to establish a // network connection. } SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED -> checkForActiveDownloads() ... } } fun checkForActiveDownloads() { splitInstallManager // Returns a SplitInstallSessionState object for each active session as a List. .sessionStates .addOnCompleteListener { task -> if (task.isSuccessful) { // Check for active sessions. for (state in task.result) { if (state.status() == SplitInstallSessionStatus.DOWNLOADING) { // Cancel the request, or request a deferred installation. } } } } }
splitInstallManager .startInstall(request) .addOnFailureListener(exception -> { switch (((SplitInstallException) exception).getErrorCode()) { case SplitInstallErrorCode.NETWORK_ERROR: // Display a message that requests the user to establish a // network connection. break; case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED: checkForActiveDownloads(); ... }); void checkForActiveDownloads() { splitInstallManager // Returns a SplitInstallSessionState object for each active session as a List. .getSessionStates() .addOnCompleteListener( task -> { if (task.isSuccessful()) { // Check for active sessions. for (SplitInstallSessionState state : task.getResult()) { if (state.status() == SplitInstallSessionStatus.DOWNLOADING) { // Cancel the request, or request a deferred installation. } } } }); }
جدول زیر خطاهایی را توضیح می دهد که ممکن است برنامه شما نیاز به رسیدگی به آن داشته باشد:
کد خطا | توضیحات | اقدام پیشنهادی |
---|---|---|
ACTIVE_SESSIONS_LIMIT_EXCEEDED | این درخواست رد می شود زیرا حداقل یک درخواست موجود در حال بارگیری است. | همانطور که در نمونه بالا نشان داده شده است، بررسی کنید که آیا هنوز درخواستی در حال دانلود است یا خیر. |
MODULE_UNAVAILABLE | Google Play نمی تواند ماژول درخواستی را بر اساس نسخه نصب شده فعلی برنامه، دستگاه و حساب Google Play کاربر پیدا کند. | اگر کاربر به ماژول دسترسی ندارد، به او اطلاع دهید. |
INVALID_REQUEST | Google Play این درخواست را دریافت کرد، اما این درخواست معتبر نیست. | بررسی کنید که اطلاعات مندرج در درخواست کامل و دقیق باشد. |
SESSION_NOT_FOUND | جلسه ای برای شناسه جلسه معین پیدا نشد. | اگر میخواهید وضعیت یک درخواست را با شناسه جلسه آن نظارت کنید، مطمئن شوید که شناسه جلسه درست است. |
API_NOT_AVAILABLE | کتابخانه تحویل ویژگی Play در دستگاه فعلی پشتیبانی نمیشود. یعنی دستگاه قادر به دانلود و نصب ویژگی ها در صورت تقاضا نیست. | برای دستگاههای دارای Android 4.4 (سطح API 20) یا پایینتر، باید ماژولهای ویژگی را در زمان نصب با استفاده از ویژگی dist:fusing manifest اضافه کنید. برای کسب اطلاعات بیشتر، درباره مانیفست ماژول ویژگی بخوانید. |
NETWORK_ERROR | درخواست به دلیل یک خطای شبکه انجام نشد. | از کاربر بخواهید یا یک اتصال شبکه برقرار کند یا به شبکه دیگری تغییر دهد. |
ACCESS_DENIED | برنامه به دلیل مجوزهای ناکافی قادر به ثبت درخواست نیست. | این معمولاً زمانی اتفاق میافتد که برنامه در پسزمینه باشد. زمانی که برنامه به پیشزمینه بازگشت، درخواست را امتحان کنید. |
INCOMPATIBLE_WITH_EXISTING_SESSION | درخواست شامل یک یا چند ماژول است که قبلاً درخواست شده اند اما هنوز نصب نشده اند. | یا درخواست جدیدی ایجاد کنید که شامل ماژولهایی نباشد که برنامه شما قبلاً درخواست کرده است، یا منتظر بمانید تا نصب همه ماژولهای درخواستی فعلی قبل از امتحان مجدد درخواست به پایان برسد. به خاطر داشته باشید، درخواست ماژولی که قبلاً نصب شده است با خطا حل نمی شود. |
SERVICE_DIED | سرویس مسئول رسیدگی به درخواست فوت کرده است. | درخواست را دوباره امتحان کنید. |
INSUFFICIENT_STORAGE | دستگاه فضای خالی کافی برای نصب ماژول ویژگی ندارد. | به کاربر اطلاع دهید که فضای ذخیره کافی برای نصب این ویژگی ندارد. |
SPLITCOMPAT_VERIFICATION_ERROR، SPLITCOMPAT_EMULATION_ERROR، SPLITCOMPAT_COPY_ERROR | SplitCompat نتوانست ماژول ویژگی را بارگیری کند. | این خطاها باید پس از راه اندازی مجدد برنامه به طور خودکار برطرف شوند. |
PLAY_STORE_NOT_FOUND | برنامه Play Store روی دستگاه نصب نشده است. | به کاربر اطلاع دهید که برای دانلود این ویژگی به برنامه Play Store نیاز است. |
APP_NOT_OWNED | این برنامه توسط گوگل پلی نصب نشده است و این ویژگی قابل دانلود نیست. این خطا فقط برای نصب های معوق رخ می دهد. | اگر میخواهید کاربر برنامه را در Google Play دریافت کند، از startInstall() استفاده کنید که میتواند تأییدیه کاربر لازم را دریافت کند. |
INTERNAL_ERROR | یک خطای داخلی در فروشگاه Play رخ داد. | درخواست را دوباره امتحان کنید. |
اگر کاربر درخواست دانلود یک ماژول درخواستی را دارد و خطایی رخ میدهد، در نظر بگیرید که گفتگویی را نمایش دهید که دو گزینه برای کاربر فراهم میکند: دوباره امتحان کنید (که دوباره درخواست را انجام میدهد) و لغو (که درخواست را رها میکند). برای پشتیبانی بیشتر، باید پیوند راهنما را نیز ارائه دهید که کاربران را به مرکز راهنمای Google Play هدایت کند.
پس از اینکه شنونده ای را ثبت کردید و شناسه جلسه را برای درخواست خود ضبط کردید، از StateUpdatedListener.onStateUpdate()
برای مدیریت تغییرات حالت، مانند شکل زیر استفاده کنید.
override fun onStateUpdate(state : SplitInstallSessionState) { if (state.status() == SplitInstallSessionStatus.FAILED && state.errorCode() == SplitInstallErrorCode.SERVICE_DIED) { // Retry the request. return } if (state.sessionId() == mySessionId) { when (state.status()) { SplitInstallSessionStatus.DOWNLOADING -> { val totalBytes = state.totalBytesToDownload() val progress = state.bytesDownloaded() // Update progress bar. } SplitInstallSessionStatus.INSTALLED -> { // After a module is installed, you can start accessing its content or // fire an intent to start an activity in the installed module. // For other use cases, see access code and resources from installed modules. // If the request is an on demand module for an Android Instant App // running on Android 8.0 (API level 26) or higher, you need to // update the app context using the SplitInstallHelper API. } } } }
@Override public void onStateUpdate(SplitInstallSessionState state) { if (state.status() == SplitInstallSessionStatus.FAILED && state.errorCode() == SplitInstallErrorCode.SERVICE_DIES) { // Retry the request. return; } if (state.sessionId() == mySessionId) { switch (state.status()) { case SplitInstallSessionStatus.DOWNLOADING: int totalBytes = state.totalBytesToDownload(); int progress = state.bytesDownloaded(); // Update progress bar. break; case SplitInstallSessionStatus.INSTALLED: // After a module is installed, you can start accessing its content or // fire an intent to start an activity in the installed module. // For other use cases, see access code and resources from installed modules. // If the request is an on demand module for an Android Instant App // running on Android 8.0 (API level 26) or higher, you need to // update the app context using the SplitInstallHelper API. } } }
حالت های احتمالی برای درخواست نصب شما در جدول زیر توضیح داده شده است.
حالت درخواست | توضیحات | اقدام پیشنهادی |
---|---|---|
در انتظار | درخواست پذیرفته شد و دانلود باید به زودی شروع شود. | برای ارائه بازخورد کاربر در مورد دانلود، مؤلفههای رابط کاربری، مانند نوار پیشرفت، را راهاندازی کنید. |
REQUIRES_USER_CONFIRMATION | دانلود نیاز به تایید کاربر دارد. معمولاً این وضعیت زمانی رخ می دهد که برنامه از طریق Google Play نصب نشده باشد. | از کاربر بخواهید تا بارگیری ویژگی را از طریق Google Play تأیید کند. برای کسب اطلاعات بیشتر، به بخش نحوه دریافت تأییدیه کاربر بروید. |
در حال دانلود | دانلود در حال انجام است. | اگر نوار پیشرفت برای دانلود ارائه می کنید، از روش های SplitInstallSessionState.bytesDownloaded() و SplitInstallSessionState.totalBytesToDownload() برای به روز رسانی رابط کاربری استفاده کنید (نمونه کد بالا را در این جدول ببینید). |
دانلود شد | دستگاه ماژول را دانلود کرده است اما نصب هنوز شروع نشده است. | برنامهها باید SplitCompat را فعال کنند تا به ماژولهای دانلود شده دسترسی داشته باشند و از دیدن این وضعیت اجتناب کنند. این برای دسترسی به کد و منابع ماژول ویژگی مورد نیاز است. |
در حال نصب | دستگاه در حال نصب ماژول است. | نوار پیشرفت را به روز کنید. این حالت معمولا کوتاه است. |
نصب شده است | ماژول بر روی دستگاه نصب شده است. | برای ادامه سفر کاربر به کد و منبع در ماژول دسترسی پیدا کنید . اگر این ماژول برای یک برنامه فوری Android است که روی Android 8.0 (سطح API 26) یا بالاتر اجرا میشود، باید از |
ناموفق | درخواست قبل از نصب ماژول روی دستگاه انجام نشد. | از کاربر بخواهید درخواست را دوباره امتحان کند یا آن را لغو کند. |
لغو | دستگاه در حال لغو درخواست است. | برای کسب اطلاعات بیشتر، به بخش نحوه لغو درخواست نصب بروید. |
لغو شد | درخواست لغو شده است. |
در برخی موارد، Google Play ممکن است قبل از برآورده کردن درخواست دانلود، به تأیید کاربر نیاز داشته باشد. به عنوان مثال، اگر برنامه شما توسط Google Play نصب نشده باشد یا اگر در حال تلاش برای دانلود بزرگ از طریق داده تلفن همراه هستید. در چنین مواردی، وضعیت درخواست REQUIRES_USER_CONFIRMATION
را گزارش میدهد و قبل از اینکه دستگاه بتواند ماژولهای موجود در درخواست را دانلود و نصب کند، برنامه شما باید تأییدیه کاربر را دریافت کند. برای دریافت تأیید، برنامه شما باید به صورت زیر از کاربر درخواست کند:
override fun onSessionStateUpdate(state: SplitInstallSessionState) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, // an activity result launcher registered via registerForActivityResult activityResultLauncher) } ... }
@Override void onSessionStateUpdate(SplitInstallSessionState state) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, // an activity result launcher registered via registerForActivityResult activityResultLauncher); } ... }
میتوانید با استفاده از قرارداد ActivityResultContracts.StartIntentSenderForResult
داخلی، یک راهانداز نتیجه فعالیت ثبت کنید. APIهای نتیجه فعالیت را ببینید.
وضعیت درخواست بسته به پاسخ کاربر به روز می شود:
- اگر کاربر تاییدیه را بپذیرد، وضعیت درخواست به
PENDING
تغییر میکند و دانلود ادامه مییابد. - اگر کاربر تأیید را رد کند، وضعیت درخواست به
CANCELED
تغییر می کند. - اگر کاربر انتخابی را قبل از از بین رفتن گفتگو انجام ندهد، وضعیت درخواست به صورت
REQUIRES_USER_CONFIRMATION
باقی می ماند. برنامه شما می تواند دوباره از کاربر بخواهد که درخواست را تکمیل کند.
برای دریافت پاسخ به تماس با پاسخ کاربر، میتوانید ActivityResultCallback را مطابق شکل زیر لغو کنید.
registerForActivityResult(StartIntentSenderForResult()) { result: ActivityResult -> { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } }
registerForActivityResult( new ActivityResultContracts.StartIntentSenderForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } });
اگر برنامه شما باید قبل از نصب درخواستی را لغو کند، میتواند روش cancelInstall()
با استفاده از شناسه جلسه درخواست، مطابق شکل زیر فراخوانی کند.
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId)
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId);
برای دسترسی به کد و منابع از یک ماژول دانلود شده پس از دانلود، برنامه شما باید کتابخانه SplitCompat را هم برای برنامه و هم برای هر فعالیت در ماژول های ویژگی که برنامه شما دانلود می کند فعال کند.
با این حال، باید توجه داشته باشید که پلتفرم محدودیتهای زیر را برای دسترسی به محتوای یک ماژول، برای مدتی (در برخی موارد) پس از دانلود ماژول تجربه میکند:
- پلتفرم نمیتواند هیچ ورودی مانیفست جدیدی را که توسط ماژول معرفی شده است اعمال کند.
- پلتفرم نمیتواند به منابع ماژول برای اجزای رابط کاربری سیستم، مانند اعلانها، دسترسی پیدا کند. اگر میخواهید فوراً از چنین منابعی استفاده کنید، آن منابع را در ماژول پایه برنامه خود قرار دهید.
برای اینکه برنامه شما به کد و منابع از یک ماژول دانلود شده دسترسی پیدا کند، باید SplitCompat را تنها با استفاده از یکی از روش های توضیح داده شده در بخش های زیر فعال کنید.
پس از اینکه SplitCompat را برای برنامه خود فعال کردید، باید SplitCompat را نیز برای هر فعالیت در ماژول های ویژگی که می خواهید برنامه شما به آنها دسترسی داشته باشد، فعال کنید .
ساده ترین راه برای فعال کردن SplitCompat این است که SplitCompatApplication
به عنوان زیر کلاس Application
در مانیفست برنامه خود اعلام کنید، همانطور که در زیر نشان داده شده است:
<application
...
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>
پس از نصب برنامه بر روی دستگاه، می توانید به طور خودکار به کد و منابع از ماژول های ویژگی دانلود شده دسترسی داشته باشید.
همچنین میتوانید SplitCompat را در فعالیتها یا خدمات خاص در زمان اجرا فعال کنید. فعال کردن SplitCompat به این روش برای راه اندازی فعالیت های موجود در ماژول های ویژگی مورد نیاز است. برای انجام این کار، همانطور که در زیر مشاهده می کنید، attachBaseContext
لغو کنید.
اگر یک کلاس Application سفارشی دارید، در عوض از آن بخواهید SplitCompatApplication
گسترش دهد تا SplitCompat را برای برنامه شما فعال کند، همانطور که در زیر نشان داده شده است:
class MyApplication : SplitCompatApplication() { ... }
public class MyApplication extends SplitCompatApplication { ... }
SplitCompatApplication
به سادگی ContextWrapper.attachBaseContext()
را نادیده می گیرد تا SplitCompat.install(Context applicationContext)
را شامل شود. اگر نمیخواهید کلاس Application
شما SplitCompatApplication
را گسترش دهد، میتوانید به صورت دستی متد attachBaseContext()
را به صورت زیر لغو کنید:
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this) }
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this); }
اگر ماژول درخواستی شما هم با برنامه های فوری و هم با برنامه های نصب شده سازگار است، می توانید SplitCompat را به صورت مشروط فراخوانی کنید، به شرح زیر:
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this) } }
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this); } }
پس از اینکه SplitCompat را برای برنامه پایه خود فعال کردید، باید SplitCompat را برای هر فعالیتی که برنامه شما در یک ماژول ویژگی دانلود می کند، فعال کنید. برای انجام این کار، از متد SplitCompat.installActivity()
به صورت زیر استفاده کنید:
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this) }
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this); }
می توانید پس از فعال کردن SplitCompat، فعالیت های تعریف شده در ماژول های ویژگی را با استفاده از startActivity()
اجرا کنید.
startActivity(Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...))
startActivity(new Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...));
پارامتر اول setClassName
نام بسته برنامه و پارامتر دوم نام کامل کلاس فعالیت است.
وقتی فعالیتی در یک ماژول ویژگی دارید که به صورت درخواستی دانلود کرده اید، باید SplitCompat را در فعالیت فعال کنید .
می توانید خدمات تعریف شده در ماژول های ویژگی را با استفاده از startService()
پس از فعال کردن SplitCompat راه اندازی کنید.
startService(Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...))
startService(new Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...));
شما نباید اجزای اندروید صادر شده را در ماژول های اختیاری قرار دهید.
سیستم ساخت، ورودی های مانیفست را برای همه ماژول ها در ماژول پایه ادغام می کند. اگر یک ماژول اختیاری حاوی یک مؤلفه صادر شده باشد، حتی قبل از نصب ماژول قابل دسترسی خواهد بود و در صورت فراخوانی از یک برنامه دیگر میتواند به دلیل از دست دادن کد باعث خرابی شود.
این مشکلی برای اجزای داخلی نیست. آنها فقط توسط برنامه قابل دسترسی هستند، بنابراین برنامه می تواند قبل از دسترسی به مؤلفه بررسی کند که ماژول نصب شده است .
اگر به یک جزء صادراتی نیاز دارید و میخواهید محتوای آن در یک ماژول اختیاری باشد، یک الگوی پروکسی را در نظر بگیرید. شما می توانید این کار را با افزودن یک جزء صادر شده پروکسی در پایه انجام دهید. در صورت دسترسی، مولفه پروکسی می تواند وجود ماژول حاوی محتوا را بررسی کند. اگر ماژول موجود باشد، مؤلفه پراکسی میتواند مؤلفه داخلی را از طریق یک Intent
از ماژول شروع کند و هدف را از برنامه تماس گیرنده منتقل کند. اگر ماژول موجود نباشد، مؤلفه می تواند ماژول را دانلود کند یا یک پیام خطای مناسب را به برنامه تماس گیرنده برگرداند.
اگر SplitCompat را برای زمینه برنامه پایه خود و فعالیتهای ماژول ویژگی خود فعال کنید ، میتوانید از کد و منابع یک ماژول ویژگی استفاده کنید که گویی بخشی از APK پایه است، پس از نصب ماژول اختیاری.
کدی که در داخل ماژول پایه شما قرار دارد می تواند مستقیماً توسط ماژول های دیگر استفاده شود. شما نیازی به انجام کار خاصی ندارید. فقط وارد کنید و از کلاس های مورد نیاز خود استفاده کنید.
یک شی یا کلاس در داخل یک ماژول را نمی توان مستقیماً از ماژول دیگری به طور ایستا دسترسی داشت، اما می توان به طور غیر مستقیم و با استفاده از بازتاب به آن دسترسی داشت.
با توجه به هزینه های عملکردی بازتاب، باید مراقب باشید که این چند وقت یکبار اتفاق می افتد. برای موارد استفاده پیچیده، از چارچوبهای تزریق وابستگی مانند Dagger 2 برای تضمین یک تماس بازتابی واحد در طول عمر برنامه استفاده کنید.
برای ساده سازی تعاملات با شی پس از نمونه سازی، توصیه می شود یک رابط در ماژول پایه و پیاده سازی آن در ماژول ویژگی تعریف شود. به عنوان مثال:
// In the base module interface MyInterface { fun hello(): String } // In the feature module object MyInterfaceImpl : MyInterface { override fun hello() = "Hello" } // In the base module, where we want to access the feature module code val stringFromModule = (Class.forName("com.package.module.MyInterfaceImpl") .kotlin.objectInstance as MyInterface).hello();
// In the base module public interface MyInterface { String hello(); } // In the feature module public class MyInterfaceImpl implements MyInterface { @Override public String hello() { return "Hello"; } } // In the base module, where we want to access the feature module code String stringFromModule = ((MyInterface) Class.forName("com.package.module.MyInterfaceImpl").getConstructor().newInstance()).hello();
هنگامی که یک ماژول نصب می شود، می توانید به منابع و دارایی های درون ماژول به روش استاندارد و با دو اخطار دسترسی داشته باشید:
- اگر از ماژول دیگری به منبعی دسترسی دارید، ماژول به شناسه منبع دسترسی نخواهد داشت، اگرچه هنوز می توان به منبع با نام دسترسی داشت. توجه داشته باشید که بسته مورد استفاده برای ارجاع به منبع، بسته ماژولی است که منبع در آن تعریف شده است.
- اگر میخواهید به داراییها یا منابعی که در یک ماژول تازه نصب شده از یک ماژول نصبشده دیگر در برنامهتان وجود دارد، دسترسی داشته باشید، باید این کار را با استفاده از زمینه برنامه انجام دهید. زمینه مولفه ای که سعی در دسترسی به منابع دارد هنوز به روز نمی شود. همچنین، میتوانید آن مؤلفه را دوباره ایجاد کنید (مثلاً فراخوانی Activity.recreate() ) یا پس از نصب ماژول ویژگی ، SplitCompat را مجدداً روی آن نصب کنید.
توصیه میکنیم از ReLinker برای بارگیری تمام کتابخانههای بومی خود هنگام استفاده از تحویل درخواستی ماژولهای ویژگی استفاده کنید. ReLinker مشکل بارگیری کتابخانه های بومی را پس از نصب ماژول ویژگی برطرف می کند. میتوانید درباره ReLinker در نکات Android JNI اطلاعات بیشتری کسب کنید.
پس از نصب یک تقسیم، توصیه می کنیم کد اصلی آن را از طریق ReLinker بارگیری کنید. برای برنامه های فوری باید از این روش ویژه استفاده کنید.
اگر از System.loadLibrary()
برای بارگیری کد بومی خود استفاده می کنید و کتابخانه بومی شما به کتابخانه دیگری در ماژول وابسته است، باید ابتدا آن کتابخانه دیگر را به صورت دستی بارگیری کنید. اگر از ReLinker استفاده می کنید، عملیات معادل Relinker.recursively().loadLibrary()
است.
اگر از dlopen()
در کد بومی برای بارگذاری یک کتابخانه تعریف شده در یک ماژول اختیاری استفاده می کنید، با مسیرهای کتابخانه نسبی کار نخواهد کرد. بهترین راه حل این است که مسیر مطلق کتابخانه را از کد جاوا از طریق ClassLoader.findLibrary()
بازیابی کنید و سپس از آن در فراخوانی dlopen()
خود استفاده کنید. این کار را قبل از وارد کردن کد بومی انجام دهید یا از یک فراخوانی JNI از کد بومی خود به جاوا استفاده کنید.
پس از گزارش ماژول برنامه فوری Android بهعنوان INSTALLED
، میتوانید با استفاده از زمینه برنامه تازهسازی شده به کد و منابع آن دسترسی پیدا کنید. زمینهای که برنامه شما قبل از نصب یک ماژول ایجاد میکند (مثلاً موردی که قبلاً در یک متغیر ذخیره شده است) حاوی محتوای ماژول جدید نیست. اما یک زمینه جدید انجام میشود—این را میتوان، برای مثال، با استفاده از createPackageContext
به دست آورد.
// Generate a new context as soon as a request for a new module // reports as INSTALLED. override fun onStateUpdate(state: SplitInstallSessionState ) { if (state.sessionId() == mySessionId) { when (state.status()) { ... SplitInstallSessionStatus.INSTALLED -> { val newContext = context.createPackageContext(context.packageName, 0) // If you use AssetManager to access your app’s raw asset files, you’ll need // to generate a new AssetManager instance from the updated context. val am = newContext.assets } } } }
// Generate a new context as soon as a request for a new module // reports as INSTALLED. @Override public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { ... case SplitInstallSessionStatus.INSTALLED: Context newContext = context.createPackageContext(context.getPackageName(), 0); // If you use AssetManager to access your app’s raw asset files, you’ll need // to generate a new AssetManager instance from the updated context. AssetManager am = newContext.getAssets(); } } }
هنگام درخواست ماژول درخواستی برای یک برنامه Instant Android در Android 8.0 (سطح API 26) و بالاتر، پس از گزارش درخواست نصب بهعنوان INSTALLED
، باید از طریق تماس با SplitInstallHelper.updateAppInfo(Context context)
، برنامه را با زمینه ماژول جدید بهروزرسانی کنید. SplitInstallHelper.updateAppInfo(Context context)
. در غیر این صورت، برنامه هنوز از کد و منابع ماژول آگاه نیست. پس از بهروزرسانی فراداده برنامه، باید محتویات ماژول را در طول رویداد رشته اصلی بعدی با فراخوانی یک Handler
جدید بارگیری کنید، همانطور که در زیر نشان داده شده است:
override fun onStateUpdate(state: SplitInstallSessionState ) { if (state.sessionId() == mySessionId) { when (state.status()) { ... SplitInstallSessionStatus.INSTALLED -> { // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context) Handler().post { // Loads contents from the module using AssetManager val am = context.assets ... } } } } } }
@Override public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { ... case SplitInstallSessionStatus.INSTALLED: // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context); new Handler().post(new Runnable() { @Override public void run() { // Loads contents from the module using AssetManager AssetManager am = context.getAssets(); ... } }); } } } }
اگر میخواهید کتابخانههای C/C++ را از ماژولی که دستگاه قبلاً در برنامه Instant دانلود کرده است بارگیری کنید، از SplitInstallHelper.loadLibrary(Context context, String libName)
استفاده کنید، همانطور که در زیر نشان داده شده است:
override fun onStateUpdate(state: SplitInstallSessionState) { if (state.sessionId() == mySessionId) { when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Updates the app’s context as soon as a module is installed. val newContext = context.createPackageContext(context.packageName, 0) // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”) ... } } } }
public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Updates the app’s context as soon as a module is installed. Context newContext = context.createPackageContext(context.getPackageName(), 0); // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”); ... } } }
- استفاده از Android WebView در فعالیتی که به منابع یا داراییها از یک ماژول اختیاری دسترسی دارد، ممکن نیست. این به دلیل ناسازگاری WebView و SplitCompat در Android API سطح 28 و پایین تر است.
- نمیتوانید اشیاء Android
ApplicationInfo
، محتویات آنها یا اشیایی که آنها را در برنامه خود دارند، کش کنید. همیشه باید این اشیاء را در صورت نیاز از یک زمینه برنامه واکشی کنید. ذخیره چنین اشیایی می تواند باعث از کار افتادن برنامه در هنگام نصب یک ماژول ویژگی شود.
برای بررسی اینکه کدام یک از ماژولهای ویژگی در حال حاضر روی دستگاه نصب شدهاند، میتوانید SplitInstallManager.getInstalledModules()
را فراخوانی کنید که یک Set<String>
از نام ماژولهای نصبشده را مطابق شکل زیر برمیگرداند.
val installedModules: Set<String> = splitInstallManager.installedModules
Set<String> installedModules = splitInstallManager.getInstalledModules();
میتوانید با فراخوانی SplitInstallManager.deferredUninstall(List<String> moduleNames)
از دستگاه درخواست کنید که ماژولها را حذف نصب کند، همانطور که در زیر نشان داده شده است.
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(listOf("pictureMessages", "promotionalFilters"))
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));
حذف نصب ماژول بلافاصله انجام نمی شود. یعنی دستگاه در صورت نیاز آنها را در پس زمینه حذف نصب می کند تا فضای ذخیره سازی ذخیره شود. همانطور که در بخش قبل توضیح داده شد، می توانید تأیید کنید که دستگاه یک ماژول را با فراخوانی SplitInstallManager.getInstalledModules()
و بررسی نتیجه حذف کرده است.
با بستههای برنامه، دستگاهها فقط کد و منابعی را که برای اجرای برنامه شما نیاز دارند دانلود میکنند. بنابراین، برای منابع زبان، دستگاه کاربر فقط منابع زبان برنامه شما را دانلود میکند که با یک یا چند زبان در حال حاضر انتخاب شده در تنظیمات دستگاه مطابقت دارد.
اگر میخواهید برنامه شما به منابع زبان اضافی دسترسی داشته باشد—مثلاً برای پیادهسازی انتخابگر زبان درونبرنامه، میتوانید از کتابخانه تحویل ویژگی Play برای دانلود آنها در صورت درخواست استفاده کنید. فرآیند مشابه دانلود یک ماژول ویژگی است، همانطور که در زیر نشان داده شده است.
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply() ... // Creates a request to download and install additional language resources. val request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build() // Submits the request to install the additional language resources. splitInstallManager.startInstall(request)
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply(); ... // Creates a request to download and install additional language resources. SplitInstallRequest request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build(); // Submits the request to install the additional language resources. splitInstallManager.startInstall(request);
درخواست به گونه ای انجام می شود که گویی درخواستی برای یک ماژول ویژگی است. یعنی میتوانید وضعیت درخواست را مانند حالت عادی نظارت کنید .
اگر برنامه شما فوراً به منابع زبان اضافی نیاز ندارد، میتوانید نصب را برای زمانی که برنامه در پسزمینه است، موکول کنید، همانطور که در زیر نشان داده شده است.
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
برای دسترسی به منابع زبان دانلود شده، برنامه شما باید روش SplitCompat.installActivity()
در متد attachBaseContext()
هر فعالیتی که نیاز به دسترسی به آن منابع دارد اجرا کند، همانطور که در زیر نشان داده شده است.
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) SplitCompat.installActivity(this) }
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); SplitCompat.installActivity(this); }
برای هر فعالیتی که میخواهید از منابع زبانی که برنامهتان دانلود کرده است استفاده کنید، زمینه پایه را بهروزرسانی کنید و از طریق Configuration
آن یک منطقه محلی جدید تنظیم کنید:
override fun attachBaseContext(base: Context) { val configuration = Configuration() configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) val context = base.createConfigurationContext(configuration) super.attachBaseContext(context) SplitCompat.install(this) }
@Override protected void attachBaseContext(Context base) { Configuration configuration = new Configuration(); configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))); Context context = base.createConfigurationContext(configuration); super.attachBaseContext(context); SplitCompat.install(this); }
برای اعمال این تغییرات، باید پس از نصب زبان جدید و آماده استفاده، فعالیت خود را دوباره ایجاد کنید. می توانید از متد Activity#recreate()
استفاده کنید.
when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Recreates the activity to load resources for the new language // preference. activity.recreate() } ... }
switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Recreates the activity to load resources for the new language // preference. activity.recreate(); ... }
مشابه ماژول های ویژگی، می توانید منابع اضافی را در هر زمان حذف نصب کنید. قبل از درخواست حذف، ممکن است بخواهید ابتدا تعیین کنید که کدام زبان ها در حال حاضر نصب شده اند، به شرح زیر.
val installedLanguages: Set<String> = splitInstallManager.installedLanguages
Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();
سپس می توانید تصمیم بگیرید که کدام زبان ها را با استفاده از متد deferredLanguageUninstall()
حذف نصب کنید، همانطور که در زیر نشان داده شده است.
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
کتابخانه تحویل ویژگی Play به شما امکان میدهد بدون اتصال به فروشگاه Play، توانایی برنامه خود را برای انجام کارهای زیر به صورت محلی آزمایش کنید:
- درخواست و نظارت بر نصب ماژول.
- خطاهای نصب را مدیریت کنید
- برای دسترسی به ماژول ها از
SplitCompat
استفاده کنید.
این صفحه نحوه استقرار فایلهای APK تقسیمشده برنامهتان را در دستگاه آزمایشی خود توضیح میدهد تا «تحویل ویژگی Play» بهطور خودکار از آن APKها برای شبیهسازی درخواست، دانلود و نصب ماژولها از فروشگاه Play استفاده کند.
اگرچه نیازی به ایجاد هیچ تغییری در منطق برنامه خود ندارید، اما باید شرایط زیر را رعایت کنید:
- آخرین نسخه
bundletool
را دانلود و نصب کنید. برای ایجاد مجموعه جدیدی از APKهای قابل نصب از بسته برنامه خود، بهbundletool
نیاز دارید.
اگر قبلاً این کار را نکردهاید، APKهای تقسیمشده برنامهتان را به شرح زیر بسازید:
- با استفاده از یکی از روش های زیر یک بسته برنامه برای برنامه خود بسازید:
- از Android Studio و پلاگین Android برای Gradle برای ساخت و امضای یک Android App Bundle استفاده کنید.
- بسته نرم افزاری خود را از خط فرمان بسازید .
از
bundletool
برای ایجاد مجموعهای از APK برای همه پیکربندیهای دستگاه با دستور زیر استفاده کنید:bundletool build-apks --local-testing --bundle my_app.aab --output my_app.apks
پرچم --local-testing
شامل متا دادههایی در مانیفستهای APK شما میشود که به کتابخانه تحویل ویژگی Play اجازه میدهد بدون اتصال به فروشگاه Play، از APKهای تقسیمشده محلی برای آزمایش نصب ماژولهای ویژگی استفاده کند.
پس از ساختن مجموعه ای از APK با استفاده از پرچم --local-testing
، از bundletool
برای نصب نسخه پایه برنامه خود و انتقال فایل های APK اضافی به حافظه محلی دستگاه خود استفاده کنید. با دستور زیر می توانید هر دو عمل را انجام دهید:
bundletool install-apks --apks my_app.apks
اکنون، وقتی برنامه خود را راهاندازی میکنید و جریان کاربر را برای دانلود و نصب یک ماژول ویژگی کامل میکنید، کتابخانه تحویل ویژگی Play از فایلهای APK استفاده میکند که bundletool
به حافظه محلی دستگاه منتقل شده است.
برای شبیهسازی نصبهای ماژول از فروشگاه Play، کتابخانه تحویل ویژگی Play از جایگزینی برای SplitInstallManager
به نام FakeSplitInstallManager
برای درخواست ماژول استفاده میکند. هنگامی که bundletool
با پرچم --local-testing
برای ساخت مجموعهای از فایلهای APK و استقرار آنها در دستگاه آزمایشی خود استفاده میکنید، شامل ابردادههایی است که به کتابخانه تحویل ویژگی Play دستور میدهد تا بهجای SplitInstallManager
، تماسهای API برنامهتان را بهطور خودکار تغییر دهد تا FakeSplitInstallManager
را فراخوانی کند. .
FakeSplitInstallManager
شامل یک پرچم بولین است که می توانید آن را فعال کنید تا یک خطای شبکه را دفعه بعد که برنامه شما درخواست نصب یک ماژول را می دهد، شبیه سازی کند. برای دسترسی به FakeSplitInstallManager
در تست های خود، می توانید نمونه ای از آن را با استفاده از FakeSplitInstallManagerFactory
دریافت کنید، همانطور که در زیر نشان داده شده است:
// Creates an instance of FakeSplitInstallManager with the app's context. val fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context) // Tells Play Feature Delivery Library to force the next module request to // result in a network error. fakeSplitInstallManager.setShouldNetworkError(true)
// Creates an instance of FakeSplitInstallManager with the app's context. FakeSplitInstallManager fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context); // Tells Play Feature Delivery Library to force the next module request to // result in a network error. fakeSplitInstallManager.setShouldNetworkError(true);