โมดูลฟีเจอร์ช่วยให้คุณแยกฟีเจอร์และทรัพยากรบางอย่างออกจากโมดูลฐานของแอปและรวมไว้ใน App Bundle ได้ ตัวอย่างเช่น ผู้ใช้สามารถดาวน์โหลดและติดตั้งคอมโพเนนต์เหล่านั้นตามต้องการภายหลังผ่าน Play Feature Delivery หลังจากที่ติดตั้ง 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>
เลือกช่องข้างการผสานหากต้องการให้โมดูลนี้พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 4.4 (API ระดับ 20) หรือต่ำกว่า และรวมอยู่ใน APK หลายรายการ ซึ่งหมายความว่าคุณสามารถเปิดใช้ลักษณะการทำงานแบบออนดีมานด์สําหรับข้อบังคับนี้ และปิดใช้การผสานเพื่อยกเว้นข้อบังคับนี้จากอุปกรณ์ที่ไม่รองรับการดาวน์โหลดและการติดตั้ง APK แบบแยก Android Studio จะแทรก ต่อไปนี้ในไฟล์ Manifest ของโมดูลเพื่อแสดงตัวเลือกของคุณ
<dist:module ...> <dist:fusing dist:include="true | false" /> </dist:module>
คลิกเสร็จสิ้น
หลังจาก Android Studio สร้างโมดูลเสร็จแล้ว ให้ตรวจสอบเนื้อหาของโมดูลด้วยตนเองจากแผงโปรเจ็กต์ (เลือกดู > หน้าต่างเครื่องมือ > โปรเจ็กต์จากแถบเมนู) โค้ด ทรัพยากร และองค์กรเริ่มต้นควรเป็น คล้ายกับโมดูลแอปมาตรฐาน
ถัดไป คุณจะต้องติดตั้งใช้งานฟังก์ชันการทำงานแบบติดตั้งเมื่อต้องการโดยใช้ไลบรารี Play Feature Delivery
รวมไลบรารีการนำส่งฟีเจอร์ 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()
แบบแอซิงโครนัส
ก่อนที่จะเริ่มรับข้อมูลอัปเดตสำหรับคำขอติดตั้ง ให้ลงทะเบียนโปรแกรมรับฟังและรับรหัสเซสชันสำหรับคำขอดังที่แสดงด้านล่าง
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 รายการ คำขอที่กำลังดาวน์โหลด | ตรวจสอบว่ามีคำขอใดที่ยังคงดาวน์โหลดอยู่หรือไม่ ดังที่แสดงในตัวอย่างด้านบน |
ไม่มีโมดูลที่พร้อมให้บริการ | Google Play ไม่พบโมดูลที่ขอตาม ในแอป อุปกรณ์ และ Google Play ของผู้ใช้ในเวอร์ชันที่ติดตั้งในปัจจุบัน ของคุณได้ | หากผู้ใช้ไม่มีสิทธิ์เข้าถึงข้อบังคับ โปรดแจ้งให้ผู้ใช้ทราบ |
INVALID_REQUEST | Google Play ได้รับคำขอ แต่คำขอดังกล่าว ไม่ได้ | ยืนยันว่าข้อมูลในคำขอนั้นถูกต้องและครบถ้วน |
SESSION_NOT_FOUND | ไม่พบเซสชันสำหรับรหัสเซสชันที่ระบุ | หากคุณพยายามตรวจสอบสถานะของคําขอตามรหัสเซสชัน ให้ตรวจสอบว่ารหัสเซสชันถูกต้อง |
API_ไม่พร้อมใช้งาน | อุปกรณ์ปัจจุบันไม่รองรับไลบรารีการนำส่งฟีเจอร์ Play กล่าวคือ อุปกรณ์ไม่สามารถดาวน์โหลดและติดตั้งฟีเจอร์ตามต้องการ | สําหรับอุปกรณ์ที่ใช้ Android 4.4 (API ระดับ 20) หรือต่ำกว่า คุณควรรวมข้อบังคับของฟีเจอร์ไว้ในเวลาติดตั้งโดยใช้dist:fusing พร็อพเพอร์ตี้ไฟล์ Manifest ดูข้อมูลเพิ่มเติมได้ที่ไฟล์ Manifest ของโมดูลฟีเจอร์
|
ข้อผิดพลาดของเครือข่าย | คำขอล้มเหลวเนื่องจากข้อผิดพลาดเกี่ยวกับเครือข่าย | แจ้งให้ผู้ใช้เชื่อมต่อเครือข่ายหรือเปลี่ยนไปใช้เครือข่ายอื่น |
ACCESS_DENIED (ปฏิเสธการเข้าถึง) | แอปลงทะเบียนคำขอไม่ได้เนื่องจากมีสิทธิ์ไม่เพียงพอ | ซึ่งมักเกิดขึ้นเมื่อแอปทำงานอยู่เบื้องหลัง ลองส่งคำขอเมื่อแอปกลับมาอยู่เบื้องหน้า |
เข้ากันไม่ได้กับเซสชันที่มีอยู่ | คำขอมีโมดูลอย่างน้อย 1 รายการที่ขอไปแล้ว แต่ยังติดตั้งไม่สำเร็จ | สร้างคำขอใหม่ที่ไม่รวมโมดูลที่
ได้ขอแอปพลิเคชันแล้ว หรือรอโมดูลที่ขอทั้งหมดในปัจจุบัน
ติดตั้งให้เสร็จก่อนที่จะลองส่งคำขออีกครั้ง
โปรดทราบว่าการขอโมดูล ติดตั้งแล้วไม่ได้รับการแก้ไขเนื่องจากข้อผิดพลาด |
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 และฟีเจอร์ไม่สามารถ ดาวน์โหลดแล้ว ข้อผิดพลาดนี้จะเกิดขึ้นกับการติดตั้งที่เลื่อนออกไปเท่านั้น | ถ้าคุณต้องการให้ผู้ใช้ดาวน์โหลดแอปจาก Google Play ให้ใช้
startInstall() ซึ่งสามารถรับข้อมูลที่จำเป็น
การยืนยันผู้ใช้ |
ข้อผิดพลาดภายใน | เกิดข้อผิดพลาดภายใน Play Store | ลองส่งคำขออีกครั้ง |
หากผู้ใช้ขอดาวน์โหลดโมดูลแบบออนดีมานด์และเกิดข้อผิดพลาดขึ้น ให้พิจารณาแสดงกล่องโต้ตอบที่มี 2 ตัวเลือกให้ผู้ใช้ ได้แก่ ลองอีกครั้ง (ซึ่งจะพยายามส่งคำขออีกครั้ง) และยกเลิก (ซึ่งจะยกเลิกคำขอ) คุณควรระบุลิงก์ความช่วยเหลือที่นําผู้ใช้ไปยังศูนย์ช่วยเหลือของ Google Play ด้วยเพื่อรับการสนับสนุนเพิ่มเติม
จัดการการอัปเดตสถานะ
หลังจากลงทะเบียนโปรแกรมรับฟังและบันทึกรหัสเซสชันของคําขอแล้ว ให้ใช้ 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 เช่น แถบความคืบหน้า เพื่อให้ความคิดเห็นแก่ผู้ใช้เกี่ยวกับการดาวน์โหลด |
REQUIRES_USER_CONFIRMATION | ผู้ใช้ต้องยืนยันการดาวน์โหลด โดยส่วนใหญ่ สถานะนี้จะเกิดขึ้นหากไม่ได้ติดตั้งแอปผ่าน 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
แอปสามารถแสดงข้อความแจ้งผู้ใช้อีกครั้งเพื่อดำเนินการตามคำขอให้เสร็จสมบูรณ์
หากต้องการรับการเรียกกลับพร้อมคําตอบของผู้ใช้ คุณสามารถลบล้าง ActivityResultCallback ดังที่แสดงด้านล่าง
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); }
หากโมดูลแบบออนดีมานด์ของคุณเข้ากันได้กับทั้งแอปด่วนและแอปที่ติดตั้ง คุณจะเรียกใช้ 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 ที่ติดตั้งไว้
หลังจากโมดูล Instant App ของ Android รายงานเป็น 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 ใช้ APK เหล่านั้นโดยอัตโนมัติเพื่อจำลองการขอ ดาวน์โหลด และติดตั้งโมดูลจาก Play Store
แม้ว่าคุณจะไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ กับตรรกะของแอป แต่คุณต้อง มีคุณสมบัติตรงตามข้อกำหนดต่อไปนี้
- ดาวน์โหลดและติดตั้ง
bundletool
เวอร์ชันล่าสุด คุณต้องใช้bundletool
เพื่อสร้าง APK ชุดใหม่ที่ติดตั้งได้จากแอปของคุณ
สร้างชุด APK
หากยังไม่ได้สร้าง ให้สร้าง APK แบบแยกของแอป ดังนี้
- สร้าง App Bundle สําหรับแอปโดยใช้วิธีใดวิธีหนึ่งต่อไปนี้
- ใช้ Android Studio และปลั๊กอิน Android สำหรับ Gradle เพื่อสร้างและเซ็นชื่อ App Bundle ของ Android
- สร้าง App Bundle จากบรรทัดคำสั่ง
ใช้
bundletool
เพื่อสร้างชุด APK สำหรับอุปกรณ์ทั้งหมด ด้วยคำสั่งต่อไปนี้bundletool build-apks --local-testing --bundle my_app.aab --output my_app.apks
Flag --local-testing
มี meta-data ในไฟล์ Manifest ของ APK ซึ่งจะแจ้งให้ Play Feature Delivery Library ทราบว่าให้ใช้ APK ที่แยกในเครื่องเพื่อทดสอบการติดตั้งโมดูลฟีเจอร์โดยไม่ต้องเชื่อมต่อกับ Play Store
ทำให้แอปใช้งานได้ในอุปกรณ์
หลังจากสร้างชุด APK โดยใช้ Flag --local-testing
แล้ว ให้ใช้ bundletool
เพื่อติดตั้งแอปเวอร์ชันพื้นฐานและโอน APK เพิ่มเติมไปยังพื้นที่เก็บข้อมูลในเครื่องของอุปกรณ์ คุณทําทั้ง 2 อย่างได้ด้วยคําสั่งต่อไปนี้
bundletool install-apks --apks my_app.apks
เมื่อคุณเริ่มแอปและดำเนินการตามขั้นตอนของผู้ใช้เพื่อดาวน์โหลดและติดตั้งโมดูลฟีเจอร์จนเสร็จสมบูรณ์แล้ว ไลบรารีการนำส่งฟีเจอร์ของ Play จะใช้ APK ที่ bundletool
โอนไปยังพื้นที่เก็บข้อมูลในเครื่องของอุปกรณ์
จำลองข้อผิดพลาดเกี่ยวกับเครือข่าย
หากต้องการจำลองการติดตั้งโมดูลจาก Play Store ไลบรารีการนำส่งฟีเจอร์ Play จะใช้ตัวเลือกอื่นแทน SplitInstallManager
ซึ่งเรียกว่า FakeSplitInstallManager
เพื่อขอโมดูล เมื่อคุณใช้ bundletool
กับ Flag --local-testing
เพื่อสร้างชุด APK และนำไปติดตั้งในอุปกรณ์ทดสอบ bundletool
จะมีข้อมูลเมตาที่สั่งให้คลังการนำส่งฟีเจอร์ของ 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);