กำหนดค่าการแสดงโฆษณาแบบออนดีมานด์

โมดูลฟีเจอร์ช่วยให้คุณแยกฟีเจอร์และทรัพยากรบางอย่างได้ จากโมดูลฐานของแอปและรวมไว้ใน App Bundle ผ่าน การนำส่งฟีเจอร์ Play เป็นต้น ว่าผู้ใช้สามารถดาวน์โหลดและติดตั้ง คอมโพเนนต์ตามคำขอหลังจากติดตั้ง APK พื้นฐานของแอปของคุณแล้ว

ตัวอย่างเช่น ลองพิจารณาแอปรับส่งข้อความที่มีฟังก์ชัน จับภาพและส่งข้อความรูปภาพ แต่มีผู้ใช้เพียงส่วนน้อย ส่งข้อความรูปภาพ การใส่ข้อความด้วยรูปภาพว่าเป็น โมดูลฟีเจอร์ที่ดาวน์โหลดได้ วิธีนี้จะทำให้การดาวน์โหลดแอปเริ่มต้น จะเล็กลงสำหรับผู้ใช้ทั้งหมด และเฉพาะผู้ใช้ที่ส่งข้อความภาพเท่านั้นที่ต้อง ดาวน์โหลดคอมโพเนนต์เพิ่มเติมนั้น

โปรดจำไว้ว่าการแยกส่วนประเภทนี้ต้องใช้ความพยายามมากขึ้น และ การเปลี่ยนโครงสร้างภายในโค้ดที่มีอยู่ของแอปคุณ ดังนั้นควรพิจารณาอย่างรอบคอบว่าโค้ดใด ฟีเจอร์ของแอปจะได้รับประโยชน์มากที่สุดเมื่อพร้อมให้บริการแก่ผู้ใช้แบบออนดีมานด์ เพื่อให้เข้าใจกรณีการใช้งานและหลักเกณฑ์ที่เหมาะสมที่สุดสำหรับฟีเจอร์ออนดีมานด์ อ่านแนวทางปฏิบัติแนะนำสำหรับ UX สำหรับการนำส่งตามคำขอ

หากต้องการค่อยๆ ทำให้ฟีเจอร์ของแอปค่อยๆ แยกเป็นส่วนๆ เมื่อเวลาผ่านไป เปิดใช้ตัวเลือกการแสดงโฆษณาขั้นสูง เช่น การนำส่งตามคำขอแทน กำหนดค่าการนำส่งเวลาติดตั้ง

หน้านี้จะช่วยคุณเพิ่มโมดูลฟีเจอร์ลงในโปรเจ็กต์แอปและ กำหนดค่าสำหรับการแสดงโฆษณาแบบออนดีมานด์ ก่อนเริ่มต้น โปรดตรวจสอบว่าคุณ ใช้ Android Studio 3.5 ขึ้นไปและปลั๊กอิน Android Gradle 3.5.0 หรือสูงกว่า

กำหนดค่าโมดูลใหม่สำหรับการแสดงโฆษณาแบบออนดีมานด์

วิธีที่ง่ายที่สุดในการสร้างโมดูลฟีเจอร์ใหม่คือการใช้ Android Studio 3.5 ขึ้นไป เนื่องจากโมดูลฟีเจอร์มี การขึ้นต่อกันโดยธรรมชาติของโมดูลแอปพื้นฐาน คุณจะสามารถเพิ่มโมดูลเหล่านั้นลงใน โปรเจ็กต์ของแอป

วิธีเพิ่มโมดูลฟีเจอร์ลงในโปรเจ็กต์แอปโดยใช้ Android Studio โดยทำตามขั้นตอนต่อไปนี้

  1. เปิดโปรเจ็กต์แอปใน IDE หากยังไม่ได้เปิด
  2. เลือก ไฟล์ > ใหม่ > โมดูลใหม่จากแถบเมนู
  3. ในกล่องโต้ตอบสร้างโมดูลใหม่ ให้เลือก Dynamic Feature Module แล้วคลิก Next
  4. ในส่วนกำหนดค่าโมดูลใหม่ ให้กรอก ดังต่อไปนี้:
    1. เลือกโมดูลแอปพลิเคชันพื้นฐานสำหรับโปรเจ็กต์แอปจาก เมนูแบบเลื่อนลง
    2. ระบุชื่อโมดูล IDE ใช้ชื่อนี้เพื่อระบุ เป็นโปรเจ็กต์ย่อย Gradle ใน ไฟล์การตั้งค่า Gradle เมื่อคุณ สร้าง App Bundle โดย Gradle จะใช้องค์ประกอบสุดท้ายของโปรเจ็กต์ย่อย ชื่อที่จะแทรกแอตทริบิวต์ <manifest split> ใน ไฟล์ Manifest ของโมดูลฟีเจอร์
    3. ระบุชื่อแพ็กเกจของโมดูล โดยค่าเริ่มต้น Android Studio แนะนำชื่อแพ็กเกจที่รวมชื่อแพ็กเกจรูทของ โมดูลฐานและชื่อโมดูลที่คุณระบุไว้ในขั้นตอนก่อนหน้า
    4. เลือกระดับ API ขั้นต่ำที่คุณต้องการให้โมดูลรองรับ ค่านี้ควรตรงกับของโมดูลฐาน
  5. คลิกถัดไป
  6. ในส่วนตัวเลือกการดาวน์โหลดโมดูล ให้กรอกข้อมูลต่อไปนี้

    1. ระบุชื่อโมดูลโดยใช้อักขระได้สูงสุด 50 ตัว แพลตฟอร์ม ใช้ชื่อนี้เพื่อระบุโมดูลให้ผู้ใช้ได้ เช่น ในกรณีที่ เพื่อยืนยันว่าผู้ใช้ต้องการดาวน์โหลดโมดูลหรือไม่ สำหรับกรณีนี้ โมดูลฐานของแอปคุณต้องมีชื่อโมดูลเป็น สตริงทรัพยากร ซึ่งคุณ แปลได้ เมื่อสร้างโมดูลโดยใช้ Android Studio, IDE เพิ่มทรัพยากรสตริงลงในโมดูลฐานให้คุณ และแทรกพารามิเตอร์ รายการต่อไปนี้ในไฟล์ Manifest ของโมดูลฟีเจอร์

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. ในเมนูแบบเลื่อนลงภายใต้การรวมเวลาติดตั้ง ให้เลือกไม่ต้อง รวมโมดูล ณ เวลาติดตั้ง Android Studio จะแทรก ต่อไปนี้ในไฟล์ Manifest ของโมดูลเพื่อแสดงตัวเลือกของคุณ

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. เลือกช่อง Fusing หากต้องการให้โมดูลนี้พร้อมใช้งาน สำหรับอุปกรณ์ที่ใช้ Android 4.4 (API ระดับ 20) และต่ำกว่า และรวมอยู่ใน APK หลายรายการ ซึ่งหมายความว่าคุณเปิดใช้พฤติกรรมออนดีมานด์สำหรับโมดูลนี้ได้ และปิดใช้การฟิวชันเพื่อยกเว้นการฟิวชันจากอุปกรณ์ที่ไม่รองรับ การดาวน์โหลดและติดตั้ง APK แยกส่วน Android Studio จะแทรก ต่อไปนี้ในไฟล์ Manifest ของโมดูลเพื่อแสดงตัวเลือกของคุณ

      <dist:module ...>
          <dist:fusing dist:include="true | false" />
      </dist:module>
      
  7. คลิกเสร็จสิ้น

หลังจากที่ 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 ของผู้ใช้ในเวอร์ชันที่ติดตั้งในปัจจุบัน ของคุณได้ หากผู้ใช้ไม่มีสิทธิ์เข้าถึงโมดูลนี้ โปรดแจ้งให้ผู้ใช้ทราบ
คำขอไม่ถูกต้อง Google Play ได้รับคำขอ แต่คำขอดังกล่าว ไม่ได้ ยืนยันว่าข้อมูลในคำขอ สมบูรณ์และถูกต้อง
SESSION_NOT_FOUND ไม่พบเซสชันสำหรับรหัสเซสชันที่ระบุ หากคุณกำลังพยายามตรวจสอบสถานะของคำขอ ตามรหัสเซสชัน ให้ตรวจสอบว่ารหัสเซสชันถูกต้อง
API_ไม่พร้อมใช้งาน อุปกรณ์ปัจจุบันไม่รองรับไลบรารีการนำส่งฟีเจอร์ Play นั่นคือ อุปกรณ์จะไม่สามารถดาวน์โหลดและติดตั้งได้ ฟีเจอร์ตามคำขอได้ สำหรับอุปกรณ์ที่ใช้ Android 4.4 (API ระดับ 20) หรือต่ำกว่า คุณควร รวมโมดูลฟีเจอร์ ณ เวลาติดตั้งโดยใช้ พร็อพเพอร์ตี้ไฟล์ Manifest dist:fusing หากต้องการเรียนรู้เพิ่มเติม โปรดอ่านเกี่ยวกับ ไฟล์ Manifest ของโมดูลฟีเจอร์
ข้อผิดพลาดของเครือข่าย คำขอล้มเหลวเนื่องจากข้อผิดพลาดเกี่ยวกับเครือข่าย แจ้งให้ผู้ใช้สร้างการเชื่อมต่อเครือข่าย หรือเปลี่ยนไปใช้เครือข่ายอื่น
ACCESS_DENIED (ปฏิเสธการเข้าถึง) แอปลงทะเบียนคำขอไม่ได้เนื่องจากมีสิทธิ์ไม่เพียงพอ กรณีนี้มักเกิดขึ้นเมื่อแอปอยู่ในเบื้องหลัง พยายามส่งคำขอเมื่อแอปกลับไปอยู่ที่เบื้องหน้า
เข้ากันไม่ได้กับเซสชันที่มีอยู่ คำขอมีโมดูลอย่างน้อยหนึ่งโมดูลที่ ส่งคำขอแล้วแต่ยังไม่ได้ติดตั้ง สร้างคำขอใหม่ที่ไม่รวมโมดูลที่ ได้ขอแอปพลิเคชันแล้ว หรือรอโมดูลที่ขอทั้งหมดในปัจจุบัน ติดตั้งให้เสร็จก่อนที่จะลองส่งคำขออีกครั้ง

โปรดทราบว่าการขอโมดูล ติดตั้งไม่ได้แก้ข้อผิดพลาด

ใช้บริการ บริการที่รับผิดชอบการจัดการคำขอหยุดทำงาน ลองส่งคำขออีกครั้ง

SplitInstallStateUpdatedListener จะได้รับ SplitInstallSessionState ที่มีรหัสข้อผิดพลาดนี้, สถานะ FAILED และรหัสเซสชัน -1

พื้นที่จัดเก็บไม่เพียงพอ อุปกรณ์มีพื้นที่เก็บข้อมูลไม่เพียงพอที่จะติดตั้งฟีเจอร์ แจ้งผู้ใช้ว่าพวกเขามีพื้นที่เก็บข้อมูลไม่เพียงพอสำหรับการติดตั้งแอปนี้
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR SplitCompat โหลดโมดูลฟีเจอร์ไม่ได้ ข้อผิดพลาดเหล่านี้ควรได้รับการแก้ไขโดยอัตโนมัติหลังจากแอปถัดไป รีสตาร์ท
Play_STORE_NOT_FOUND อุปกรณ์ไม่ได้ติดตั้งแอป Play Store แจ้งให้ผู้ใช้ทราบว่าจำเป็นต้องดาวน์โหลดแอป Play Store
แอปไม่ได้เป็นเจ้าของ แอปนี้ยังไม่ได้รับการติดตั้งโดย Google Play และฟีเจอร์ไม่สามารถ ดาวน์โหลดแล้ว ข้อผิดพลาดนี้อาจเกิดขึ้นกับการติดตั้งที่มีการเลื่อนเวลาเท่านั้น ถ้าคุณต้องการให้ผู้ใช้ดาวน์โหลดแอปจาก Google Play ให้ใช้ startInstall() ซึ่งสามารถรับข้อมูลที่จำเป็น การยืนยันผู้ใช้
INTERNAL_ERROR เกิดข้อผิดพลาดภายใน 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) หรือสูงกว่า คุณต้องใช้ splitInstallHelper เพื่อ อัปเดตคอมโพเนนต์ของแอปด้วยโมดูลใหม่

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

หน้านี้อธิบายวิธีทำให้ APK แยกของแอปใช้งานได้ในอุปกรณ์ทดสอบ ที่ Play Feature Delivery จะใช้ APK เหล่านั้นโดยอัตโนมัติ เพื่อจำลองการขอ การดาวน์โหลด และติดตั้งโมดูลจาก Play Store

แม้คุณจะไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ กับตรรกะของแอป แต่คุณต้อง มีคุณสมบัติตรงตามข้อกำหนดต่อไปนี้

  • ดาวน์โหลดและติดตั้ง bundletool เวอร์ชันล่าสุด คุณต้องใช้ bundletool เพื่อสร้าง APK ชุดใหม่ที่ติดตั้งได้จากแอปของคุณ

สร้างชุด APK

สร้าง APK แยกของแอป (หากยังไม่ได้สร้าง) โดยทำดังนี้

  1. สร้าง App Bundle สําหรับแอปโดยใช้วิธีใดวิธีหนึ่งต่อไปนี้
  2. ใช้ 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);