همانطور که در مقاله مروری بر خدمات Google Play توضیح داده شد، SDK های ارائه شده توسط سرویس های Google Play توسط سرویس های روی دستگاه در دستگاه های Android دارای گواهی Google پشتیبانی می شوند. برای حفظ فضای ذخیرهسازی و حافظه در کل ناوگان دستگاهها، برخی از سرویسها بر حسب تقاضا نصب میشوند، زمانی که مشخص باشد دستگاه خاصی به عملکرد مربوطه نیاز دارد. به عنوان مثال، ML Kit این گزینه را هنگام استفاده از مدل ها در سرویس های Google Play فراهم می کند .
رایجترین مورد این است که یک سرویس (یا «ماژول») به موازات برنامهای که به آن نیاز دارد دانلود و نصب میشود، بر اساس یک وابستگی در AndroidManifest.xml
SDK. برای کنترل بیشتر، APIهای نصب ماژول توانایی بررسی صریح در دسترس بودن ماژول، درخواست نصب ماژول، نظارت بر وضعیت درخواست و رسیدگی به خطاها را فراهم می کنند.
برای اطمینان از در دسترس بودن API با ModuleInstallClient
مراحل زیر را دنبال کنید. توجه داشته باشید که قطعه کد زیر از TensorFlow Lite SDK ( play-services-tflite-java
) به عنوان نمونه کتابخانه استفاده می کند، اما این مراحل برای هر کتابخانه ای که با OptionalModuleApi
یکپارچه شده است، قابل اجرا است. این راهنما با اطلاعات اضافی بهروزرسانی میشود، زیرا SDKهای بیشتری پشتیبانی میکنند.
قبل از شروع
برای آماده سازی اپلیکیشن خود، مراحل زیر را انجام دهید.
پیش نیازهای اپلیکیشن
مطمئن شوید که فایل ساخت برنامه شما از مقادیر زیر استفاده می کند:
-
minSdkVersion
19
یا بالاتر
برنامه خود را پیکربندی کنید
در فایل
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.5.0' implementation 'com.google.android.gms:play-services-tflite-java:16.4.0' }
در دسترس بودن ماژول را بررسی کنید
یک نمونه از
ModuleInstallClient
را دریافت کنید:کاتلین
val moduleInstallClient = ModuleInstall.getClient(context)
جاوا
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
در دسترس بودن یک ماژول اختیاری را با استفاده از
OptionalModuleApi
آن بررسی کنید:کاتلین
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… });
یک درخواست نصب معوق ارسال کنید
یک نمونه از
ModuleInstallClient
را دریافت کنید:کاتلین
val moduleInstallClient = ModuleInstall.getClient(context)
جاوا
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
ارسال درخواست معوق:
کاتلین
val optionalModuleApi = TfLite.getClient(context) moduleInstallClient.deferredInstall(optionalModuleApi)
جاوا
OptionalModuleApi optionalModuleApi = TfLite.getClient(context); moduleInstallClient.deferredInstall(optionalModuleApi);
یک درخواست نصب فوری ماژول ارسال کنید
یک نمونه از
ModuleInstallClient
را دریافت کنید:کاتلین
val moduleInstallClient = ModuleInstall.getClient(context)
جاوا
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
(اختیاری) برای مدیریت بهروزرسانیهای وضعیت نصب، یک
InstallStatusListener
ایجاد کنید.اگر میخواهید پیشرفت دانلود را در یک رابط کاربری سفارشیشده (مثلاً نوار پیشرفت) نظارت کنید، میتوانید یک
InstallStatusListener
برای دریافت بهروزرسانیهای وضعیت نصب ایجاد کنید.کاتلین
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
را به درخواست اضافه کنید:کاتلین
val optionalModuleApi = TfLite.getClient(context) val moduleInstallRequest = ModuleInstallRequest.newBuilder() .addApi(optionalModuleApi) // Add more APIs if you would like to request multiple optional 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 optional modules //.addApi(...) // Set the listener if you need to monitor the download progress //.setListener(listener) .build();
ارسال درخواست نصب:
کاتلین
moduleInstallClient .installModules(moduleInstallRequest) .addOnSuccessListener { if (it.areModulesAlreadyInstalled()) { // Modules are already installed when the request is sent. } } .addOnFailureListener { // Handle failure… }
جاوا
moduleInstallClient.installModules(moduleInstallRequest) .addOnSuccessListener( response -> { if (response.areModulesAlreadyInstalled()) { // Modules are already installed when the request is sent. } }) .addOnFailureListener( e -> { // Handle failure... });
تست محلی با FakeModuleInstallClient
SDK خدمات Google Play FakeModuleInstallClient
را ارائه میکند تا به شما امکان میدهد نتایج APIهای نصب ماژول را در آزمایشها با استفاده از تزریق وابستگی شبیهسازی کنید.
پیش نیازهای اپلیکیشن
برنامه خود را برای استفاده از چارچوب تزریق وابستگی Hilt پیکربندی کنید.
در آزمایش، ModuleInstallClient
با FakeModuleInstallClient
جایگزین کنید
افزودن وابستگی:
در فایل ساخت Gradle ماژول خود (معمولا
app/build.gradle
)، وابستگیهای خدمات Google Play را برایplay-services-base-testing
در آزمون خود اضافه کنید.dependencies { // other dependencies... testImplementation 'com.google.android.gms:play-services-base-testing:16.1.0' }
یک ماژول Hilt برای ارائه
ModuleInstallClient
ایجاد کنید:کاتلین
@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
در اکتیویتی تزریق کنید:کاتلین
@AndroidEntryPoint class MyActivity: AppCompatActivity() { @Inject lateinit var moduleInstallClient: ModuleInstallClient ... }
جاوا
@AndroidEntryPoint public class MyActivity extends AppCompatActivity { @Inject ModuleInstallClient moduleInstallClient; ... }
اتصال در تست را جایگزین کنید:
کاتلین
@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; ... }
شبیه سازی در دسترس بودن ماژول
کاتلین
@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... }
نتیجه را برای درخواست نصب معوق شبیه سازی کنید
کاتلین
@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... }
شبیه سازی نتیجه برای درخواست نصب فوری
کاتلین
@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... }