โมดูลฟีเจอร์ช่วยให้คุณแยกฟีเจอร์และทรัพยากรบางอย่างได้ จากโมดูลฐานของแอปและรวมไว้ใน App Bundle ผ่าน การนำส่งฟีเจอร์ Play เป็นต้น ว่าผู้ใช้สามารถดาวน์โหลดและติดตั้ง คอมโพเนนต์ตามคำขอหลังจากติดตั้ง APK พื้นฐานของแอปของคุณแล้ว
ตัวอย่างเช่น ลองพิจารณาแอปรับส่งข้อความที่มีฟังก์ชัน จับภาพและส่งข้อความรูปภาพ แต่มีผู้ใช้เพียงส่วนน้อย ส่งข้อความรูปภาพ การใส่ข้อความด้วยรูปภาพว่าเป็น โมดูลฟีเจอร์ที่ดาวน์โหลดได้ วิธีนี้จะทำให้การดาวน์โหลดแอปเริ่มต้น จะเล็กลงสำหรับผู้ใช้ทั้งหมด และเฉพาะผู้ใช้ที่ส่งข้อความภาพเท่านั้นที่ต้อง ดาวน์โหลดคอมโพเนนต์เพิ่มเติมนั้น
โปรดจำไว้ว่าการแยกส่วนประเภทนี้ต้องใช้ความพยายามมากขึ้น และ การเปลี่ยนโครงสร้างภายในโค้ดที่มีอยู่ของแอปคุณ ดังนั้นควรพิจารณาอย่างรอบคอบว่าโค้ดใด ฟีเจอร์ของแอปจะได้รับประโยชน์มากที่สุดเมื่อพร้อมให้บริการแก่ผู้ใช้แบบออนดีมานด์ เพื่อให้เข้าใจกรณีการใช้งานและหลักเกณฑ์ที่เหมาะสมที่สุดสำหรับฟีเจอร์ออนดีมานด์ อ่านแนวทางปฏิบัติแนะนำสำหรับ UX สำหรับการนำส่งตามคำขอ
หากต้องการค่อยๆ ทำให้ฟีเจอร์ของแอปค่อยๆ แยกเป็นส่วนๆ เมื่อเวลาผ่านไป เปิดใช้ตัวเลือกการแสดงโฆษณาขั้นสูง เช่น การนำส่งตามคำขอแทน กำหนดค่าการนำส่งเวลาติดตั้ง
หน้านี้จะช่วยคุณเพิ่มโมดูลฟีเจอร์ลงในโปรเจ็กต์แอปและ กำหนดค่าสำหรับการแสดงโฆษณาแบบออนดีมานด์ ก่อนเริ่มต้น โปรดตรวจสอบว่าคุณ ใช้ Android Studio 3.5 ขึ้นไปและปลั๊กอิน Android Gradle 3.5.0 หรือสูงกว่า
กำหนดค่าโมดูลใหม่สำหรับการแสดงโฆษณาแบบออนดีมานด์
วิธีที่ง่ายที่สุดในการสร้างโมดูลฟีเจอร์ใหม่คือการใช้ Android Studio 3.5 ขึ้นไป เนื่องจากโมดูลฟีเจอร์มี การขึ้นต่อกันโดยธรรมชาติของโมดูลแอปพื้นฐาน คุณจะสามารถเพิ่มโมดูลเหล่านั้นลงใน โปรเจ็กต์ของแอป
วิธีเพิ่มโมดูลฟีเจอร์ลงในโปรเจ็กต์แอปโดยใช้ Android Studio โดยทำตามขั้นตอนต่อไปนี้
- เปิดโปรเจ็กต์แอปใน IDE หากยังไม่ได้เปิด
- เลือก ไฟล์ > ใหม่ > โมดูลใหม่จากแถบเมนู
- ในกล่องโต้ตอบสร้างโมดูลใหม่ ให้เลือก Dynamic Feature Module แล้วคลิก Next
- ในส่วนกำหนดค่าโมดูลใหม่ ให้กรอก
ดังต่อไปนี้:
- เลือกโมดูลแอปพลิเคชันพื้นฐานสำหรับโปรเจ็กต์แอปจาก เมนูแบบเลื่อนลง
- ระบุชื่อโมดูล IDE ใช้ชื่อนี้เพื่อระบุ
เป็นโปรเจ็กต์ย่อย Gradle ใน
ไฟล์การตั้งค่า Gradle เมื่อคุณ
สร้าง App Bundle โดย Gradle จะใช้องค์ประกอบสุดท้ายของโปรเจ็กต์ย่อย
ชื่อที่จะแทรกแอตทริบิวต์
<manifest split>
ใน ไฟล์ Manifest ของโมดูลฟีเจอร์ - ระบุชื่อแพ็กเกจของโมดูล โดยค่าเริ่มต้น Android Studio แนะนำชื่อแพ็กเกจที่รวมชื่อแพ็กเกจรูทของ โมดูลฐานและชื่อโมดูลที่คุณระบุไว้ในขั้นตอนก่อนหน้า
- เลือกระดับ API ขั้นต่ำที่คุณต้องการให้โมดูลรองรับ ค่านี้ควรตรงกับของโมดูลฐาน
- คลิกถัดไป
ในส่วนตัวเลือกการดาวน์โหลดโมดูล ให้กรอกข้อมูลต่อไปนี้
ระบุชื่อโมดูลโดยใช้อักขระได้สูงสุด 50 ตัว แพลตฟอร์ม ใช้ชื่อนี้เพื่อระบุโมดูลให้ผู้ใช้ได้ เช่น ในกรณีที่ เพื่อยืนยันว่าผู้ใช้ต้องการดาวน์โหลดโมดูลหรือไม่ สำหรับกรณีนี้ โมดูลฐานของแอปคุณต้องมีชื่อโมดูลเป็น สตริงทรัพยากร ซึ่งคุณ แปลได้ เมื่อสร้างโมดูลโดยใช้ Android Studio, IDE เพิ่มทรัพยากรสตริงลงในโมดูลฐานให้คุณ และแทรกพารามิเตอร์ รายการต่อไปนี้ในไฟล์ Manifest ของโมดูลฟีเจอร์
<dist:module ... dist:title="@string/feature_title"> </dist:module>
ในเมนูแบบเลื่อนลงภายใต้การรวมเวลาติดตั้ง ให้เลือกไม่ต้อง รวมโมดูล ณ เวลาติดตั้ง Android Studio จะแทรก ต่อไปนี้ในไฟล์ Manifest ของโมดูลเพื่อให้สอดคล้องกับตัวเลือกของคุณ
<dist:module ... > <dist:delivery> <dist:on-demand/> </dist:delivery> </dist:module>
เลือกช่อง Fusing หากต้องการให้โมดูลนี้พร้อมใช้งาน สำหรับอุปกรณ์ที่ใช้ Android 4.4 (API ระดับ 20) และต่ำกว่า และรวมอยู่ใน APK หลายรายการ ซึ่งหมายความว่าคุณเปิดใช้ลักษณะการทำงานแบบออนดีมานด์สำหรับโมดูลนี้ได้ และปิดใช้การฟิวชันเพื่อยกเว้นการฟิวชันจากอุปกรณ์ที่ไม่รองรับ การดาวน์โหลดและติดตั้ง APK แยกส่วน Android Studio จะแทรก ต่อไปนี้ในไฟล์ Manifest ของโมดูลเพื่อแสดงตัวเลือกของคุณ
<dist:module ...> <dist:fusing dist:include="true | false" /> </dist:module>
คลิกเสร็จสิ้น
หลังจากที่ Android Studio สร้างโมดูลเสร็จแล้ว ให้ตรวจสอบเนื้อหา เองจากแผงโปรเจ็กต์ (เลือกมุมมอง > หน้าต่างเครื่องมือ > โปรเจ็กต์ จากแถบเมนู) โค้ด ทรัพยากร และองค์กรเริ่มต้นควรเป็น คล้ายกับโมดูลแอปมาตรฐาน
ต่อไป คุณจะต้องใช้ฟังก์ชันการติดตั้งแบบออนดีมานด์โดยใช้ไลบรารีการนำส่งฟีเจอร์ Play
รวมไลบรารีการนำส่งฟีเจอร์ Play ไว้ในโปรเจ็กต์ของคุณ
ก่อนที่คุณจะเริ่มต้น คุณต้อง เพิ่มไลบรารีการนำส่งฟีเจอร์ Play ลงในโปรเจ็กต์ของคุณ
ขอโมดูลออนดีมานด์
เมื่อแอปของคุณต้องใช้โมดูลฟีเจอร์ แอปจะขอโมดูลได้
อยู่เบื้องหน้าผ่านทาง
SplitInstallManager
เมื่อสร้าง
แอปของคุณจำเป็นต้องระบุชื่อโมดูลตามที่กำหนดโดย
องค์ประกอบ split
ในไฟล์ Manifest ของโมดูลเป้าหมาย เมื่อคุณ
สร้างโมดูลฟีเจอร์
เมื่อใช้ Android Studio ระบบบิลด์จะใช้ชื่อโมดูลที่คุณระบุ
เพื่อแทรกคุณสมบัตินี้ลงในไฟล์ Manifest ของโมดูลในเวลาคอมไพล์
สำหรับข้อมูลเพิ่มเติม โปรดอ่านเกี่ยวกับ
ไฟล์ Manifest ของโมดูลฟีเจอร์
ตัวอย่างเช่น ลองพิจารณาแอปที่มีโมดูลออนดีมานด์เพื่อบันทึกและส่ง
ข้อความภาพโดยใช้กล้องของอุปกรณ์ และโมดูลนี้แบบออนดีมานด์
ระบุ split="pictureMessages"
ในไฟล์ Manifest
ตัวอย่างต่อไปนี้ใช้ SplitInstallManager
เพื่อขอ pictureMessages
โมดูล (พร้อมด้วยโมดูลเพิ่มเติมสำหรับตัวกรองโปรโมชันบางรายการ):
Kotlin
// 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 -> ... }
Java
// 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 จะอัปเดตอยู่เสมอ โดยอัตโนมัติ กล่าวคือ เมื่อคุณอัปโหลด App Bundle เวอร์ชันใหม่ แพลตฟอร์ม อัปเดต APK ที่ติดตั้งไว้ทั้งหมดซึ่งเป็นของแอปคุณ สำหรับข้อมูลเพิ่มเติม โปรดอ่าน จัดการการอัปเดตแอป
หากต้องการเข้าถึงโค้ดและทรัพยากรของโมดูล แอปของคุณจะต้อง เปิดใช้ SplitCompat โปรดทราบว่า SplitCompat ที่จำเป็นสำหรับ Android Instant Apps
เลื่อนการติดตั้งโมดูลออนดีมานด์
หากคุณไม่ต้องการให้แอปของคุณดาวน์โหลดและติดตั้งแบบออนดีมานด์ได้ทันที คุณสามารถเลื่อนการติดตั้งเมื่อแอปอยู่ในเบื้องหลังได้ สำหรับ ตัวอย่างเช่น หากคุณต้องการโหลดเนื้อหาส่งเสริมการขาย เพื่อการเปิดตัวในภายหลัง แอปของคุณ
คุณสามารถระบุโมดูลที่จะดาวน์โหลดในภายหลังโดยใช้
deferredInstall()
ตามที่แสดงด้านล่าง และที่ต่างจาก
SplitInstallManager.startInstall()
แอปของคุณไม่จำเป็นต้องอยู่เบื้องหน้าเพื่อเริ่มการส่งคำขอ
การติดตั้งที่ถูกเลื่อนเวลา
Kotlin
// 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"))
Java
// 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()
แบบไม่พร้อมกัน
ก่อนที่คุณจะเริ่มรับการอัปเดตสำหรับคำขอติดตั้ง ให้ลงทะเบียน
Listener และรับรหัสเซสชันของคำขอตามที่แสดงด้านล่าง
Kotlin
// 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)
Java
// 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 Store สำหรับคำแนะนำเกี่ยวกับวิธีรับมือกับสถานการณ์เหล่านี้ ในมุมมองของผู้ใช้ ดูที่ หลักเกณฑ์ UX สำหรับการนำส่งตามคำขอ
ตามโค้ด คุณควรจัดการกับความล้มเหลวในการดาวน์โหลดหรือการติดตั้งโมดูล
โดยใช้ addOnFailureListener()
ดังที่แสดงด้านล่าง
Kotlin
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. } } } } }
Java
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 | คำขอถูกปฏิเสธเนื่องจากมีคำขออยู่แล้วอย่างน้อย 1 รายการ คำขอที่กำลังดาวน์โหลด | ตรวจสอบว่ามีคำขอใดที่ยังคงดาวน์โหลดอยู่ ดังที่แสดง ในตัวอย่างข้างต้น |
MODULE_ไม่มีให้บริการ | Google Play ไม่พบโมดูลที่ขอตาม ในแอป อุปกรณ์ และ Google Play ของผู้ใช้ในเวอร์ชันที่ติดตั้งในปัจจุบัน ของคุณได้ | หากผู้ใช้ไม่มีสิทธิ์เข้าถึงโมดูลนี้ โปรดแจ้งให้ผู้ใช้ทราบ |
INVALID_REQUEST | Google Play ได้รับคำขอ แต่คำขอดังกล่าว ไม่ได้ | ยืนยันว่าข้อมูลในคำขอ สมบูรณ์และถูกต้อง |
SESSION_NOT_FOUND | ไม่พบเซสชันสำหรับรหัสเซสชันที่ระบุ | หากคุณกำลังพยายามตรวจสอบสถานะของคำขอ ตามรหัสเซสชัน ให้ตรวจสอบว่ารหัสเซสชันถูกต้อง |
API_ไม่พร้อมใช้งาน | อุปกรณ์ปัจจุบันไม่รองรับไลบรารีการนำส่งฟีเจอร์ Play นั่นคือ อุปกรณ์จะไม่สามารถดาวน์โหลดและติดตั้งได้ ฟีเจอร์ตามคำขอได้ | สำหรับอุปกรณ์ที่ใช้ Android 4.4 (API ระดับ 20) หรือต่ำกว่า คุณควร
รวมโมดูลฟีเจอร์ ณ เวลาติดตั้งโดยใช้
พร็อพเพอร์ตี้ไฟล์ Manifest dist:fusing หากต้องการเรียนรู้เพิ่มเติม โปรดอ่านเกี่ยวกับ
ไฟล์ Manifest ของโมดูลฟีเจอร์
|
NETWORK_ERROR | คำขอล้มเหลวเนื่องจากข้อผิดพลาดเกี่ยวกับเครือข่าย | แจ้งให้ผู้ใช้สร้างการเชื่อมต่อเครือข่าย หรือเปลี่ยนไปใช้เครือข่ายอื่น |
ACCESS_DENIED (ปฏิเสธการเข้าถึง) | แอปลงทะเบียนคำขอไม่ได้เนื่องจากมีสิทธิ์ไม่เพียงพอ | กรณีนี้มักเกิดขึ้นเมื่อแอปอยู่ในเบื้องหลัง พยายามส่งคำขอเมื่อแอปกลับไปอยู่ที่เบื้องหน้า |
เข้ากันไม่ได้กับเซสชันที่มีอยู่ | คำขอมีโมดูลอย่างน้อยหนึ่งโมดูลที่ ส่งคำขอแล้วแต่ยังไม่ได้ติดตั้ง | สร้างคำขอใหม่ที่ไม่รวมโมดูลที่
ได้ขอแอปพลิเคชันแล้ว หรือรอโมดูลที่ขอทั้งหมดในปัจจุบัน
ติดตั้งให้เสร็จก่อนที่จะลองส่งคำขออีกครั้ง
โปรดทราบว่าการขอโมดูล ติดตั้งไม่ได้แก้ข้อผิดพลาด |
ใช้บริการ | บริการที่รับผิดชอบการจัดการคำขอหยุดทำงาน | ลองส่งคำขออีกครั้ง
|
พื้นที่จัดเก็บไม่เพียงพอ | อุปกรณ์มีพื้นที่เก็บข้อมูลไม่เพียงพอที่จะติดตั้งฟีเจอร์ | แจ้งผู้ใช้ว่าพวกเขามีพื้นที่เก็บข้อมูลไม่เพียงพอสำหรับการติดตั้งแอปนี้ |
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR | SplitCompat โหลดโมดูลฟีเจอร์ไม่ได้ | ข้อผิดพลาดเหล่านี้ควรได้รับการแก้ไขโดยอัตโนมัติหลังจากแอปถัดไป รีสตาร์ท |
Play_STORE_NOT_FOUND | อุปกรณ์ไม่ได้ติดตั้งแอป Play Store | แจ้งให้ผู้ใช้ทราบว่าจำเป็นต้องดาวน์โหลดแอป Play Store |
แอปไม่ได้เป็นเจ้าของ | แอปนี้ยังไม่ได้รับการติดตั้งโดย Google Play และฟีเจอร์ไม่สามารถ ดาวน์โหลดแล้ว ข้อผิดพลาดนี้อาจเกิดขึ้นกับการติดตั้งที่มีการเลื่อนเวลาเท่านั้น | ถ้าคุณต้องการให้ผู้ใช้ดาวน์โหลดแอปจาก Google Play ให้ใช้
startInstall() ซึ่งสามารถรับข้อมูลที่จำเป็น
การยืนยันผู้ใช้ |
ข้อผิดพลาดภายใน | เกิดข้อผิดพลาดภายใน Play Store | ลองส่งคำขออีกครั้ง |
หากผู้ใช้ขอดาวน์โหลดโมดูลออนดีมานด์และเกิดข้อผิดพลาด ลองแสดงกล่องโต้ตอบที่มี 2 ตัวเลือกสำหรับผู้ใช้ ดังนี้ อีกครั้ง (ซึ่งพยายามส่งคำขออีกครั้ง) และยกเลิก (ซึ่งยกเลิก คำขอ) หากต้องการการสนับสนุนเพิ่มเติม คุณควรระบุลิงก์ความช่วยเหลือที่ จะนำผู้ใช้ไปยังส่วน ศูนย์ช่วยเหลือของ Google Play
จัดการการอัปเดตสถานะ
หลังจากที่คุณลงทะเบียน Listener และบันทึกรหัสเซสชันสำหรับคำขอของคุณแล้ว
ใช้ StateUpdatedListener.onStateUpdate()
เพื่อรับมือกับการเปลี่ยนแปลงสถานะ ดังที่แสดงด้านล่าง
Kotlin
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. } } } }
Java
@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. } } }
สถานะที่เป็นไปได้สำหรับคำขอติดตั้งอธิบายไว้ในตารางด้านล่าง
สถานะคำขอ | คำอธิบาย | การดำเนินการที่แนะนำ |
---|---|---|
รอดำเนินการ | คำขอได้รับการยอมรับและ การดาวน์โหลดควรเริ่มต้นในไม่ช้า | เริ่มต้นคอมโพเนนต์ UI เช่น แถบความคืบหน้า เพื่อให้ความคิดเห็นแก่ผู้ใช้เกี่ยวกับการดาวน์โหลด |
ต้องมีการยืนยันผู้ใช้ | ผู้ใช้ต้องยืนยันการดาวน์โหลด โดยส่วนใหญ่ สถานะนี้จะเกิดขึ้นหากไม่ได้ติดตั้งแอปผ่าน Google Play | แจ้งให้ผู้ใช้ยืนยันการดาวน์โหลดฟีเจอร์ผ่าน Google Play ดูข้อมูลเพิ่มเติมได้ที่ส่วน "วิธี" รับการยืนยันจากผู้ใช้ |
การดาวน์โหลด | อยู่ระหว่างการดาวน์โหลด | หากคุณระบุแถบความคืบหน้าสำหรับการดาวน์โหลด ให้ใช้
SplitInstallSessionState.bytesDownloaded()
และ SplitInstallSessionState.totalBytesToDownload()
วิธีการอัปเดต UI (ดูตัวอย่างโค้ดเหนือตารางนี้) |
ดาวน์โหลดแล้ว | อุปกรณ์ดาวน์โหลดโมดูลแล้ว แต่ยังไม่ได้เริ่มการติดตั้ง | แอปควรเปิดใช้ SplitCompat มีสิทธิ์เข้าถึงโมดูลที่ดาวน์โหลด และหลีกเลี่ยงสถานะนี้ ซึ่งจำเป็นต่อการเข้าถึงโค้ดของโมดูลฟีเจอร์และ ที่ไม่ซับซ้อน |
กำลังติดตั้ง | อุปกรณ์กำลังติดตั้งโมดูลอยู่ในขณะนี้ | อัปเดตแถบความคืบหน้า รัฐนี้มักสั้น |
ติดตั้งแล้ว | โมดูลติดตั้งอยู่ในอุปกรณ์แล้ว | รหัสการเข้าถึงและทรัพยากรในโมดูล
ในการดำเนินการต่อของผู้ใช้
หากโมดูลมีไว้สำหรับ Android Instant App ที่ทำงานใน Android 8.0 (API ระดับ 26)
หรือสูงกว่า คุณต้องใช้ |
FAILED | คำขอล้มเหลวก่อนที่โมดูลจะ ที่ติดตั้งบนอุปกรณ์ | แจ้งให้ผู้ใช้ลองส่งคำขออีกครั้งหรือยกเลิกคำขอ |
กำลังยกเลิก | อุปกรณ์อยู่ระหว่างการยกเลิกคำขอ | ดูข้อมูลเพิ่มเติมได้ที่ส่วน "วิธี" ยกเลิกคำขอติดตั้ง |
ยกเลิก | ยกเลิกคำขอแล้ว |
รับการยืนยันจากผู้ใช้
ในบางกรณี Google Play อาจต้องการการยืนยันจากผู้ใช้ก่อนที่จะดำเนินการตาม
คำขอดาวน์โหลด เช่น หาก Google ไม่ได้ติดตั้งแอปของคุณ
เล่นหรือคุณกำลังพยายามดาวน์โหลดข้อมูลขนาดใหญ่ผ่านอินเทอร์เน็ตมือถือ ในกรณีดังกล่าว
สถานะสำหรับรายงานคำขอ REQUIRES_USER_CONFIRMATION
และแอปของคุณ
ต้องได้รับการยืนยันจากผู้ใช้ก่อน อุปกรณ์จึงจะสามารถดาวน์โหลดและ
ให้ติดตั้งโมดูลในคำขอ หากต้องการการยืนยัน แอปของคุณควร
แจ้งให้ผู้ใช้ทราบดังนี้
Kotlin
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) } ... }
Java
@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
แอปสามารถแสดงข้อความแจ้งผู้ใช้อีกครั้งเพื่อให้คำขอเสร็จสมบูรณ์
หากต้องการได้รับการติดต่อกลับพร้อมคำตอบของผู้ใช้ คุณสามารถลบล้าง Activityผลลัพธ์Callback ดังที่แสดงด้านล่าง
Kotlin
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. } }
Java
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()
โดยใช้รหัสเซสชันของคําขอดังที่แสดงด้านล่าง
Kotlin
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId)
Java
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId);
โมดูลการเข้าถึง
หากต้องการเข้าถึงโค้ดและทรัพยากรจากโมดูลที่ดาวน์โหลดหลังจากดาวน์โหลดแล้ว แอปของคุณต้องเปิดใช้ ไลบรารี SplitCompat สำหรับทั้งแอปและแต่ละกิจกรรมในโมดูลฟีเจอร์ของแอป ดาวน์โหลด
อย่างไรก็ตาม คุณควรทราบว่าแพลตฟอร์มมีลักษณะต่อไปนี้ การจํากัดการเข้าถึงเนื้อหาของโมดูลไปสักระยะหนึ่ง (หลายวัน บางวัน กรณี) หลังจากดาวน์โหลดโมดูล:
- แพลตฟอร์มนี้จะไม่สามารถใช้รายการไฟล์ Manifest ใหม่ๆ ที่โมดูลแนะนำได้
- แพลตฟอร์มไม่สามารถเข้าถึงทรัพยากรของโมดูลสำหรับคอมโพเนนต์ UI ของระบบ เช่น การแจ้งเตือน หากคุณต้องการใช้ทรัพยากรดังกล่าวทันที โปรดพิจารณา รวมถึงทรัพยากรเหล่านั้นในโมดูลฐานของแอป
เปิดใช้ SplitCompat
เพื่อให้แอปเข้าถึงโค้ดและทรัพยากรจากโมดูลที่ดาวน์โหลดไว้ได้ คุณต้องเปิดใช้งาน SplitCompat โดยใช้วิธีใดวิธีหนึ่งที่อธิบายไว้ใน ส่วนต่างๆ ต่อไปนี้
หลังจากเปิดใช้ SplitCompat สำหรับแอปแล้ว คุณจะต้องเปิดใช้ SplitCompat ด้วย สำหรับแต่ละกิจกรรมในโมดูลฟีเจอร์ที่คุณ ที่ต้องการให้แอปของคุณเข้าถึงได้
ประกาศ SplitCompatApplication ในไฟล์ Manifest
วิธีที่ง่ายที่สุดในการเปิดใช้ SplitCompat คือการประกาศ SplitCompatApplication
เป็นคลาสย่อย Application
ใน
ไฟล์ Manifest ของแอปตามที่แสดงด้านล่าง
<application
...
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>
หลังจากติดตั้งแอปในอุปกรณ์แล้ว คุณสามารถเข้าถึงรหัสและทรัพยากรได้จาก โมดูลฟีเจอร์ที่ดาวน์โหลดโดยอัตโนมัติ
เรียกใช้ SplitCompat ขณะรันไทม์
คุณยังเปิดใช้ SplitCompat ในกิจกรรมหรือบริการที่เฉพาะเจาะจงขณะรันไทม์ได้ด้วย
การเปิดใช้ SplitCompat ด้วยวิธีนี้จำเป็นต่อการเปิดตัวกิจกรรมที่รวมอยู่ใน
โมดูลฟีเจอร์ โดยให้ลบล้าง attachBaseContext
ดังที่แสดงด้านล่าง
หากคุณมีคลาสแอปพลิเคชันที่กำหนดเอง
ให้ใช้ส่วนขยายแทน
SplitCompatApplication
เพื่อเปิดใช้ SplitCompat สำหรับแอปของคุณดังที่แสดงด้านล่าง
Kotlin
class MyApplication : SplitCompatApplication() { ... }
Java
public class MyApplication extends SplitCompatApplication { ... }
SplitCompatApplication
จะลบล้าง ContextWrapper.attachBaseContext()
เพื่อรวม SplitCompat.install(Context applicationContext)
หากไม่
ต้องการให้ชั้นเรียน Application
ของคุณ
ขยาย SplitCompatApplication
คุณสามารถลบล้าง attachBaseContext()
ด้วยตนเองดังนี้
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this); }
หากโมดูลออนดีมานด์ของคุณใช้งานร่วมกันได้ สำหรับทั้ง Instant App และแอปที่ติดตั้ง คุณสามารถเรียกใช้ SplitCompat ตามเงื่อนไขดังต่อไปนี้
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this) } }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this); } }
เปิดใช้ SplitCompat สำหรับกิจกรรมโมดูล
หลังจากเปิดใช้ SplitCompat สำหรับแอปพื้นฐานแล้ว คุณจะต้องเปิดใช้ SplitCompat
สำหรับแต่ละกิจกรรมที่แอปของคุณดาวน์โหลดในโมดูลฟีเจอร์ โดยดำเนินการดังนี้
ให้ใช้เมธอด SplitCompat.installActivity()
ดังนี้
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this); }
เข้าถึงคอมโพเนนต์ที่กำหนดไว้ในโมดูลฟีเจอร์
เริ่มกิจกรรมที่กำหนดไว้ในโมดูลฟีเจอร์
คุณสามารถเปิดใช้งานกิจกรรมที่กำหนดไว้ในโมดูลฟีเจอร์ได้โดยใช้
startActivity()
หลังจากเปิดใช้ SplitCompat
Kotlin
startActivity(Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...))
Java
startActivity(new Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...));
พารามิเตอร์แรกที่ส่งไปยัง setClassName
คือชื่อแพ็กเกจของแอปและ
พารามิเตอร์ที่ 2 คือชื่อเต็มของกิจกรรม
เมื่อมีกิจกรรมในโมดูลฟีเจอร์ที่ดาวน์โหลดแบบออนดีมานด์ คุณต้อง เปิดใช้ SplitCompat ในกิจกรรม
เริ่มบริการที่กำหนดไว้ในโมดูลฟีเจอร์
คุณสามารถเปิดใช้งานบริการที่กำหนดไว้ในโมดูลฟีเจอร์ได้โดยใช้
startService()
หลังจากเปิดใช้ SplitCompat
Kotlin
startService(Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...))
Java
startService(new Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...));
ส่งออกคอมโพเนนต์ที่กำหนดไว้ในโมดูลฟีเจอร์
คุณไม่ควรรวมคอมโพเนนต์ Android ที่ส่งออกไว้ภายในโมดูลที่ไม่บังคับ
ระบบบิลด์จะรวมรายการไฟล์ Manifest ของโมดูลทั้งหมดลงในโมดูลฐาน หากโมดูลที่ไม่บังคับมีคอมโพเนนต์ที่ส่งออก ก่อนที่จะมีการติดตั้งโมดูลและอาจทำให้เกิดข้อขัดข้องเนื่องจากโค้ดขาดหายไป เมื่อเรียกใช้จากแอปอื่น
นี่ไม่ใช่ปัญหาสำหรับคอมโพเนนต์ภายใน วิดีโอเหล่านั้นจะเข้าถึงได้เฉพาะ เพื่อให้แอปสามารถ ตรวจสอบว่ามีการติดตั้งโมดูลแล้วก่อนที่จะเข้าถึง คอมโพเนนต์
หากคุณต้องการคอมโพเนนต์ที่ส่งออก และต้องการให้เนื้อหาของคอมโพเนนต์เป็นคอมโพเนนต์ที่ไม่บังคับ
ให้พิจารณาใช้รูปแบบพร็อกซี
ซึ่งทำได้โดยการเพิ่มคอมโพเนนต์ที่ส่งออกพร็อกซีในฐาน
เมื่อเข้าถึง คอมโพเนนต์พร็อกซีจะสามารถตรวจสอบการมีอยู่ของโมดูลที่
มีเนื้อหาดังกล่าว หากมีโมดูลอยู่ พร็อกซี
สามารถเริ่มต้นคอมโพเนนต์ภายในจากโมดูลผ่านทาง Intent
เป็นการส่งต่อความตั้งใจจากแอปผู้โทร หากไม่มีโมดูลดังกล่าว
คอมโพเนนต์สามารถดาวน์โหลดโมดูลหรือส่งกลับข้อความแสดงข้อผิดพลาดที่เหมาะสมไปยัง
แอปผู้โทร
เข้าถึงโค้ดและทรัพยากรจากโมดูลที่ติดตั้งไว้
หากเปิดใช้ SplitCompat สำหรับฐานของคุณ แอปพลิเคชันและกิจกรรมในโมดูลคุณลักษณะของคุณ คุณสามารถใช้ โค้ดและทรัพยากรจากโมดูลฟีเจอร์ราวกับว่าเป็นส่วนหนึ่งของ APK พื้นฐาน เมื่อติดตั้งโมดูลที่ไม่บังคับแล้ว
รหัสการเข้าถึงจากโมดูลอื่น
เข้าถึงโค้ดพื้นฐานจากโมดูล
โมดูลอื่นสามารถใช้โค้ดที่อยู่ภายในโมดูลฐานได้โดยตรง คุณไม่จำเป็นต้องทำอะไรพิเศษ เพียงนำเข้าและใช้ชั้นเรียนที่คุณต้องการ
เข้าถึงโค้ดโมดูลจากโมดูลอื่น
วัตถุหรือคลาสภายในโมดูลไม่สามารถเข้าถึงแบบคงที่จากวัตถุหรือคลาสอื่น โดยตรง แต่ก็เข้าถึงได้โดยอ้อมโดยใช้การสะท้อนความรู้สึก
คุณควรระวังว่าปัญหานี้เกิดขึ้นบ่อยเพียงใด เนื่องจากค่าใช้จ่ายด้านประสิทธิภาพ ของการสะท้อนความรู้สึก สำหรับกรณีการใช้งานที่ซับซ้อน ให้ใช้เฟรมเวิร์กการแทรกทรัพยากร Dependency เช่น เครื่องหมาย 2 เพื่อรับประกันการเรียกสะท้อนกลับ 1 ครั้งต่อ อายุการใช้งานของแอปพลิเคชัน
หากต้องการลดความซับซ้อนของการโต้ตอบกับออบเจ็กต์หลังจากสร้างอินสแตนซ์ แนะนำให้กำหนดอินเทอร์เฟซในโมดูลฐานและการนำไปใช้ใน โมดูลฟีเจอร์ ตัวอย่างเช่น
Kotlin
// 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();
Java
// 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();
เข้าถึงทรัพยากรและเนื้อหาจากโมดูลอื่น
เมื่อติดตั้งโมดูลแล้ว คุณจะเข้าถึงทรัพยากรและเนื้อหาภายใน ในแนวทางมาตรฐาน โดยมีข้อควรระวัง 2 ข้อคือ
- หากคุณกำลังเข้าถึงแหล่งข้อมูลจากโมดูลอื่น โมดูลดังกล่าวจะไม่ มีสิทธิ์เข้าถึงตัวระบุทรัพยากร แม้ว่าทรัพยากรจะยังคง มีได้ เข้าถึงตามชื่อ โปรดทราบว่าแพ็กเกจที่จะใช้อ้างอิงทรัพยากรคือ ของโมดูลที่มีการกำหนดทรัพยากร
- ถ้าคุณต้องการเข้าถึงเนื้อหาหรือทรัพยากรที่มีอยู่ในที่ติดตั้งใหม่ จากโมดูลอื่นที่ติดตั้งของแอปของคุณ คุณจะต้องทำโดยใช้ บริบทของแอปพลิเคชัน บริบทของคอมโพเนนต์ที่พยายามเข้าถึงทรัพยากรจะยังไม่ มีการอัปเดต หรือจะสร้างคอมโพเนนต์นั้นใหม่ (เช่น การเรียกใช้ Activity.recreate()) หรือ ติดตั้ง SplitCompat อีกครั้งหลังจากโมดูลฟีเจอร์ ของคุณ
โหลดโค้ดเนทีฟในแอปโดยใช้การนำส่งแบบออนดีมานด์
เราขอแนะนำให้ใช้ ReLinker เพื่อโหลดทั้งหมด ไลบรารีเนทีฟของคุณเมื่อใช้การนำส่งโมดูลฟีเจอร์แบบออนดีมานด์ ReLinker แก้ปัญหาการโหลดไลบรารีเนทีฟหลังการติดตั้ง โมดูลฟีเจอร์ ดูข้อมูลเพิ่มเติมเกี่ยวกับ ReLinker ได้ใน เคล็ดลับเกี่ยวกับ Android JNI
โหลดโค้ดเนทีฟจากโมดูลที่ไม่บังคับ
เมื่อติดตั้งการแยกแล้ว เราขอแนะนำให้โหลดโค้ดเนทีฟผ่าน ReLinker สำหรับ Instant App คุณควรใช้วิธีการพิเศษนี้
หากคุณใช้ System.loadLibrary()
เพื่อโหลดโค้ดเนทีฟและเนทีฟ
ไลบรารีมีการขึ้นต่อกันกับไลบรารีอื่นในโมดูล คุณต้อง
โหลดไลบรารีอื่นนั้นก่อน
หากคุณใช้ ReLinker การดำเนินการที่เทียบเท่าคือ
Relinker.recursively().loadLibrary()
หากคุณใช้ dlopen()
ในโค้ดแบบเนทีฟเพื่อโหลดไลบรารีที่กำหนดไว้ใน
เป็นโมดูลที่ไม่บังคับ วิธีนี้จะไม่ทำงานกับเส้นทางไลบรารีที่เกี่ยวข้อง
วิธีแก้ไขที่ดีที่สุดคือการเรียกเส้นทางสัมบูรณ์ของไลบรารีจากโค้ด Java
ผ่าน ClassLoader.findLibrary()
แล้วใช้ในการโทร dlopen()
ก่อนที่จะป้อนรหัสของระบบหรือใช้การโทร JNI จาก
ลงใน Java ได้
เข้าถึง Android Instant Apps ที่ติดตั้งไว้
หลังจากที่โมดูล Android Instant App รายงานเป็น INSTALLED
คุณจะเข้าถึง
โค้ดและทรัพยากรต่างๆ โดยใช้แอปพลิเคชันที่ได้รับการปรับปรุงใหม่
บริบท ต
บริบทที่แอปของคุณสร้างขึ้นก่อนติดตั้งโมดูล (เช่น
ที่เก็บไว้ในตัวแปรแล้ว) จะไม่มีเนื้อหาฟิลด์ใหม่
แต่บริบทใหม่สามารถทำได้ เช่น โดยการใช้
createPackageContext
Kotlin
// 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 } } } }
Java
// 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(); } } }
Android Instant Apps ใน Android 8.0 ขึ้นไป
เมื่อขอโมดูลออนดีมานด์สำหรับ Android Instant App บน Android 8.0
(API ระดับ 26) ขึ้นไป หลังจากที่คำขอติดตั้งรายงานเป็น INSTALLED
คุณจะ
ที่มีบริบทของโมดูลใหม่ผ่านการเรียกเพื่ออัปเดตแอป
SplitInstallHelper.updateAppInfo(Context context)
ไม่เช่นนั้น แอปจะยังไม่ทราบโค้ดของโมดูล
และทรัพยากรต่างๆ หลังจากอัปเดตข้อมูลเมตาของแอปแล้ว คุณควรโหลด
ในระหว่างเหตุการณ์เทรดหลักครั้งถัดไปด้วยการเรียกใช้
Handler
ตามที่แสดงด้านล่าง
Kotlin
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 ... } } } } } }
Java
@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++
หากคุณต้องการโหลดไลบรารี C/C++ จากโมดูลที่อุปกรณ์มีอยู่แล้ว
เมื่อดาวน์โหลดใน Instant App ให้ใช้
SplitInstallHelper.loadLibrary(Context context, String libName)
ดังที่แสดงด้านล่าง
Kotlin
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”) ... } } } }
Java
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 และต่ำกว่า
- คุณจะแคชออบเจ็กต์
ApplicationInfo
ของ Android, เนื้อหา หรือ ที่มีสิ่งเหล่านั้นอยู่ภายในแอปของคุณ คุณควรดึงข้อมูลออบเจ็กต์เหล่านี้เสมอ ตามความจำเป็นจากบริบทของแอป การแคชออบเจ็กต์ดังกล่าวอาจทำให้แอปขัดข้อง เมื่อติดตั้งโมดูลฟีเจอร์
จัดการโมดูลที่ติดตั้งไว้
หากต้องการตรวจสอบว่ากำลังติดตั้งโมดูลฟีเจอร์ใดในอุปกรณ์ ให้ทำดังนี้
เธอโทรหา
SplitInstallManager.getInstalledModules()
ซึ่งแสดงผล Set<String>
ของชื่อของโมดูลที่ติดตั้ง ตามที่แสดง
ที่ด้านล่าง
Kotlin
val installedModules: Set<String> = splitInstallManager.installedModules
Java
Set<String> installedModules = splitInstallManager.getInstalledModules();
ถอนการติดตั้งโมดูล
คุณสามารถขอให้อุปกรณ์ถอนการติดตั้งโมดูลโดยการเรียกใช้
SplitInstallManager.deferredUninstall(List<String> moduleNames)
ดังที่แสดงด้านล่าง
Kotlin
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(listOf("pictureMessages", "promotionalFilters"))
Java
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));
การถอนการติดตั้งโมดูลจะไม่เกิดขึ้นทันที นั่นคือ
อุปกรณ์จะถอนการติดตั้งในเบื้องหลังตามความจำเป็นเพื่อประหยัดพื้นที่เก็บข้อมูล
คุณสามารถยืนยันว่าอุปกรณ์
ลบโมดูลโดยการเรียกใช้
SplitInstallManager.getInstalledModules()
และตรวจสอบผลลัพธ์ ตามที่อธิบายไว้ในส่วนก่อนหน้านี้
ดาวน์โหลดแหล่งข้อมูลด้านภาษาเพิ่มเติม
เมื่อใช้ App Bundle อุปกรณ์จะดาวน์โหลดเฉพาะโค้ดและทรัพยากรที่ ต้องมีการเรียกใช้แอป ดังนั้น สำหรับแหล่งข้อมูลด้านภาษา อุปกรณ์ของผู้ใช้จะดาวน์โหลด เฉพาะทรัพยากรภาษาของแอปที่ตรงกับอย่างน้อย 1 ภาษาในปัจจุบัน ในการตั้งค่าของอุปกรณ์
หากคุณต้องการให้แอปเข้าถึงแหล่งข้อมูลด้านภาษาเพิ่มเติม เช่น หากต้องการใช้เครื่องมือเลือกภาษาในแอป คุณก็ใช้การนำส่งฟีเจอร์ Play คลังเพื่อให้ดาวน์โหลดได้แบบออนดีมานด์ กระบวนการนี้คล้ายกับกระบวนการ และดาวน์โหลดโมดูลฟีเจอร์ ตามที่แสดงด้านล่าง
Kotlin
// 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)
Java
// 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);
ระบบจะจัดการคำขอเสมือนเป็นคำขอสำหรับโมดูลฟีเจอร์ นั่นคือ คุณตรวจสอบสถานะคำขอได้เหมือนเช่นปกติ
หากแอปไม่จำเป็นต้องใช้ทรัพยากรด้านภาษาเพิ่มเติมในทันที คุณจะ สามารถเลื่อนการติดตั้งเมื่อแอปอยู่ในเบื้องหลัง ดังที่แสดง ที่ด้านล่าง
Kotlin
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
เข้าถึงทรัพยากรภาษาที่ดาวน์โหลด
หากต้องการรับสิทธิ์เข้าถึงทรัพยากรภาษาที่ดาวน์โหลดไว้ แอปของคุณต้องเรียกใช้
เมธอด SplitCompat.installActivity()
ภายในเมธอด attachBaseContext()
ของแต่ละกิจกรรมที่ต้องเข้าถึงทรัพยากรเหล่านั้น ดังที่แสดงด้านล่าง
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); SplitCompat.installActivity(this); }
สำหรับแต่ละกิจกรรมที่คุณต้องการใช้แหล่งข้อมูลด้านภาษาที่แอปได้ดาวน์โหลดไว้
อัปเดตบริบทพื้นฐานและตั้งค่าภาษาใหม่ผ่าน
Configuration
:
Kotlin
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) }
Java
@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()
วิธี
Kotlin
when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Recreates the activity to load resources for the new language // preference. activity.recreate() } ... }
Java
switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Recreates the activity to load resources for the new language // preference. activity.recreate(); ... }
ถอนการติดตั้งแหล่งข้อมูลด้านภาษาเพิ่มเติม
เช่นเดียวกับโมดูลฟีเจอร์ คุณสามารถถอนการติดตั้งทรัพยากรเพิ่มเติมที่ ตลอดเวลา ก่อนส่งคำขอถอนการติดตั้ง คุณอาจต้องพิจารณาก่อนว่า ที่มีการติดตั้งภาษาต่อไปนี้
Kotlin
val installedLanguages: Set<String> = splitInstallManager.installedLanguages
Java
Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();
จากนั้น คุณสามารถเลือกภาษาที่จะถอนการติดตั้งโดยใช้
deferredLanguageUninstall()
ดังที่แสดงด้านล่าง
Kotlin
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
การติดตั้งโมดูลทดสอบในเครื่อง
ไลบรารีการนำส่งฟีเจอร์ Play ช่วยให้คุณสามารถทดสอบความสามารถของแอปในเครื่องเพื่อดำเนินการ โดยไม่ต้องเชื่อมต่อกับ Play Store
- ส่งคำขอและตรวจสอบการติดตั้งโมดูล
- จัดการข้อผิดพลาดในการติดตั้ง
- ใช้
SplitCompat
ไปยังโมดูลการเข้าถึง
หน้านี้อธิบายวิธีทำให้ APK แยกของแอปใช้งานได้ในอุปกรณ์ทดสอบ ที่ Play Feature Delivery จะใช้ APK เหล่านั้นโดยอัตโนมัติ เพื่อจำลองการขอ การดาวน์โหลด และติดตั้งโมดูลจาก Play Store
แม้ว่าคุณจะไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ กับตรรกะของแอป แต่คุณต้อง มีคุณสมบัติตรงตามข้อกำหนดต่อไปนี้
- ดาวน์โหลดและติดตั้ง
bundletool
เวอร์ชันล่าสุด คุณต้องใช้bundletool
เพื่อสร้าง APK ชุดใหม่ที่ติดตั้งได้จากแอปของคุณ
สร้างชุด APK
สร้าง APK แยกของแอป (หากยังไม่ได้สร้าง) โดยทำดังนี้
- สร้าง App Bundle สําหรับแอปโดยใช้วิธีใดวิธีหนึ่งต่อไปนี้
- ใช้ Android Studio และปลั๊กอิน Android สำหรับ Gradle เพื่อสร้างและรับรอง Android App Bundle
- สร้าง App Bundle จากบรรทัดคำสั่ง
ใช้
bundletool
เพื่อสร้างชุด APK สำหรับอุปกรณ์ทั้งหมด ด้วยคำสั่งต่อไปนี้bundletool build-apks --local-testing --bundle my_app.aab --output my_app.apks
แฟล็ก --local-testing
มีข้อมูลเมตาใน APK ของคุณ ปรากฏว่า
แจ้งให้ไลบรารีการนำส่งฟีเจอร์ Play ทราบว่าจะใช้ APK แยกในเครื่องเพื่อทดสอบ
ติดตั้งโมดูลฟีเจอร์โดยไม่ต้องเชื่อมต่อกับ Play Store
ทำให้แอปใช้งานได้ในอุปกรณ์
หลังจากที่คุณสร้างชุด APK โดยใช้แฟล็ก --local-testing
แล้ว
ใช้ bundletool
เพื่อติดตั้งแอปเวอร์ชันพื้นฐานและโอนข้อมูลเพิ่มเติม
APK ไปยังพื้นที่เก็บข้อมูลในเครื่องของอุปกรณ์ คุณสามารถทำทั้ง 2 อย่างด้วย
คำสั่งต่อไปนี้
bundletool install-apks --apks my_app.apks
ทีนี้ เมื่อคุณเริ่มแอปและทำตามขั้นตอนของผู้ใช้จนเสร็จสิ้นเพื่อดาวน์โหลดและติดตั้ง
ซึ่งเป็นโมดูลฟีเจอร์ ไลบรารีการนำส่งฟีเจอร์ Play จะใช้ APK ที่bundletool
โอนไปยังพื้นที่เก็บข้อมูลในเครื่องของอุปกรณ์แล้ว
จำลองข้อผิดพลาดของเครือข่าย
ในการจำลองการติดตั้งโมดูลจาก Play Store ไลบรารีการนำส่งฟีเจอร์ Play ใช้
อีกตัวเลือกหนึ่งของ SplitInstallManager
ซึ่งเรียกว่า
FakeSplitInstallManager
,
เพื่อขอโมดูล เมื่อคุณใช้ bundletool
กับแฟล็ก --local-testing
ในการสร้างชุด APK และนำไปใช้กับอุปกรณ์ทดสอบ
มีข้อมูลเมตาที่สั่งให้ไลบรารีการนำส่งฟีเจอร์ Play เปลี่ยนโดยอัตโนมัติ
การเรียก API ของแอปเพื่อเรียกใช้ FakeSplitInstallManager
แทน
SplitInstallManager
FakeSplitInstallManager
มีแฟล็กบูลีนที่คุณเปิดใช้ได้
จำลองข้อผิดพลาดเกี่ยวกับเครือข่ายในครั้งต่อไปที่แอปของคุณขอติดตั้งโมดูล ถึง
เข้าถึง FakeSplitInstallManager
ในการทดสอบของคุณ คุณจะสามารถรับอินสแตนซ์ได้
โดยใช้
FakeSplitInstallManagerFactory
,
ดังที่แสดงด้านล่าง
Kotlin
// 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)
Java
// 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);