همانطور که در مقاله نمای کلی خدمات Google Play توضیح داده شده است، کیتهای توسعه نرمافزار با پشتیبانی «خدمات Google Play» توسط سرویسهای دروندستگاهی در دستگاههای Android دارای گواهی Google پشتیبانی میشوند. برای صرفهجویی در فضای ذخیرهسازی و حافظه در کل ناوگان دستگاهها، برخیاز سرویسها بهصورت واحد ارائه میشوند که وقتی برنامهتان به عملکرد مربوطه نیاز داشته باشد، بهدرخواست نصب میشوند. برای مثال، ML Kit این گزینه را هنگام استفاده از مدلها در «خدمات Google Play» ارائه میدهد.
در اکثر موارد، وقتی برنامهتان از میانای برنامهسازی کاربردیای استفاده میکند که به واحدهای لازم نیاز دارد، کیت توسعه نرمافزار خدمات Google Play بهطور خودکار این واحدها را بارگیری و نصب میکند. بااینحال، ممکن است بخواهید کنترل بیشتری بر این فرایند داشته باشید، مثلاً وقتیکه میخواهید با نصب کردن ماژول ازقبل، تجربه کاربری را بهبود ببخشید.
میانای برنامهسازی کاربردی ModuleInstallClient به شما امکان میدهد:
- بررسی کنید که آیا پودمانها قبلاً در دستگاه نصب شدهاند یا نه.
- درخواست نصب واحدها.
- پیشرفت نصب را نظارت کنید.
- خطاها را درطول فرایند نصب مدیریت کنید.
این راهنما به شما نشان میدهد که چگونه از ModuleInstallClient برای مدیریت ماژولها در برنامهتان استفاده کنید. توجه داشته باشید که تکهکدهای زیر از TensorFlow Lite SDK (play-services-tflite-java) بهعنوان نمونه استفاده میکنند، اما این مراحل برای هر کتابخانهای که با OptionalModuleApi ادغام شده است قابلاجرا هستند.
قبلاز شروع
برای آماده کردن برنامهتان، مراحل بخشهای زیر را تکمیل کنید.
پیشنیازهای برنامه
مطمئن شوید که فایل ساخت برنامه شما از مقادیر زیر استفاده میکند:
-
minSdkVersionاز23یا بالاتر
پیکربندی برنامه
در فایل
settings.gradleسطح بالای خود، مخزن Maven Google و مخزن مرکزی Maven را در بلوکdependencyResolutionManagementبگنجانید:dependencyResolutionManagement { repositories { google() mavenCentral() } }در فایل ساخت Gradle واحدتان (معمولاً
app/build.gradle)، وابستگیهای خدمات Google Play را برایplay-services-baseوplay-services-tflite-javaاضافه کنید:dependencies { implementation 'com.google.android.gms:play-services-base:18.11.0' implementation 'com.google.android.gms:play-services-tflite-java:16.5.0' }
بررسی دردسترس بودن واحدها
قبلاز اینکه بخواهید واحدی را نصب کنید، میتوانید بررسی کنید که آیا قبلاً در دستگاه نصب شده است یا نه. این کار به شما کمک میکند از درخواستهای نصب غیرضروری جلوگیری کنید.
نمونهای از
ModuleInstallClientرا دریافت کنید:Kotlin
val moduleInstallClient = ModuleInstall.getClient(context)
جاوا
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
بااستفاده از
OptionalModuleApiآن، دردسترس بودن واحد را بررسی کنید. این API توسط کیت توسعه نرمافزار «خدمات Google Play» که استفاده میکنید ارائه میشود.Kotlin
val optionalModuleApi = TfLite.getClient(context) moduleInstallClient .areModulesAvailable(optionalModuleApi) .addOnSuccessListener { if (it.areModulesAvailable()) { // Modules are present on the device... } else { // Modules are not present on the device... } } .addOnFailureListener { // Handle failure... }
جاوا
OptionalModuleApi optionalModuleApi = TfLite.getClient(context); moduleInstallClient .areModulesAvailable(optionalModuleApi) .addOnSuccessListener( response -> { if (response.areModulesAvailable()) { // Modules are present on the device... } else { // Modules are not present on the device... } }) .addOnFailureListener( e -> { // Handle failure… });
درخواست نصب معوق
اگر بلافاصله به واحد نیاز ندارید، میتوانید نصب معوقه درخواست کنید. این کار به «خدمات Google Play» اجازه میدهد تا ماژول را در پسزمینه نصب کند، احتمالاً زمانی که دستگاه غیرفعال است و به Wi-Fi متصل است.
نمونهای از
ModuleInstallClientرا دریافت کنید:Kotlin
val moduleInstallClient = ModuleInstall.getClient(context)
جاوا
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
ارسال درخواست بهتعویقافتاده:
Kotlin
val optionalModuleApi = TfLite.getClient(context) moduleInstallClient.deferredInstall(optionalModuleApi)
جاوا
OptionalModuleApi optionalModuleApi = TfLite.getClient(context); moduleInstallClient.deferredInstall(optionalModuleApi);
درخواست نصب فوری واحد
اگر برنامهتان فوراً به واحد نیاز دارد، میتوانید درخواست نصب فوری کنید. با این کار، واحد در سریعترین زمان ممکن نصب خواهد شد، حتی اگر به این معنی باشد که از داده تلفن همراه استفاده شود.
نمونهای از
ModuleInstallClientرا دریافت کنید:Kotlin
val moduleInstallClient = ModuleInstall.getClient(context)
جاوا
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
(اختیاری)
InstallStatusListenerرا برای نظارت بر پیشرفت نصب ایجاد کنید.اگر میخواهید پیشرفت بارگیری را در میانای کاربر برنامهتان نمایش دهید (برای مثال، با نوار پیشرفت)، میتوانید
InstallStatusListenerایجاد کنید تا بهروزرسانیها را دریافت کنید.Kotlin
inner class ModuleInstallProgressListener : InstallStatusListener { override fun onInstallStatusUpdated(update: ModuleInstallStatusUpdate) { // Progress info is only set when modules are in the progress of downloading. update.progressInfo?.let { val progress = (it.bytesDownloaded * 100 / it.totalBytesToDownload).toInt() // Set the progress for the progress bar. progressBar.setProgress(progress) } if (isTerminateState(update.installState)) { moduleInstallClient.unregisterListener(this) } } fun isTerminateState(@InstallState state: Int): Boolean { return state == STATE_CANCELED || state == STATE_COMPLETED || state == STATE_FAILED } } val listener = ModuleInstallProgressListener()
جاوا
static final class ModuleInstallProgressListener implements InstallStatusListener { @Override public void onInstallStatusUpdated(ModuleInstallStatusUpdate update) { ProgressInfo progressInfo = update.getProgressInfo(); // Progress info is only set when modules are in the progress of downloading. if (progressInfo != null) { int progress = (int) (progressInfo.getBytesDownloaded() * 100 / progressInfo.getTotalBytesToDownload()); // Set the progress for the progress bar. progressBar.setProgress(progress); } // Handle failure status maybe… // Unregister listener when there are no more install status updates. if (isTerminateState(update.getInstallState())) { moduleInstallClient.unregisterListener(this); } } public boolean isTerminateState(@InstallState int state) { return state == STATE_CANCELED || state == STATE_COMPLETED || state == STATE_FAILED; } } InstallStatusListener listener = new ModuleInstallProgressListener();
ModuleInstallRequestرا پیکربندی کنید وOptionalModuleApiرا به درخواست اضافه کنید:Kotlin
val optionalModuleApi = TfLite.getClient(context) val moduleInstallRequest = ModuleInstallRequest.newBuilder() .addApi(optionalModuleApi) // Add more APIs if you would like to request multiple modules. // .addApi(...) // Set the listener if you need to monitor the download progress. // .setListener(listener) .build()
جاوا
OptionalModuleApi optionalModuleApi = TfLite.getClient(context); ModuleInstallRequest moduleInstallRequest = ModuleInstallRequest.newBuilder() .addApi(optionalModuleApi) // Add more API if you would like to request multiple modules //.addApi(...) // Set the listener if you need to monitor the download progress //.setListener(listener) .build();
ارسال درخواست نصب:
Kotlin
moduleInstallClient .installModules(moduleInstallRequest) .addOnSuccessListener { if (it.areModulesAlreadyInstalled()) { // Modules are already installed when the request is sent. } // The install request has been sent successfully. This does not mean // the installation is completed. To monitor the install status, set an // InstallStatusListener to the ModuleInstallRequest. } .addOnFailureListener { // Handle failure… }
جاوا
moduleInstallClient.installModules(moduleInstallRequest) .addOnSuccessListener( response -> { if (response.areModulesAlreadyInstalled()) { // Modules are already installed when the request is sent. } // The install request has been sent successfully. This does not // mean the installation is completed. To monitor the install // status, set an InstallStatusListener to the // ModuleInstallRequest. }) .addOnFailureListener( e -> { // Handle failure... });
آزمایش برنامه با FakeModuleInstallClient
کیتهای توسعه نرمافزار «خدمات Google Play» FakeModuleInstallClient را ارائه میدهد تا به شما امکان دهد
نتایج میاناهای برنامهسازی کاربردی نصب واحد را در آزمایشها بااستفاده از تزریق وابستگی
شبیهسازی کنید. این کار به شما کمک میکند رفتار برنامهتان را در سناریوهای مختلف
بدون نیاز به استقرار آن در دستگاه واقعی آزمایش کنید.
پیشنیازهای برنامه
برنامهتان را پیکربندی کنید تا از چارچوب تزریق وابستگی Hilt استفاده کند.
جایگزین کردن ModuleInstallClient با FakeModuleInstallClient در آزمایش
برای استفاده از FakeModuleInstallClient در آزمایشهایتان، باید پیوند ModuleInstallClient را با پیادهسازی ساختگی جایگزین کنید.
افزودن وابستگی:
در فایل ساخت Gradle واحد (معمولاً
app/build.gradle)، وابستگیهای خدمات Google Play را برایplay-services-base-testingدر آزمایش خود اضافه کنید.dependencies { // other dependencies... testImplementation 'com.google.android.gms:play-services-base-testing:16.2.0' }برای ارائه
ModuleInstallClient، واحد Hilt بسازید:Kotlin
@Module @InstallIn(ActivityComponent::class) object ModuleInstallModule { @Provides fun provideModuleInstallClient( @ActivityContext context: Context ): ModuleInstallClient = ModuleInstall.getClient(context) }
جاوا
@Module @InstallIn(ActivityComponent.class) public class ModuleInstallModule { @Provides public static ModuleInstallClient provideModuleInstallClient( @ActivityContext Context context) { return ModuleInstall.getClient(context); } }
ModuleInstallClientرا در فعالیت تزریق کنید:Kotlin
@AndroidEntryPoint class MyActivity: AppCompatActivity() { @Inject lateinit var moduleInstallClient: ModuleInstallClient ... }
جاوا
@AndroidEntryPoint public class MyActivity extends AppCompatActivity { @Inject ModuleInstallClient moduleInstallClient; ... }
جایگزین کردن اتصال در آزمایش:
Kotlin
@UninstallModules(ModuleInstallModule::class) @HiltAndroidTest class MyActivityTest { ... private val context:Context = ApplicationProvider.getApplicationContext() private val fakeModuleInstallClient = FakeModuleInstallClient(context) @BindValue @JvmField val moduleInstallClient: ModuleInstallClient = fakeModuleInstallClient ... }
جاوا
@UninstallModules(ModuleInstallModule.class) @HiltAndroidTest class MyActivityTest { ... private static final Context context = ApplicationProvider.getApplicationContext(); private final FakeModuleInstallClient fakeModuleInstallClient = new FakeModuleInstallClient(context); @BindValue ModuleInstallClient moduleInstallClient = fakeModuleInstallClient; ... }
شبیهسازی سناریوهای مختلف
با FakeModuleInstallClient میتوانید سناریوهای مختلفی را شبیهسازی کنید، ازجمله:
- پیمانهها قبلاً نصب شدهاند.
- واحدها در دستگاه دردسترس نیستند.
- فرایند نصب ناموفق است.
- درخواست نصب معوق موفقیتآمیز باشد یا ناموفق باشد.
- درخواست نصب فوری موفقیتآمیز باشد یا ناموفق باشد.
Kotlin
@Test fun checkAvailability_available() { // Reset any previously installed modules. fakeModuleInstallClient.reset() val availableModule = TfLite.getClient(context) fakeModuleInstallClient.setInstalledModules(api) // Verify the case where modules are already available... } @Test fun checkAvailability_unavailable() { // Reset any previously installed modules. fakeModuleInstallClient.reset() // Do not set any installed modules in the test. // Verify the case where modules unavailable on device... } @Test fun checkAvailability_failed() { // Reset any previously installed modules. fakeModuleInstallClient.reset() fakeModuleInstallClient.setModulesAvailabilityTask(Tasks.forException(RuntimeException())) // Verify the case where an RuntimeException happened when trying to get module's availability... }
جاوا
@Test public void checkAvailability_available() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); OptionalModuleApi optionalModuleApi = TfLite.getClient(context); fakeModuleInstallClient.setInstalledModules(api); // Verify the case where modules are already available... } @Test public void checkAvailability_unavailable() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); // Do not set any installed modules in the test. // Verify the case where modules unavailable on device... } @Test public void checkAvailability_failed() { fakeModuleInstallClient.setModulesAvailabilityTask(Tasks.forException(new RuntimeException())); // Verify the case where an RuntimeException happened when trying to get module's availability... }
شبیهسازی نتیجه برای درخواست نصب معوق
Kotlin
@Test fun deferredInstall_success() { fakeModuleInstallClient.setDeferredInstallTask(Tasks.forResult(null)) // Verify the case where the deferred install request has been sent successfully... } @Test fun deferredInstall_failed() { fakeModuleInstallClient.setDeferredInstallTask(Tasks.forException(RuntimeException())) // Verify the case where an RuntimeException happened when trying to send the deferred install request... }
جاوا
@Test public void deferredInstall_success() { fakeModuleInstallClient.setDeferredInstallTask(Tasks.forResult(null)); // Verify the case where the deferred install request has been sent successfully... } @Test public void deferredInstall_failed() { fakeModuleInstallClient.setDeferredInstallTask(Tasks.forException(new RuntimeException())); // Verify the case where an RuntimeException happened when trying to send the deferred install request... }
شبیهسازی نتیجه برای درخواست نصب فوری
Kotlin
@Test fun installModules_alreadyExist() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); OptionalModuleApi optionalModuleApi = TfLite.getClient(context); fakeModuleInstallClient.setInstalledModules(api); // Verify the case where the modules already exist when sending the install request... } @Test fun installModules_withoutListener() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); // Verify the case where the urgent install request has been sent successfully... } @Test fun installModules_withListener() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); // Generates a ModuleInstallResponse and set it as the result for installModules(). val moduleInstallResponse = FakeModuleInstallUtil.generateModuleInstallResponse() fakeModuleInstallClient.setInstallModulesTask(Tasks.forResult(moduleInstallResponse)) // Verify the case where the urgent install request has been sent successfully... // Generates some fake ModuleInstallStatusUpdate and send it to listener. val update = FakeModuleInstallUtil.createModuleInstallStatusUpdate( moduleInstallResponse.sessionId, STATE_COMPLETED) fakeModuleInstallClient.sendInstallUpdates(listOf(update)) // Verify the corresponding updates are handled correctly... } @Test fun installModules_failed() { fakeModuleInstallClient.setInstallModulesTask(Tasks.forException(RuntimeException())) // Verify the case where an RuntimeException happened when trying to send the urgent install request... }
جاوا
@Test public void installModules_alreadyExist() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); OptionalModuleApi optionalModuleApi = TfLite.getClient(context); fakeModuleInstallClient.setInstalledModules(api); // Verify the case where the modules already exist when sending the install request... } @Test public void installModules_withoutListener() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); // Verify the case where the urgent install request has been sent successfully... } @Test public void installModules_withListener() { // Reset any previously installed modules. fakeModuleInstallClient.reset(); // Generates a ModuleInstallResponse and set it as the result for installModules(). ModuleInstallResponse moduleInstallResponse = FakeModuleInstallUtil.generateModuleInstallResponse(); fakeModuleInstallClient.setInstallModulesTask(Tasks.forResult(moduleInstallResponse)); // Verify the case where the urgent install request has been sent successfully... // Generates some fake ModuleInstallStatusUpdate and send it to listener. ModuleInstallStatusUpdate update = FakeModuleInstallUtil.createModuleInstallStatusUpdate( moduleInstallResponse.getSessionId(), STATE_COMPLETED); fakeModuleInstallClient.sendInstallUpdates(ImmutableList.of(update)); // Verify the corresponding updates are handled correctly... } @Test public void installModules_failed() { fakeModuleInstallClient.setInstallModulesTask(Tasks.forException(new RuntimeException())); // Verify the case where an RuntimeException happened when trying to send the urgent install request... }