ตามที่อธิบายไว้ในบทความภาพรวมของบริการ Google Play SDK ที่ขับเคลื่อนโดยบริการ Google Play ได้รับการรองรับจากบริการในอุปกรณ์ในอุปกรณ์ Android ที่ผ่านการรับรองจาก Google บริการบางอย่างจะให้บริการเป็นโมดูลที่ติดตั้งเมื่อแอปของคุณต้องใช้ฟังก์ชันการทำงานที่เกี่ยวข้อง เพื่อประหยัดพื้นที่เก็บข้อมูลและหน่วยความจำในอุปกรณ์ทั้งหมด ตัวอย่างเช่น ML Kit มีตัวเลือกนี้เมื่อใช้โมเดลในบริการ Google Play
ในกรณีส่วนใหญ่ SDK บริการ Google Play จะดาวน์โหลดและติดตั้งข้อบังคับที่จำเป็นโดยอัตโนมัติเมื่อแอปของคุณใช้ API ที่ต้องมีข้อบังคับดังกล่าว อย่างไรก็ตาม คุณอาจต้องการควบคุมกระบวนการนี้มากขึ้น เช่น เมื่อต้องการปรับปรุงประสบการณ์ของผู้ใช้ด้วยการติดตั้งข้อบังคับล่วงหน้า
ModuleInstallClient
API ช่วยให้คุณทําสิ่งต่อไปนี้ได้
- ตรวจสอบว่าติดตั้งโมดูลในอุปกรณ์แล้วหรือยัง
- ขอติดตั้งโมดูล
- ตรวจสอบความคืบหน้าในการติดตั้ง
- จัดการข้อผิดพลาดระหว่างกระบวนการติดตั้ง
คู่มือนี้จะแสดงวิธีใช้ 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
) ให้เพิ่มทรัพยากร Dependency ของบริการ Google Play สำหรับplay-services-base
และplay-services-tflite-java
ดังนี้dependencies { implementation 'com.google.android.gms:play-services-base:18.7.0' implementation 'com.google.android.gms:play-services-tflite-java:16.4.0' }
ตรวจสอบว่าโมดูลพร้อมใช้งานหรือไม่
ก่อนที่จะพยายามติดตั้งโมดูล คุณสามารถตรวจสอบว่าอุปกรณ์มีการติดตั้งโมดูลนั้นอยู่แล้วหรือไม่ วิธีนี้จะช่วยหลีกเลี่ยงคำขอการติดตั้งที่ไม่จำเป็น
รับอินสแตนซ์ของ
ModuleInstallClient
Kotlin
val moduleInstallClient = ModuleInstall.getClient(context)
Java
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
ตรวจสอบความพร้อมใช้งานของข้อบังคับโดยใช้
OptionalModuleApi
API นี้มาจาก SDK บริการ 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... }
Java
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)
Java
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
ส่งคำขอที่เลื่อนเวลาไว้ โดยทำดังนี้
Kotlin
val optionalModuleApi = TfLite.getClient(context) moduleInstallClient.deferredInstall(optionalModuleApi)
Java
OptionalModuleApi optionalModuleApi = TfLite.getClient(context); moduleInstallClient.deferredInstall(optionalModuleApi);
ขอติดตั้งโมดูลอย่างเร่งด่วน
หากแอปต้องใช้โมดูลทันที คุณสามารถขอติดตั้งแบบเร่งด่วนได้ ซึ่งจะพยายามติดตั้งโมดูลให้เร็วที่สุด แม้ว่าจะต้องใช้อินเทอร์เน็ตมือถือก็ตาม
รับอินสแตนซ์ของ
ModuleInstallClient
Kotlin
val moduleInstallClient = ModuleInstall.getClient(context)
Java
ModuleInstallClient moduleInstallClient = ModuleInstall.getClient(context);
(ไม่บังคับ) สร้าง
InstallStatusListener
เพื่อตรวจสอบความคืบหน้าในการติดตั้งหากต้องการแสดงความคืบหน้าในการดาวน์โหลดใน UI ของแอป (เช่น ใช้แถบความคืบหน้า) คุณสามารถสร้าง
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()
Java
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()
Java
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… }
Java
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
SDK บริการ Google Play มี FakeModuleInstallClient
ให้คุณจำลองผลลัพธ์ของ API การติดตั้งโมดูลในการทดสอบโดยใช้การแทรกพึ่งพา ซึ่งจะช่วยให้คุณทดสอบลักษณะการทํางานของแอปในสถานการณ์ต่างๆ ได้โดยไม่ต้องติดตั้งใช้งานในอุปกรณ์จริง
ข้อกําหนดเบื้องต้นของแอป
กำหนดค่าแอปให้ใช้เฟรมเวิร์กการฉีดข้อมูล Dependency ของ Hilt
แทนที่ ModuleInstallClient
ด้วย FakeModuleInstallClient
ในการทดสอบ
หากต้องการใช้ FakeModuleInstallClient
ในการทดสอบ คุณต้องแทนที่การเชื่อมโยง ModuleInstallClient
ด้วยการติดตั้งใช้งานจำลอง
เพิ่มการพึ่งพา
ในไฟล์บิลด์ Gradle ของโมดูล (โดยปกติคือ
app/build.gradle
) ให้เพิ่มทรัพยากร Dependency ของบริการ Google Play สำหรับplay-services-base-testing
ในการทดสอบdependencies { // other dependencies... testImplementation 'com.google.android.gms:play-services-base-testing:16.1.0' }
สร้างโมดูล Hilt เพื่อให้บริการ
ModuleInstallClient
Kotlin
@Module @InstallIn(ActivityComponent::class) object ModuleInstallModule { @Provides fun provideModuleInstallClient( @ActivityContext context: Context ): ModuleInstallClient = ModuleInstall.getClient(context) }
Java
@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 ... }
Java
@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 ... }
Java
@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... }
Java
@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... }
Java
@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... }
Java
@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... }