Google Play กำหนดให้ APK ที่บีบอัดซึ่งผู้ใช้ดาวน์โหลดมีขนาดไม่เกิน 100 MB สำหรับแอปส่วนใหญ่ พื้นที่นี้เพียงพอสำหรับโค้ดและชิ้นงานทั้งหมดของแอป อย่างไรก็ตาม แอปบางแอปต้องใช้พื้นที่เพิ่มสำหรับกราฟิกที่มีคุณภาพสูง ไฟล์สื่อ หรือชิ้นงานขนาดใหญ่อื่นๆ ก่อนหน้านี้ หากขนาดการดาวน์โหลดที่บีบอัดของแอปเกิน 100 MB คุณจะต้องโฮสต์และดาวน์โหลดทรัพยากรเพิ่มเติมด้วยตนเองเมื่อผู้ใช้เปิดแอป การโฮสต์และแสดงไฟล์เพิ่มเติมอาจทำให้สิ้นเปลืองค่าใช้จ่าย และประสบการณ์ของผู้ใช้มักไม่เป็นไปตามที่คาดหวัง Google Play อนุญาตให้คุณแนบไฟล์ขยายขนาดใหญ่ 2 ไฟล์เพื่อเสริม APK ของคุณได้ เพื่อช่วยให้คุณดำเนินการได้ง่ายขึ้นและผู้ใช้ได้รับประสบการณ์การใช้งานที่ดีขึ้น
Google Play จะโฮสต์ไฟล์ขยายสำหรับแอปของคุณและแสดงไฟล์เหล่านั้นในอุปกรณ์โดยไม่มีค่าใช้จ่าย ระบบจะบันทึกไฟล์สำหรับขยายลงในตำแหน่งที่จัดเก็บข้อมูลที่ใช้ร่วมกันของอุปกรณ์ (การ์ด SD หรือพาร์ติชันที่เชื่อมต่อได้ด้วย USB หรือที่เรียกว่าพื้นที่เก็บข้อมูล "ภายนอก") ซึ่งแอปของคุณเข้าถึงได้ ในอุปกรณ์ส่วนใหญ่ Google Play จะดาวน์โหลดไฟล์สำหรับขยายไปพร้อมๆ กับที่ดาวน์โหลด APK เพื่อให้แอปมีทุกอย่างที่จำเป็นเมื่อผู้ใช้เปิดแอปเป็นครั้งแรก อย่างไรก็ตาม ในบางกรณี แอปของคุณจะต้องดาวน์โหลดไฟล์จาก Google Play เมื่อแอปเริ่มทำงาน
หากต้องการหลีกเลี่ยงการใช้ไฟล์ส่วนขยายและขนาดการดาวน์โหลดที่บีบอัดของแอปใหญ่กว่า 100 MB คุณควรอัปโหลดแอปโดยใช้App Bundle ของ Android แทน ซึ่งอนุญาตให้มีขนาดการดาวน์โหลดที่บีบอัดได้สูงสุด 200 MB นอกจากนี้ เนื่องจากการใช้ App Bundle จะเลื่อนการสร้างและการลงนาม APK ไปยัง Google Play ผู้ใช้จึงดาวน์โหลด APK ที่เพิ่มประสิทธิภาพซึ่งมีเฉพาะโค้ดและทรัพยากรที่จําเป็นต่อการใช้งานแอป คุณจึงไม่ต้องสร้าง ลงนาม และจัดการ APK หรือไฟล์ Expansion หลายรายการ และผู้ใช้จะดาวน์โหลดไฟล์ที่มีขนาดเล็กลงและเพิ่มประสิทธิภาพมากขึ้น
ภาพรวม
ทุกครั้งที่คุณอัปโหลด APK โดยใช้ Google Play Console คุณจะมีตัวเลือกในการเพิ่มไฟล์สำหรับขยาย 1 หรือ 2 ไฟล์ลงใน APK ไฟล์แต่ละไฟล์มีขนาดไม่เกิน 2 GB และใช้รูปแบบใดก็ได้ แต่เราขอแนะนำให้ใช้ไฟล์ที่บีบอัดเพื่อประหยัดแบนด์วิดท์ระหว่างการดาวน์โหลด ไฟล์เสริมแต่ละไฟล์มีบทบาทแตกต่างกันดังนี้
- ไฟล์เสริมหลักคือไฟล์เสริมหลักสำหรับทรัพยากรเพิ่มเติมที่แอปของคุณต้องใช้
- ไฟล์สำหรับขยายแพตช์เป็นไฟล์ที่ไม่บังคับและมีไว้สำหรับการอัปเดตเล็กๆ น้อยๆ ของไฟล์สำหรับขยายหลัก
แม้ว่าคุณจะใช้ไฟล์สำหรับขยาย 2 ไฟล์นี้ในลักษณะใดก็ได้ แต่เราขอแนะนำให้ไฟล์สำหรับขยายหลักส่งชิ้นงานหลักและควรอัปเดตน้อยครั้งหรือไม่อัปเดตเลย ส่วนไฟล์สำหรับขยายแพตช์ควรมีขนาดเล็กลงและทำหน้าที่เป็น "พาหะแพตช์" ซึ่งจะได้รับการอัปเดตพร้อมกับรุ่นหลักแต่ละรุ่นหรือตามความจำเป็น
อย่างไรก็ตาม แม้ว่าการอัปเดตแอปของคุณจะต้องใช้เฉพาะไฟล์สำหรับขยายแพตช์ใหม่ คุณยังคงต้องอัปโหลด APK ใหม่ที่มี versionCode
ที่อัปเดตแล้วในไฟล์ Manifest (Play Console ไม่อนุญาตให้คุณอัปโหลดไฟล์สำหรับขยายไปยัง APK ที่มีอยู่)
หมายเหตุ: ไฟล์สำหรับขยายแพตช์มีความหมายเหมือนกับไฟล์สำหรับขยายหลัก คุณจึงใช้ไฟล์แต่ละไฟล์ได้ตามต้องการ
รูปแบบชื่อไฟล์
ไฟล์เสริมแต่ละไฟล์ที่คุณอัปโหลดอาจเป็นรูปแบบใดก็ได้ (ZIP, PDF, MP4 ฯลฯ) นอกจากนี้ คุณยังใช้เครื่องมือ JOBB เพื่อรวมและเข้ารหัสชุดไฟล์ทรัพยากรและแพตช์ชุดถัดไปสำหรับชุดนั้นได้อีกด้วย ไม่ว่าไฟล์จะเป็นประเภทใด Google Play จะถือว่าไฟล์เหล่านั้นเป็นบล็อกไบนารีทึบแสงและจะเปลี่ยนชื่อไฟล์โดยใช้รูปแบบต่อไปนี้
[main|patch].<expansion-version>.<package-name>.obb
รูปแบบนี้มีองค์ประกอบ 3 อย่าง ได้แก่
main
หรือpatch
- ระบุว่าไฟล์เป็นไฟล์สำหรับขยายหลักหรือไฟล์แพตช์ แต่ละ APK จะมีไฟล์หลักได้เพียงไฟล์เดียวและไฟล์แพตช์ได้เพียงไฟล์เดียว
<expansion-version>
- คือจำนวนเต็มซึ่งตรงกับรหัสเวอร์ชันของ APK ที่การขยายครั้งแรกเชื่อมโยงอยู่ (ตรงกับค่า
android:versionCode
ของแอป)เราเน้นคำว่า "ครั้งแรก" เนื่องจากแม้ว่า Play Console จะอนุญาตให้คุณใช้ไฟล์สำหรับขยายที่อัปโหลดแล้วกับ APK ใหม่ได้ แต่ชื่อของไฟล์สำหรับขยายจะไม่เปลี่ยนแปลง โดยจะยังคงเป็นเวอร์ชันที่ใช้กับไฟล์เมื่อคุณอัปโหลดไฟล์ครั้งแรก
<package-name>
- ชื่อแพ็กเกจสไตล์ Java ของแอป
ตัวอย่างเช่น สมมติว่าเวอร์ชัน APK ของคุณคือ 314159 และชื่อแพ็กเกจคือ com.example.app หากคุณอัปโหลดไฟล์สำหรับขยายหลัก ระบบจะเปลี่ยนชื่อไฟล์เป็น
main.314159.com.example.app.obb
ตำแหน่งพื้นที่เก็บข้อมูล
เมื่อ Google Play ดาวน์โหลดไฟล์ขยายลงในอุปกรณ์ ระบบจะบันทึกไฟล์เหล่านั้นไว้ในตำแหน่งพื้นที่เก็บข้อมูลที่ใช้ร่วมกันของระบบ คุณต้องไม่ลบ ย้าย หรือเปลี่ยนชื่อไฟล์ส่วนขยายเพื่อให้การทำงานเป็นไปอย่างถูกต้อง ในกรณีที่แอปต้องทำการดาวน์โหลดจาก Google Play ด้วยตนเอง คุณต้องบันทึกไฟล์ไว้ในตำแหน่งเดียวกันทุกประการ
เมธอด getObbDir()
จะแสดงตําแหน่งเฉพาะสำหรับไฟล์การขยายในรูปแบบต่อไปนี้
<shared-storage>/Android/obb/<package-name>/
<shared-storage>
คือเส้นทางไปยังพื้นที่เก็บข้อมูลที่ใช้ร่วมกัน ซึ่งพร้อมใช้งานจากgetExternalStorageDirectory()
<package-name>
คือชื่อแพ็กเกจสไตล์ Java ของแอป ซึ่งรับได้จากgetPackageName()
แต่ละแอปจะมีไฟล์ขยายได้ไม่เกิน 2 ไฟล์ในไดเรกทอรีนี้
ไฟล์หนึ่งคือไฟล์เสริมหลัก และอีกไฟล์หนึ่งคือไฟล์เสริมแพตช์ (หากจำเป็น) ระบบจะเขียนทับเวอร์ชันก่อนหน้าเมื่อคุณอัปเดตแอปด้วยไฟล์สำหรับขยายใหม่ ตั้งแต่ Android 4.4 (API ระดับ 19) เป็นต้นไป แอปจะอ่านOBB
ไฟล์เสริมได้โดยไม่ต้องมีสิทธิ์เข้าถึงพื้นที่เก็บข้อมูลภายนอก อย่างไรก็ตาม การใช้งานบางอย่างใน Android 6.0 (API ระดับ 23) ขึ้นไปยังคงต้องใช้สิทธิ์ดังกล่าว คุณจึงต้องประกาศสิทธิ์ READ_EXTERNAL_STORAGE
ในไฟล์ Manifest ของแอปและขอสิทธิ์ในรันไทม์ ดังนี้
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
สำหรับ Android เวอร์ชัน 6 ขึ้นไป จะต้องขอสิทธิ์เข้าถึงพื้นที่เก็บข้อมูลภายนอกขณะรันไทม์ อย่างไรก็ตาม การใช้งาน Android บางเวอร์ชันไม่จําเป็นต้องขอสิทธิ์ในการอ่านไฟล์ OBB ข้อมูลโค้ดต่อไปนี้แสดงวิธีตรวจสอบสิทธิ์การอ่านก่อนที่จะขอสิทธิ์เข้าถึงพื้นที่เก็บข้อมูลภายนอก
Kotlin
val obb = File(obb_filename) var open_failed = false try { BufferedReader(FileReader(obb)).also { br -> ReadObbFile(br) } } catch (e: IOException) { open_failed = true } if (open_failed) { // request READ_EXTERNAL_STORAGE permission before reading OBB file ReadObbFileWithPermission() }
Java
File obb = new File(obb_filename); boolean open_failed = false; try { BufferedReader br = new BufferedReader(new FileReader(obb)); open_failed = false; ReadObbFile(br); } catch (IOException e) { open_failed = true; } if (open_failed) { // request READ_EXTERNAL_STORAGE permission before reading OBB file ReadObbFileWithPermission(); }
หากต้องแตกไฟล์ในไฟล์ขยาย อย่าลบไฟล์OBB
ขยายหลังจากนั้น และอย่าบันทึกข้อมูลที่แตกไฟล์แล้วในไดเรกทอรีเดียวกัน คุณควรบันทึกไฟล์ที่แตกไฟล์แล้วในไดเรกทอรีที่ระบุโดย getExternalFilesDir()
อย่างไรก็ตาม หากเป็นไปได้ เราขอแนะนำให้ใช้รูปแบบไฟล์การขยายที่ให้คุณอ่านจากไฟล์ได้โดยตรงแทนที่จะต้องแตกไฟล์ ตัวอย่างเช่น เราได้จัดเตรียมโปรเจ็กต์ไลบรารีที่เรียกว่า APK Expansion Zip Library ซึ่งจะอ่านข้อมูลจากไฟล์ ZIP โดยตรง
ข้อควรระวัง: ผู้ใช้และแอปอื่นๆ จะอ่านไฟล์ที่บันทึกไว้ในพื้นที่เก็บข้อมูลที่แชร์ได้ ซึ่งแตกต่างจากไฟล์ APK
เคล็ดลับ: หากกำลังจัดแพ็กเกจไฟล์สื่อเป็น ZIP คุณสามารถใช้การเรียกใช้การเล่นสื่อในไฟล์ที่มีการควบคุมระยะถ่วงและความยาว (เช่น MediaPlayer.setDataSource()
และ SoundPool.load()
) โดยไม่ต้องแตกไฟล์ ZIP คุณต้องไม่ทำการบีบอัดเพิ่มเติมในไฟล์สื่อเมื่อสร้างแพ็กเกจ ZIP เพื่อให้การดําเนินการนี้ได้ผล ตัวอย่างเช่น เมื่อใช้เครื่องมือ zip
คุณควรใช้ตัวเลือก -n
เพื่อระบุนามสกุลไฟล์ที่ไม่ควรบีบอัด ดังนี้
zip -n .mp4;.ogg main_expansion media_files
กระบวนการดาวน์โหลด
ส่วนใหญ่ Google Play จะดาวน์โหลดและบันทึกไฟล์สำหรับขยายไปพร้อมๆ กับการดาวน์โหลด APK ลงในอุปกรณ์ อย่างไรก็ตาม ในบางกรณี Google Play อาจดาวน์โหลดไฟล์เสริมไม่ได้ หรือผู้ใช้อาจลบไฟล์เสริมที่ดาวน์โหลดไว้ก่อนหน้านี้ไปแล้ว หากต้องการจัดการกับสถานการณ์เหล่านี้ แอปของคุณต้องสามารถดาวน์โหลดไฟล์ด้วยตนเองได้เมื่อกิจกรรมหลักเริ่มต้นขึ้น โดยใช้ URL ที่ Google Play ระบุ
กระบวนการดาวน์โหลดโดยสังเขปมีดังนี้
- ผู้ใช้เลือกติดตั้งแอปของคุณจาก Google Play
- หาก Google Play ดาวน์โหลดไฟล์สำหรับขยายได้ (ซึ่งอุปกรณ์ส่วนใหญ่ทำได้) ก็จะดาวน์โหลดไฟล์ดังกล่าวไปพร้อมกับ APK
หาก Google Play ดาวน์โหลดไฟล์สำหรับขยายไม่ได้ ก็จะดาวน์โหลด APK เท่านั้น
- เมื่อผู้ใช้เปิดแอป แอปของคุณต้องตรวจสอบว่าไฟล์เสริมบันทึกอยู่ในอุปกรณ์แล้วหรือยัง
- หากใช่ แอปของคุณก็พร้อมใช้งานแล้ว
- หากไม่มี แอปของคุณจะต้องดาวน์โหลดไฟล์ขยายผ่าน HTTP จาก Google Play แอปของคุณต้องส่งคำขอไปยังไคลเอ็นต์ Google Play โดยใช้บริการการอนุญาตให้ใช้แอปของ Google Play ซึ่งจะตอบสนองด้วยชื่อ ขนาดไฟล์ และ URL ของไฟล์ขยายแต่ละไฟล์ เมื่อทราบข้อมูลนี้แล้ว คุณสามารถดาวน์โหลดไฟล์และบันทึกลงในตำแหน่งพื้นที่เก็บข้อมูลที่เหมาะสม
ข้อควรระวัง: คุณจำเป็นต้องใส่โค้ดที่จำเป็นเพื่อดาวน์โหลดไฟล์ขยายจาก Google Play ในกรณีที่ไฟล์ดังกล่าวยังไม่มีอยู่ในอุปกรณ์เมื่อแอปเริ่มทำงาน ดังที่ได้กล่าวไว้ในส่วนต่อไปนี้เกี่ยวกับการดาวน์โหลดไฟล์ Expansion เราได้จัดทำคลังให้คุณใช้งานแล้ว ซึ่งจะลดความซับซ้อนของกระบวนการนี้อย่างมากและทำการดาวน์โหลดจากบริการด้วยโค้ดเพียงเล็กน้อย
รายการตรวจสอบการพัฒนา
ต่อไปนี้เป็นสรุปของงานที่คุณควรทำเพื่อใช้ไฟล์สำหรับขยายกับแอป
- ก่อนอื่นให้พิจารณาว่าขนาดการดาวน์โหลดที่บีบอัดของแอปต้องมากกว่า 100 MB หรือไม่ พื้นที่เก็บข้อมูลมีคุณค่ามาก คุณจึงควรทำให้ขนาดการดาวน์โหลดทั้งหมดมีขนาดเล็กที่สุดเท่าที่จะเป็นไปได้ หากแอปใช้พื้นที่มากกว่า 100 MB เพื่อให้บริการชิ้นงานกราฟิกหลายเวอร์ชันสำหรับความหนาแน่นของหน้าจอหลายแบบ ให้พิจารณาเผยแพร่APK หลายรายการแทน โดยแต่ละ APK จะมีเฉพาะชิ้นงานที่จําเป็นสําหรับหน้าจอที่กําหนดเป้าหมาย หากต้องการให้ได้ผลลัพธ์ที่ดีที่สุดเมื่อเผยแพร่ไปยัง Google Play ให้อัปโหลด Android App Bundle ซึ่งรวมโค้ดและทรัพยากรที่คอมไพล์แล้วทั้งหมดของแอป แต่เลื่อนการสร้างและ Signing APK ไปยัง Google Play
- เลือกทรัพยากรของแอปที่จะแยกออกจาก APK และแพ็กเกจไว้ในไฟล์เพื่อใช้เป็นไฟล์เสริมหลัก
ปกติแล้ว คุณควรใช้ไฟล์สำหรับขยายแพตช์ที่ 2 เฉพาะเมื่อทำการอัปเดตไฟล์สำหรับขยายหลักเท่านั้น อย่างไรก็ตาม หากทรัพยากรเกินขีดจำกัด 2 GB สำหรับไฟล์สำหรับขยายหลัก คุณจะใช้ไฟล์แพตช์สำหรับเนื้อหาที่เหลือได้
- พัฒนาแอปให้ใช้ทรัพยากรจากไฟล์ขยายในตำแหน่งพื้นที่เก็บข้อมูลที่แชร์ของอุปกรณ์
โปรดทราบว่าคุณต้องไม่ลบ ย้าย หรือเปลี่ยนชื่อไฟล์สำหรับขยาย
หากแอปของคุณไม่ได้กำหนดรูปแบบที่เฉพาะเจาะจง เราขอแนะนำให้คุณสร้างไฟล์ ZIP สำหรับไฟล์สำหรับขยาย แล้วอ่านโดยใช้คลัง ZIP สำหรับขยาย APK
- เพิ่มตรรกะลงในกิจกรรมหลักของแอปเพื่อตรวจสอบว่าไฟล์ขยายอยู่ในอุปกรณ์เมื่อเริ่มต้นหรือไม่ หากไฟล์ไม่ได้อยู่ในอุปกรณ์ ให้ใช้บริการการอนุญาตให้ใช้สิทธิแอปของ Google Play เพื่อขอ URL ของไฟล์ขยาย จากนั้นดาวน์โหลดและบันทึกไฟล์
หากต้องการลดจำนวนโค้ดที่ต้องเขียนลงอย่างมากและช่วยให้ผู้ใช้ได้รับประสบการณ์ที่ดีขณะดาวน์โหลด เราขอแนะนำให้คุณใช้คลังดาวน์โหลดเพื่อใช้ลักษณะการดาวน์โหลด
หากคุณสร้างบริการดาวน์โหลดของคุณเองแทนการใช้คลัง โปรดทราบว่าคุณต้องไม่เปลี่ยนชื่อไฟล์ส่วนขยายและต้องบันทึกไฟล์เหล่านั้นลงในตำแหน่งพื้นที่เก็บข้อมูลที่เหมาะสม
เมื่อพัฒนาแอปเสร็จแล้ว ให้ทำตามคำแนะนำในการทดสอบไฟล์ Expansion
กฎและข้อจำกัด
การเพิ่มไฟล์ขยาย APK เป็นฟีเจอร์ที่ใช้ได้เมื่อคุณอัปโหลดแอปโดยใช้ Play Console เมื่ออัปโหลดแอปเป็นครั้งแรกหรืออัปเดตแอปที่ใช้ไฟล์เสริม คุณต้องคำนึงถึงกฎและข้อจำกัดต่อไปนี้
- ไฟล์ขยายแต่ละไฟล์ต้องมีขนาดไม่เกิน 2 GB
- ผู้ใช้ต้องดาวน์โหลดแอปจาก Google Play จึงจะดาวน์โหลดไฟล์ส่วนขยายจาก Google Play ได้ Google Play จะไม่ระบุ URL ของไฟล์สำหรับขยายหากติดตั้งแอปด้วยวิธีอื่น
- เมื่อทำการดาวน์โหลดจากภายในแอป URL ที่ Google Play ให้ไว้สำหรับแต่ละไฟล์จะไม่ซ้ำกันสำหรับการดาวน์โหลดแต่ละครั้ง และแต่ละ URL จะหมดอายุไม่นานหลังจากที่ส่งให้กับแอป
- หากอัปเดตแอปด้วย APK ใหม่หรืออัปโหลด APK หลายรายการสำหรับแอปเดียวกัน คุณสามารถเลือกไฟล์สำหรับขยายที่คุณอัปโหลดไว้สำหรับ APK รายการก่อนหน้าได้ ชื่อไฟล์ส่วนขยายจะไม่เปลี่ยนแปลง โดยไฟล์จะยังคงเป็นเวอร์ชันที่ได้รับจาก APK ที่เชื่อมโยงกับไฟล์นั้นในตอนแรก
- หากคุณใช้ไฟล์ขยายร่วมกับ APK หลายรายการเพื่อระบุไฟล์ขยายที่แตกต่างกันสำหรับอุปกรณ์แต่ละเครื่อง คุณยังคงต้องอัปโหลด APK แยกต่างหากสำหรับแต่ละอุปกรณ์เพื่อระบุค่า
versionCode
ที่ไม่ซ้ำกันและประกาศตัวกรองที่แตกต่างกันสำหรับแต่ละ APK - คุณไม่สามารถอัปเดตแอปโดยเปลี่ยนไฟล์สำหรับขยายเพียงอย่างเดียว คุณต้องอัปโหลด APK ใหม่เพื่ออัปเดตแอป หากการเปลี่ยนแปลงเกี่ยวข้องกับเนื้อหาในไฟล์สำหรับขยายเท่านั้น คุณสามารถอัปเดต APK ได้โดยเปลี่ยน
versionCode
(และอาจเปลี่ยนversionName
ด้วย) - อย่าบันทึกข้อมูลอื่นๆ ลงใน
obb/
ไดเรกทอรี หากต้องแตกไฟล์ข้อมูล ให้บันทึกข้อมูลดังกล่าวไว้ในตำแหน่งที่getExternalFilesDir()
ระบุ - อย่าลบหรือเปลี่ยนชื่อไฟล์สำหรับขยาย
.obb
(เว้นแต่คุณจะทำการอัปเดต) เนื่องจากจะทำให้ Google Play (หรือแอปของคุณเอง) ดาวน์โหลดไฟล์สำหรับขยายซ้ำๆ - เมื่ออัปเดตไฟล์สำหรับขยายด้วยตนเอง คุณต้องลบไฟล์สำหรับขยายก่อนหน้านี้
การดาวน์โหลดไฟล์สำหรับขยาย
ในกรณีส่วนใหญ่ Google Play จะดาวน์โหลดและบันทึกไฟล์สำหรับขยายลงในอุปกรณ์ในเวลาเดียวกันกับที่ติดตั้งหรืออัปเดต APK วิธีนี้จะทำให้ไฟล์ขยายพร้อมใช้งานเมื่อแอปเปิดขึ้นเป็นครั้งแรก อย่างไรก็ตาม ในบางกรณี แอปของคุณจะต้องดาวน์โหลดไฟล์เสริมด้วยตนเองโดยขอไฟล์จาก URL ที่ระบุไว้ในคําตอบจากบริการการอนุญาตให้ใช้แอปของ Google Play
ตรรกะพื้นฐานที่คุณต้องใช้ในการดาวน์โหลดไฟล์เสริมมีดังนี้
- เมื่อแอปเริ่มทำงาน ให้มองหาไฟล์ขยายในตำแหน่งที่จัดเก็บข้อมูลที่ใช้ร่วมกัน (ในไดเรกทอรี
Android/obb/<package-name>/
)- หากมีไฟล์ขยายอยู่ ทุกอย่างก็พร้อมแล้วและแอปจะดำเนินการต่อได้
- หากไฟล์สำหรับขยายไม่อยู่ ให้ทำดังนี้
- ส่งคำขอโดยใช้การอนุญาตให้ใช้สิทธิของแอปของ Google Play เพื่อดูชื่อ ขนาด และ URL ของไฟล์ขยายของแอป
- ใช้ URL ที่ Google Play ระบุเพื่อดาวน์โหลดไฟล์สำหรับขยายและบันทึกไฟล์สำหรับขยาย คุณต้องบันทึกไฟล์ลงในตำแหน่งพื้นที่เก็บข้อมูลที่ใช้ร่วมกัน (
Android/obb/<package-name>/
) และใช้ชื่อไฟล์ที่ตรงกันทุกประการกับที่ระบุไว้ในคําตอบของ Google Playหมายเหตุ: URL ที่ Google Play ระบุสำหรับไฟล์เสริมของคุณจะไม่ซ้ำกันสำหรับการดาวน์โหลดแต่ละครั้ง และแต่ละ URL จะหมดอายุไม่นานหลังจากที่ส่งไปยังแอป
หากแอปของคุณเป็นแบบไม่มีค่าใช้จ่าย (ไม่ใช่แอปที่ต้องซื้อ) คุณอาจไม่ได้ใช้บริการการอนุญาตให้ใช้สิทธิแอป โดยหลักแล้ว ฟีเจอร์นี้ออกแบบมาเพื่อให้คุณบังคับใช้นโยบายการอนุญาตให้ใช้สิทธิสำหรับแอปและตรวจสอบว่าผู้ใช้มีสิทธิ์ใช้แอปของคุณ (ผู้ใช้ชำระเงินอย่างถูกต้องใน Google Play) เราได้ปรับปรุงบริการอนุญาตให้ใช้สิทธิเพื่อให้การตอบสนองแก่แอปของคุณมี URL ของไฟล์ส่วนขยายของแอปที่โฮสต์ใน Google Play เพื่ออำนวยความสะดวกในฟังก์ชันการทำงานของไฟล์ส่วนขยาย ดังนั้น แม้ว่าแอปของคุณจะให้บริการแก่ผู้ใช้แบบไม่มีค่าใช้จ่าย คุณก็จะต้องใส่ไฟล์ LVL (License Verification Library) เพื่อใช้ไฟล์สำหรับขยายของ APK แน่นอนว่าหากแอปของคุณไม่มีค่าใช้จ่าย คุณไม่จำเป็นต้องบังคับใช้การยืนยันใบอนุญาต เพียงแค่ต้องมีไลบรารีเพื่อดำเนินการตามคำขอที่แสดงผล URL ของไฟล์ส่วนขยาย
หมายเหตุ: ไม่ว่าแอปของคุณจะฟรีหรือไม่ Google Play จะแสดง URL ของไฟล์ขยายเฉพาะในกรณีที่ผู้ใช้ดาวน์โหลดแอปจาก Google Play เท่านั้น
นอกจาก LVL แล้ว คุณต้องมีชุดโค้ดที่ดาวน์โหลดไฟล์ส่วนขยายผ่านการเชื่อมต่อ HTTP และบันทึกไฟล์เหล่านั้นไว้ในตำแหน่งที่เหมาะสมบนพื้นที่เก็บข้อมูลที่ใช้ร่วมกันของอุปกรณ์ ขณะสร้างขั้นตอนนี้ในแอป คุณควรพิจารณาถึงปัญหาหลายประการ ดังนี้
- อุปกรณ์อาจมีพื้นที่ไม่เพียงพอสำหรับไฟล์ขยาย ดังนั้นคุณควรตรวจสอบก่อนเริ่มการดาวน์โหลดและเตือนผู้ใช้หากมีพื้นที่ไม่เพียงพอ
- การดาวน์โหลดไฟล์ควรเกิดขึ้นในบริการเบื้องหลังเพื่อหลีกเลี่ยงการบล็อกการโต้ตอบของผู้ใช้ และอนุญาตให้ผู้ใช้ออกจากแอปขณะที่การดาวน์โหลดเสร็จสมบูรณ์
- ข้อผิดพลาดหลายอย่างอาจเกิดขึ้นระหว่างการขอและการดาวน์โหลด ซึ่งคุณต้องจัดการอย่างเหมาะสม
- การเชื่อมต่อเครือข่ายอาจเปลี่ยนแปลงระหว่างการดาวน์โหลด คุณจึงควรจัดการกับการเปลี่ยนแปลงดังกล่าว และหากการดาวน์โหลดถูกขัดจังหวะ ให้ดาวน์โหลดต่อเมื่อเป็นไปได้
- ขณะที่มีการดาวน์โหลดในเบื้องหลัง คุณควรแสดงการแจ้งเตือนที่บ่งบอกความคืบหน้าของการดาวน์โหลด แจ้งให้ผู้ใช้ทราบเมื่อดาวน์โหลดเสร็จแล้ว และนําผู้ใช้กลับไปที่แอปของคุณเมื่อเลือก
เราได้สร้างคลังโปรแกรมดาวน์โหลดเพื่อลดความซับซ้อนของงานนี้ให้คุณ ซึ่งจะขอ URL ของไฟล์ขยายผ่านบริการอนุญาตให้ใช้สิทธิ ดาวน์โหลดไฟล์ขยาย ทำงานทั้งหมดที่ระบุไว้ข้างต้น และแม้แต่หยุดกิจกรรมชั่วคราวและดาวน์โหลดต่อ การเพิ่มคลังเครื่องมือดาวน์โหลดและฮุกโค้ด 2-3 รายการลงในแอปจะทําให้ระบบเขียนโค้ดเกือบทั้งหมดสําหรับการดาวน์โหลดไฟล์ส่วนขยายให้คุณแล้ว ดังนั้น เราขอแนะนำให้คุณใช้คลังโปรแกรมดาวน์โหลดเพื่อดาวน์โหลดไฟล์ส่วนขยายเพื่อให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดีที่สุดโดยที่คุณไม่ต้องทำอะไรมากนัก ข้อมูลในส่วนต่อไปนี้อธิบายวิธีผสานรวมคลังเข้ากับแอป
หากต้องการพัฒนาโซลูชันของคุณเองเพื่อดาวน์โหลดไฟล์ขยายโดยใช้ URL ของ Google Play คุณต้องทําตามเอกสารประกอบการอนุญาตให้ใช้แอปเพื่อส่งคําขอใบอนุญาต จากนั้นดึงข้อมูลชื่อ ไฟล์ขยาย ขนาด และ URL จากข้อมูลเพิ่มเติมของคำตอบ คุณควรใช้คลาส APKExpansionPolicy
(รวมอยู่ในคลังการยืนยันใบอนุญาต) เป็นนโยบายการอนุญาตให้ใช้สิทธิ ซึ่งจะบันทึกชื่อ ขนาดใหญ่ และ URL ของไฟล์ขยายจากบริการอนุญาตให้ใช้สิทธิ
เกี่ยวกับคลังโปรแกรมดาวน์โหลด
หากต้องการใช้ไฟล์การขยาย APK กับแอปและมอบประสบการณ์การใช้งานที่ดีที่สุดให้กับผู้ใช้โดยที่คุณไม่ต้องทำอะไรมากนัก เราขอแนะนำให้ใช้ Downloader Library ที่รวมอยู่ในแพ็กเกจ Google Play APK Expansion Library คลังนี้จะดาวน์โหลดไฟล์ส่วนขยายในบริการเบื้องหลัง แสดงการแจ้งเตือนผู้ใช้พร้อมสถานะการดาวน์โหลด จัดการการขาดการเชื่อมต่อเครือข่าย ดาวน์โหลดต่อเมื่อเป็นไปได้ และอื่นๆ
หากต้องการใช้การดาวน์โหลดไฟล์สำหรับขยายโดยใช้คลังเครื่องมือดาวน์โหลด คุณก็เพียงทำดังนี้
- ขยาย
Service
ซับคลาสและBroadcastReceiver
ซับคลาสพิเศษที่แต่ละรายการต้องใช้โค้ดเพียงไม่กี่บรรทัด - เพิ่มตรรกะบางอย่างลงในกิจกรรมหลักที่ตรวจสอบว่าดาวน์โหลดไฟล์ขยายไปแล้วหรือยัง หากยัง ให้เรียกใช้กระบวนการดาวน์โหลดและแสดง UI ความคืบหน้า
- ใช้อินเทอร์เฟซการเรียกกลับที่มีเมธอด 2-3 รายการในกิจกรรมหลักซึ่งรับข้อมูลอัปเดตเกี่ยวกับความคืบหน้าของการดาวน์โหลด
ส่วนต่อไปนี้จะอธิบายวิธีตั้งค่าแอปโดยใช้คลังโปรแกรมดาวน์โหลด
การเตรียมพร้อมใช้งานคลังโปรแกรมดาวน์โหลด
หากต้องการใช้ไลบรารีโปรแกรมดาวน์โหลด คุณต้องดาวน์โหลดแพ็กเกจ 2 รายการจากเครื่องมือจัดการ SDK และเพิ่มไลบรารีที่เหมาะสมลงในแอป
ก่อนอื่น ให้เปิด Android SDK Manager (เครื่องมือ > SDK Manager) และในส่วนลักษณะที่ปรากฏและลักษณะการทํางาน > การตั้งค่าระบบ > Android SDK ให้เลือกแท็บเครื่องมือ SDK เพื่อเลือกและดาวน์โหลดรายการต่อไปนี้
- แพ็กเกจคลังใบอนุญาตของ Google Play
- แพ็กเกจ Google Play Expansion Library สำหรับ APK
สร้างโมดูลไลบรารีใหม่สําหรับไลบรารีการยืนยันใบอนุญาตและ Downloader Library สำหรับคลังแต่ละแห่ง
- เลือก File > New > New Module
- ในหน้าต่างสร้างข้อบังคับใหม่ ให้เลือกคลัง Android แล้วเลือกถัดไป
- ระบุชื่อแอป/ไลบรารี เช่น "ไลบรารีใบอนุญาต Google Play" และ "ไลบรารีโปรแกรมดาวน์โหลด Google Play" เลือกระดับ SDK ขั้นต่ำ แล้วเลือกเสร็จสิ้น
- เลือกไฟล์ > โครงสร้างโปรเจ็กต์
- เลือกแท็บพร็อพเพอร์ตี้ และในส่วนคลัง
ที่เก็บ ให้ป้อนคลังจากไดเรกทอรี
<sdk>/extras/google/
(play_licensing/
สำหรับคลังการยืนยันใบอนุญาตหรือplay_apk_expansion/downloader_library/
สำหรับคลังโปรแกรมดาวน์โหลด) - เลือกตกลงเพื่อสร้างข้อบังคับใหม่
หมายเหตุ: ไลบรารีโปรแกรมดาวน์โหลดจะขึ้นอยู่กับไลบรารีการยืนยันใบอนุญาต อย่าลืมเพิ่มไลบรารีการยืนยันใบอนุญาตลงในพร็อพเพอร์ตี้โปรเจ็กต์ของไลบรารีโปรแกรมดาวน์โหลด
หรืออัปเดตโปรเจ็กต์จากบรรทัดคำสั่งให้รวมไลบรารีต่อไปนี้
- เปลี่ยนไดเรกทอรีเป็นไดเรกทอรี
<sdk>/tools/
- เรียกใช้
android update project
ด้วยตัวเลือก--library
เพื่อเพิ่มทั้ง LVL และไลบรารี Downloader ลงในโปรเจ็กต์ เช่นandroid update project --path ~/Android/MyApp \ --library ~/android_sdk/extras/google/market_licensing \ --library ~/android_sdk/extras/google/market_apk_expansion/downloader_library
เมื่อเพิ่มทั้งไลบรารีการยืนยันใบอนุญาตและไลบรารีโปรแกรมดาวน์โหลดลงในแอปแล้ว คุณจะผสานรวมความสามารถในการดาวน์โหลดไฟล์ส่วนขยายจาก Google Play ได้อย่างรวดเร็ว รูปแบบที่คุณเลือกสำหรับไฟล์ขยายและวิธีอ่านไฟล์เหล่านั้นจากพื้นที่เก็บข้อมูลที่ใช้ร่วมกันเป็นการใช้งานแยกต่างหากที่คุณควรพิจารณาตามความต้องการของแอป
เคล็ดลับ: แพ็กเกจการขยาย Apk มีตัวอย่างแอปที่แสดงวิธีใช้ไลบรารี Downloader ในแอป ตัวอย่างนี้ใช้ไลบรารีของบุคคลที่สามซึ่งมีอยู่ในแพ็กเกจการขยาย Apk ที่เรียกว่า APK Expansion Zip Library หากวางแผนที่จะใช้ไฟล์ ZIP สำหรับไฟล์สำหรับขยาย เราขอแนะนำให้คุณเพิ่มไลบรารี ZIP ส่วนขยาย APK ลงในแอปด้วย ดูข้อมูลเพิ่มเติมได้ที่ส่วนการใช้ไลบรารี ZIP ส่วนขยาย APK
การประกาศสิทธิ์ของผู้ใช้
หากต้องการดาวน์โหลดไฟล์เสริม ไลบรารี Downloader จะต้องใช้สิทธิ์หลายรายการที่คุณจะต้องประกาศในไฟล์ Manifest ของแอป ดังนี้
<manifest ...> <!-- Required to access Google Play Licensing --> <uses-permission android:name="com.android.vending.CHECK_LICENSE" /> <!-- Required to download files from Google Play --> <uses-permission android:name="android.permission.INTERNET" /> <!-- Required to keep CPU alive while downloading files (NOT to keep screen awake) --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- Required to poll the state of the network connection and respond to changes --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- Required to check whether Wi-Fi is enabled --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <!-- Required to read and write the expansion files on shared storage --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
หมายเหตุ: โดยค่าเริ่มต้น ไลบรารี Downloader ต้องใช้ API ระดับ 4 แต่ไลบรารี ZIP การขยาย APK ต้องใช้ API ระดับ 5
การใช้บริการดาวน์โหลด
หากต้องการทำการดาวน์โหลดในเบื้องหลัง ไลบรารี Downloader จะมีService
ซับคลาสของตัวเองชื่อ DownloaderService
ที่คุณควรขยาย นอกเหนือจากการดาวน์โหลดไฟล์ส่วนขยายให้คุณแล้ว DownloaderService
ยังทําสิ่งต่อไปนี้ด้วย
- ลงทะเบียน
BroadcastReceiver
ที่คอยฟังการเปลี่ยนแปลงการเชื่อมต่อเครือข่ายของอุปกรณ์ (การออกอากาศCONNECTIVITY_ACTION
) เพื่อหยุดการดาวน์โหลดชั่วคราวเมื่อจำเป็น (เช่น การเชื่อมต่อขาดหายไป) และกลับมาดาวน์โหลดต่อเมื่อเป็นไปได้ (มีการเชื่อมต่อ) - ตั้งเวลาการปลุก
RTC_WAKEUP
เพื่อลองดาวน์โหลดอีกครั้งสำหรับกรณีที่บริการถูกหยุด - สร้าง
Notification
ที่กําหนดเองซึ่งแสดงความคืบหน้าการดาวน์โหลด รวมถึงข้อผิดพลาดหรือการเปลี่ยนแปลงสถานะ - อนุญาตให้แอปหยุดการดาวน์โหลดชั่วคราวและดาวน์โหลดต่อด้วยตนเอง
- ตรวจสอบว่าพื้นที่เก็บข้อมูลที่ใช้ร่วมกันนั้นพร้อมใช้งานและได้รับการต่อเชื่อมแล้ว ไม่มีไฟล์ดังกล่าวอยู่แล้ว และมีพื้นที่เพียงพอ ก่อนที่จะดาวน์โหลดไฟล์ขยาย จากนั้นจะแจ้งให้ผู้ใช้ทราบหากข้อมูลข้างต้นไม่ถูกต้อง
สิ่งที่ต้องทำมีเพียงสร้างคลาสในแอปที่ขยายคลาส DownloaderService
และลบล้างเมธอด 3 รายการเพื่อระบุรายละเอียดแอปที่เฉพาะเจาะจง ดังนี้
getPublicKey()
- การดำเนินการนี้ต้องแสดงผลสตริงที่เป็นคีย์สาธารณะ RSA ที่เข้ารหัส Base64 สำหรับบัญชีผู้เผยแพร่ของคุณ ซึ่งดูได้จากหน้าโปรไฟล์ใน Play Console (ดูการตั้งค่าสำหรับการอนุญาตให้ใช้สิทธิ)
getSALT()
- การดำเนินการนี้ต้องแสดงผลอาร์เรย์ไบต์แบบสุ่มที่
Policy
ที่ใช้เพื่อสร้างObfuscator
เกลือช่วยให้มั่นใจว่าไฟล์SharedPreferences
ที่มีการสร้างความสับสนซึ่งบันทึกข้อมูลการอนุญาตให้ใช้สิทธิจะไม่เหมือนใครและไม่สามารถค้นพบได้ getAlarmReceiverClassName()
- การดำเนินการนี้ต้องแสดงผลชื่อคลาสของ
BroadcastReceiver
ในแอปของคุณที่ควรได้รับการแจ้งเตือนว่าควรเริ่มการดาวน์โหลดอีกครั้ง (ซึ่งอาจเกิดขึ้นหากบริการดาวน์โหลดหยุดทำงานโดยไม่คาดคิด)
ตัวอย่างเช่น ต่อไปนี้คือการใช้งาน DownloaderService
ที่สมบูรณ์
Kotlin
// You must use the public key belonging to your publisher account const val BASE64_PUBLIC_KEY = "YourLVLKey" // You should also modify this salt val SALT = byteArrayOf( 1, 42, -12, -1, 54, 98, -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84 ) class SampleDownloaderService : DownloaderService() { override fun getPublicKey(): String = BASE64_PUBLIC_KEY override fun getSALT(): ByteArray = SALT override fun getAlarmReceiverClassName(): String = SampleAlarmReceiver::class.java.name }
Java
public class SampleDownloaderService extends DownloaderService { // You must use the public key belonging to your publisher account public static final String BASE64_PUBLIC_KEY = "YourLVLKey"; // You should also modify this salt public static final byte[] SALT = new byte[] { 1, 42, -12, -1, 54, 98, -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84 }; @Override public String getPublicKey() { return BASE64_PUBLIC_KEY; } @Override public byte[] getSALT() { return SALT; } @Override public String getAlarmReceiverClassName() { return SampleAlarmReceiver.class.getName(); } }
หมายเหตุ: คุณต้องอัปเดตค่า BASE64_PUBLIC_KEY
เป็นคีย์สาธารณะของบัญชีผู้เผยแพร่โฆษณา คุณดูคีย์ได้ใน Developer Console ในส่วนข้อมูลโปรไฟล์ ซึ่งจำเป็นต้องทำแม้กระทั่งเมื่อทดสอบการดาวน์โหลด
อย่าลืมประกาศบริการในไฟล์ Manifest
<app ...> <service android:name=".SampleDownloaderService" /> ... </app>
การติดตั้งใช้งานเครื่องรับสัญญาณเตือน
DownloaderService
จะตั้งเวลาการปลุก RTC_WAKEUP
เพื่อส่ง Intent
ไปยัง BroadcastReceiver
ในแอปของคุณ เพื่อตรวจสอบความคืบหน้าของการดาวน์โหลดไฟล์และเริ่มดาวน์โหลดอีกครั้งหากจําเป็น คุณต้องกําหนด BroadcastReceiver
เพื่อเรียก API จากคลังโปรแกรมดาวน์โหลดที่จะตรวจสอบสถานะการดาวน์โหลดและเริ่มดาวน์โหลดอีกครั้งหากจําเป็น
คุณเพียงต้องลบล้างเมธอด onReceive()
เพื่อเรียกใช้ DownloaderClientMarshaller.startDownloadServiceIfRequired()
เช่น
Kotlin
class SampleAlarmReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { try { DownloaderClientMarshaller.startDownloadServiceIfRequired( context, intent, SampleDownloaderService::class.java ) } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } } }
Java
public class SampleAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { try { DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, SampleDownloaderService.class); } catch (NameNotFoundException e) { e.printStackTrace(); } } }
โปรดทราบว่านี่คือคลาสที่คุณจะต้องแสดงชื่อในเมธอด getAlarmReceiverClassName()
ของบริการ (ดูส่วนก่อนหน้า)
อย่าลืมประกาศผู้รับในไฟล์ Manifest
<app ...> <receiver android:name=".SampleAlarmReceiver" /> ... </app>
กำลังเริ่มดาวน์โหลด
กิจกรรมหลักในแอป (กิจกรรมที่เริ่มต้นโดยไอคอนตัวเปิดแอป) จะมีหน้าที่รับผิดชอบในการยืนยันว่ามีไฟล์ขยายอยู่ในอุปกรณ์หรือไม่ และเริ่มการดาวน์โหลดหากไม่มี
คุณต้องทําตามขั้นตอนต่อไปนี้เพื่อเริ่มการดาวน์โหลดโดยใช้คลังโปรแกรมดาวน์โหลด
- ตรวจสอบว่าระบบดาวน์โหลดไฟล์แล้วหรือยัง
ไลบรารี Downloader มี API บางรายการในคลาส
Helper
เพื่อช่วยในกระบวนการนี้getExpansionAPKFileName(Context, c, boolean mainFile, int versionCode)
doesFileExist(Context c, String fileName, long fileSize)
ตัวอย่างเช่น แอปตัวอย่างที่ให้มาในแพ็กเกจการขยาย Apk จะเรียกใช้วิธีต่อไปนี้ในเมธอด
onCreate()
ของกิจกรรมเพื่อตรวจสอบว่ามีไฟล์ขยายอยู่ในอุปกรณ์แล้วหรือยังKotlin
fun expansionFilesDelivered(): Boolean { xAPKS.forEach { xf -> Helpers.getExpansionAPKFileName(this, xf.isBase, xf.fileVersion).also { fileName -> if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false)) return false } } return true }
Java
boolean expansionFilesDelivered() { for (XAPKFile xf : xAPKS) { String fileName = Helpers.getExpansionAPKFileName(this, xf.isBase, xf.fileVersion); if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false)) return false; } return true; }
ในกรณีนี้ ออบเจ็กต์
XAPKFile
แต่ละรายการจะมีหมายเลขเวอร์ชันและขนาดไฟล์ของไฟล์เสริมที่รู้จัก รวมถึงบูลีนว่าไฟล์นั้นเป็นไฟล์เสริมหลักหรือไม่ (ดูรายละเอียดได้ที่คลาสSampleDownloaderActivity
ของแอปตัวอย่าง)หากเมธอดนี้แสดงผลเป็นเท็จ แอปจะต้องเริ่มการดาวน์โหลด
- เริ่มการดาวน์โหลดโดยเรียกใช้เมธอดแบบคงที่
DownloaderClientMarshaller.startDownloadServiceIfRequired(Context c, PendingIntent notificationClient, Class<?> serviceClass)
โดยเมธอดนี้ใช้พารามิเตอร์ต่อไปนี้
context
:Context
ของแอปnotificationClient
:PendingIntent
เพื่อเริ่มกิจกรรมหลัก ซึ่งจะใช้ในNotification
ที่DownloaderService
สร้างขึ้นเพื่อแสดงความคืบหน้าในการดาวน์โหลด เมื่อผู้ใช้เลือกการแจ้งเตือน ระบบจะเรียกใช้PendingIntent
ที่คุณระบุที่นี่และควรเปิดกิจกรรมที่แสดงความคืบหน้าการดาวน์โหลด (โดยปกติจะเป็นกิจกรรมเดียวกันกับที่เริ่มการดาวน์โหลด)serviceClass
: ออบเจ็กต์Class
สำหรับการติดตั้งใช้งานDownloaderService
ซึ่งจําเป็นต่อการเริ่มบริการและเริ่มการดาวน์โหลด หากจําเป็น
เมธอดจะแสดงผลจำนวนเต็มที่ระบุว่าจำเป็นต้องดาวน์โหลดหรือไม่ ค่าที่เป็นไปได้มีดังนี้
NO_DOWNLOAD_REQUIRED
: แสดงผลหากไฟล์มีอยู่แล้วหรือมีการดาวน์โหลดอยู่LVL_CHECK_REQUIRED
: แสดงผลหากจำเป็นต้องมีการยืนยันใบอนุญาตเพื่อรับ URL ของไฟล์ขยายDOWNLOAD_REQUIRED
: แสดงผลหากระบบทราบ URL ของไฟล์ขยายอยู่แล้ว แต่ยังไม่ได้ดาวน์โหลด
โดยทั่วไปแล้ว
LVL_CHECK_REQUIRED
และDOWNLOAD_REQUIRED
มีลักษณะการทำงานเหมือนกัน และคุณไม่จําเป็นต้องกังวลเกี่ยวกับค่าเหล่านี้ ในกิจกรรมหลักที่เรียกstartDownloadServiceIfRequired()
คุณสามารถตรวจสอบได้ว่าคําตอบคือNO_DOWNLOAD_REQUIRED
หรือไม่ หากคำตอบเป็นค่าอื่นที่ไม่ใช่NO_DOWNLOAD_REQUIRED
แสดงว่าไลบรารีโปรแกรมดาวน์โหลดจะเริ่มการดาวน์โหลดและคุณควรอัปเดต UI ของกิจกรรมเพื่อแสดงความคืบหน้าของการดาวน์โหลด (ดูขั้นตอนถัดไป) หากคำตอบคือNO_DOWNLOAD_REQUIRED
แสดงว่าไฟล์พร้อมใช้งานและแอปของคุณจะเริ่มทำงานได้เช่น
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Check if expansion files are available before going any further if (!expansionFilesDelivered()) { val pendingIntent = // Build an Intent to start this activity from the Notification Intent(this, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP }.let { notifierIntent -> PendingIntent.getActivity( this, 0, notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT ) } // Start the download service (if required) val startResult: Int = DownloaderClientMarshaller.startDownloadServiceIfRequired( this, pendingIntent, SampleDownloaderService::class.java ) // If download has started, initialize this activity to show // download progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // This is where you do set up to display the download // progress (next step) ... return } // If the download wasn't necessary, fall through to start the app } startApp() // Expansion files are available, start the app }
Java
@Override public void onCreate(Bundle savedInstanceState) { // Check if expansion files are available before going any further if (!expansionFilesDelivered()) { // Build an Intent to start this activity from the Notification Intent notifierIntent = new Intent(this, MainActivity.getClass()); notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); ... PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT); // Start the download service (if required) int startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(this, pendingIntent, SampleDownloaderService.class); // If download has started, initialize this activity to show // download progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // This is where you do set up to display the download // progress (next step) ... return; } // If the download wasn't necessary, fall through to start the app } startApp(); // Expansion files are available, start the app }
- เมื่อเมธอด
startDownloadServiceIfRequired()
แสดงผลเป็นค่าอื่นที่ไม่ใช่NO_DOWNLOAD_REQUIRED
ให้สร้างอินสแตนซ์ของIStub
โดยการเรียกใช้DownloaderClientMarshaller.CreateStub(IDownloaderClient client, Class<?> downloaderService)
IStub
มีการเชื่อมโยงระหว่างกิจกรรมกับบริการดาวน์โหลดเพื่อให้กิจกรรมได้รับการเรียกกลับเกี่ยวกับความคืบหน้าของการดาวน์โหลดหากต้องการสร้างอินสแตนซ์
IStub
โดยการเรียกใช้CreateStub()
คุณต้องส่งผ่านการใช้งานอินเทอร์เฟซIDownloaderClient
และการใช้งานDownloaderService
ส่วนถัดไปเกี่ยวกับการรับความคืบหน้าการดาวน์โหลดจะกล่าวถึงอินเทอร์เฟซIDownloaderClient
ซึ่งโดยปกติแล้วคุณควรนำไปใช้ในคลาสActivity
เพื่อให้อัปเดต UI ของกิจกรรมได้เมื่อสถานะการดาวน์โหลดมีการเปลี่ยนแปลงเราขอแนะนำให้คุณเรียก
CreateStub()
เพื่อสร้างอินสแตนซ์IStub
ในระหว่างเมธอดonCreate()
ของกิจกรรม หลังจากที่startDownloadServiceIfRequired()
เริ่มการดาวน์โหลดตัวอย่างเช่น ในตัวอย่างโค้ดก่อนหน้าสําหรับ
onCreate()
คุณสามารถตอบสนองต่อผลการค้นหาstartDownloadServiceIfRequired()
ดังนี้Kotlin
// Start the download service (if required) val startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired( this@MainActivity, pendingIntent, SampleDownloaderService::class.java ) // If download has started, initialize activity to show progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // Instantiate a member instance of IStub downloaderClientStub = DownloaderClientMarshaller.CreateStub(this, SampleDownloaderService::class.java) // Inflate layout that shows download progress setContentView(R.layout.downloader_ui) return }
Java
// Start the download service (if required) int startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(this, pendingIntent, SampleDownloaderService.class); // If download has started, initialize activity to show progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // Instantiate a member instance of IStub downloaderClientStub = DownloaderClientMarshaller.CreateStub(this, SampleDownloaderService.class); // Inflate layout that shows download progress setContentView(R.layout.downloader_ui); return; }
หลังจากเมธอด
onCreate()
แสดงผลแล้ว กิจกรรมของคุณจะได้รับคําเรียกonResume()
ซึ่งคุณควรเรียกconnect()
ในIStub
โดยส่งContext
ของแอป ในทางกลับกัน คุณควรเรียกใช้disconnect()
ในonStop()
callback ของกิจกรรมKotlin
override fun onResume() { downloaderClientStub?.connect(this) super.onResume() } override fun onStop() { downloaderClientStub?.disconnect(this) super.onStop() }
Java
@Override protected void onResume() { if (null != downloaderClientStub) { downloaderClientStub.connect(this); } super.onResume(); } @Override protected void onStop() { if (null != downloaderClientStub) { downloaderClientStub.disconnect(this); } super.onStop(); }
การเรียกใช้
connect()
ในIStub
จะเชื่อมโยงกิจกรรมของคุณกับDownloaderService
เพื่อให้กิจกรรมได้รับการเรียกกลับเกี่ยวกับการเปลี่ยนแปลงสถานะการดาวน์โหลดผ่านอินเทอร์เฟซIDownloaderClient
ความคืบหน้าในการรับการดาวน์โหลด
หากต้องการรับข้อมูลอัปเดตเกี่ยวกับความคืบหน้าของการดาวน์โหลดและโต้ตอบกับ DownloaderService
คุณต้องติดตั้งใช้งานอินเทอร์เฟซ IDownloaderClient
ของ Downloader Library
โดยปกติแล้ว กิจกรรมที่คุณใช้เพื่อเริ่มการดาวน์โหลดควรใช้อินเทอร์เฟซนี้เพื่อแสดงความคืบหน้าของการดาวน์โหลดและส่งคําขอไปยังบริการ
วิธีการอินเทอร์เฟซที่จําเป็นสําหรับ IDownloaderClient
มีดังนี้
onServiceConnected(Messenger m)
- หลังจากสร้างอินสแตนซ์
IStub
ในกิจกรรมแล้ว คุณจะได้รับคําเรียกใช้เมธอดนี้ ซึ่งจะส่งออบเจ็กต์Messenger
ที่เชื่อมต่อกับอินสแตนซ์DownloaderService
หากต้องการส่งคำขอไปยังบริการ เช่น หยุดชั่วคราวและดาวน์โหลดต่อ คุณต้องเรียกใช้DownloaderServiceMarshaller.CreateProxy()
เพื่อรับอินเทอร์เฟซIDownloaderService
ที่เชื่อมต่อกับบริการการติดตั้งใช้งานที่แนะนํามีลักษณะดังนี้
Kotlin
private var remoteService: IDownloaderService? = null ... override fun onServiceConnected(m: Messenger) { remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply { downloaderClientStub?.messenger?.also { messenger -> onClientUpdated(messenger) } } }
Java
private IDownloaderService remoteService; ... @Override public void onServiceConnected(Messenger m) { remoteService = DownloaderServiceMarshaller.CreateProxy(m); remoteService.onClientUpdated(downloaderClientStub.getMessenger()); }
เมื่อเริ่มต้นออบเจ็กต์
IDownloaderService
แล้ว คุณจะส่งคําสั่งไปยังบริการดาวน์โหลดได้ เช่น หยุดชั่วคราวและดาวน์โหลดต่อ (requestPauseDownload()
และrequestContinueDownload()
) onDownloadStateChanged(int newState)
- บริการดาวน์โหลดจะเรียกใช้เมธอดนี้เมื่อมีการเปลี่ยนแปลงสถานะการดาวน์โหลด เช่น การดาวน์โหลดเริ่มต้นขึ้นหรือเสร็จสมบูรณ์
ค่า
newState
จะเป็นหนึ่งในค่าที่เป็นไปได้หลายค่าที่ระบุไว้ในค่าคงที่STATE_*
ของคลาสIDownloaderClient
หากต้องการแสดงข้อความที่เป็นประโยชน์ต่อผู้ใช้ คุณสามารถขอสตริงที่เกี่ยวข้องสำหรับสถานะแต่ละรายการได้โดยเรียกใช้
Helpers.getDownloaderStringResourceIDFromState()
ซึ่งจะแสดงรหัสทรัพยากรของสตริงใดสตริงหนึ่งที่อยู่ในชุดหนังสือของโปรแกรมดาวน์โหลด เช่น สตริง "การดาวน์โหลดหยุดชั่วคราวเนื่องจากคุณกำลังโรมมิ่ง" สอดคล้องกับSTATE_PAUSED_ROAMING
onDownloadProgress(DownloadProgressInfo progress)
- บริการดาวน์โหลดจะเรียกใช้เพื่อส่งออบเจ็กต์
DownloadProgressInfo
ซึ่งจะอธิบายข้อมูลต่างๆ เกี่ยวกับความคืบหน้าของการดาวน์โหลด รวมถึงเวลาที่เหลือโดยประมาณ ความเร็วปัจจุบัน ความคืบหน้าโดยรวม และจำนวนทั้งหมดเพื่อให้คุณอัปเดต UI ความคืบหน้าของการดาวน์โหลดได้
เคล็ดลับ: ดูตัวอย่างการเรียกกลับเหล่านี้ที่อัปเดต UI ความคืบหน้าการดาวน์โหลดได้ที่ SampleDownloaderActivity
ในแอปตัวอย่างที่มาพร้อมกับแพ็กเกจการขยาย Apk
เมธอดสาธารณะบางรายการสำหรับอินเทอร์เฟซ IDownloaderService
ที่อาจเป็นประโยชน์มีดังนี้
requestPauseDownload()
- หยุดการดาวน์โหลดชั่วคราว
requestContinueDownload()
- ดาวน์โหลดต่อจากตอนที่หยุดไว้
setDownloadFlags(int flags)
- ตั้งค่ากำหนดของผู้ใช้สำหรับประเภทเครือข่ายที่อนุญาตให้ดาวน์โหลดไฟล์ได้ การใช้งานปัจจุบันรองรับ Flag 1 รายการเท่านั้น ซึ่งก็คือ
FLAGS_DOWNLOAD_OVER_CELLULAR
แต่คุณเพิ่ม Flag อื่นๆ ได้ โดยค่าเริ่มต้น ระบบจะไม่เปิดใช้ Flag นี้ ดังนั้นผู้ใช้จึงต้องใช้ Wi-Fi เพื่อดาวน์โหลดไฟล์ส่วนขยาย คุณอาจต้องระบุค่ากำหนดของผู้ใช้เพื่อเปิดใช้การดาวน์โหลดผ่านเครือข่ายมือถือ ในกรณีนี้ คุณสามารถโทรหาหมายเลขต่อไปนี้Kotlin
remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply { ... setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR) }
Java
remoteService .setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR);
การใช้ APKExpansionPolicy
หากตัดสินใจที่จะสร้างบริการดาวน์โหลดของคุณเองแทนที่จะใช้คลังเครื่องมือดาวน์โหลดของ Google Play คุณควรใช้ APKExpansionPolicy
ที่ระบุไว้ในคลังการยืนยันใบอนุญาต คลาส APKExpansionPolicy
เกือบจะเหมือนกับ ServerManagedPolicy
(มีอยู่ใน Google Play License Verification Library) แต่มีการจัดการเพิ่มเติมสำหรับข้อมูลเพิ่มเติมในการตอบกลับไฟล์การขยาย APK
หมายเหตุ: หากคุณใช้คลังโปรแกรมดาวน์โหลดตามที่ได้อธิบายไว้ในส่วนก่อนหน้า คลังจะดำเนินการโต้ตอบกับ APKExpansionPolicy
ทั้งหมด คุณจึงไม่ต้องใช้คลาสนี้โดยตรง
คลาสนี้มีเมธอดที่จะช่วยให้คุณได้รับข้อมูลที่จําเป็นเกี่ยวกับไฟล์ส่วนขยายที่ใช้ได้ ดังนี้
getExpansionURLCount()
getExpansionURL(int index)
getExpansionFileName(int index)
getExpansionFileSize(int index)
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้ APKExpansionPolicy
เมื่อไม่ได้ใช้คลังเครื่องมือดาวน์โหลดได้ที่เอกสารประกอบสำหรับการเพิ่มการอนุญาตให้ใช้สิทธิในแอป ซึ่งอธิบายวิธีใช้นโยบายการอนุญาตให้ใช้สิทธิเช่นนี้
การอ่านไฟล์สำหรับขยาย
เมื่อบันทึกไฟล์ขยายของ APK ไว้ในอุปกรณ์แล้ว วิธีอ่านไฟล์จะขึ้นอยู่กับประเภทไฟล์ที่คุณใช้ ดังที่ได้กล่าวไว้ในภาพรวม ไฟล์ขยายอาจเป็นไฟล์ประเภทใดก็ได้ตามต้องการ แต่ระบบจะเปลี่ยนชื่อโดยใช้รูปแบบชื่อไฟล์ที่เฉพาะเจาะจงและบันทึกลงใน<shared-storage>/Android/obb/<package-name>/
ไม่ว่าคุณจะอ่านไฟล์ด้วยวิธีใด คุณควรตรวจสอบก่อนเสมอว่าพื้นที่เก็บข้อมูลภายนอกพร้อมให้อ่าน ผู้ใช้อาจต่อพื้นที่เก็บข้อมูลกับคอมพิวเตอร์ผ่าน USB หรือนำการ์ด SD ออกแล้ว
หมายเหตุ: เมื่อแอปเริ่มทำงาน คุณควรตรวจสอบเสมอว่าพื้นที่เก็บข้อมูลภายนอกพร้อมใช้งานและอ่านได้หรือไม่โดยเรียกใช้ getExternalStorageState()
ซึ่งจะแสดงผลสตริงที่เป็นไปได้ 1 รายการจากหลายรายการซึ่งแสดงสถานะของพื้นที่เก็บข้อมูลภายนอก ค่าที่แสดงผลต้องเป็น MEDIA_MOUNTED
เพื่อให้แอปอ่านได้
การรับชื่อไฟล์
ตามที่อธิบายไว้ในภาพรวม ระบบจะบันทึกไฟล์เสริมของ APK โดยใช้รูปแบบชื่อไฟล์ที่เฉพาะเจาะจง ดังนี้
[main|patch].<expansion-version>.<package-name>.obb
หากต้องการทราบตำแหน่งและชื่อของไฟล์ขยาย คุณควรใช้เมธอด getExternalStorageDirectory()
และ getPackageName()
เพื่อสร้างเส้นทางไปยังไฟล์
ต่อไปนี้คือเมธอดที่คุณใช้ในแอปเพื่อรับอาร์เรย์ที่มีเส้นทางที่สมบูรณ์ไปยังไฟล์ขยายทั้ง 2 ไฟล์
Kotlin
fun getAPKExpansionFiles(ctx: Context, mainVersion: Int, patchVersion: Int): Array<String> { val packageName = ctx.packageName val ret = mutableListOf<String>() if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) { // Build the full path to the app's expansion files val root = Environment.getExternalStorageDirectory() val expPath = File(root.toString() + EXP_PATH + packageName) // Check that expansion file path exists if (expPath.exists()) { if (mainVersion > 0) { val strMainPath = "$expPath${File.separator}main.$mainVersion.$packageName.obb" val main = File(strMainPath) if (main.isFile) { ret += strMainPath } } if (patchVersion > 0) { val strPatchPath = "$expPath${File.separator}patch.$mainVersion.$packageName.obb" val main = File(strPatchPath) if (main.isFile) { ret += strPatchPath } } } } return ret.toTypedArray() }
Java
// The shared path to all app expansion files private final static String EXP_PATH = "/Android/obb/"; static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) { String packageName = ctx.getPackageName(); Vector<String> ret = new Vector<String>(); if (Environment.getExternalStorageState() .equals(Environment.MEDIA_MOUNTED)) { // Build the full path to the app's expansion files File root = Environment.getExternalStorageDirectory(); File expPath = new File(root.toString() + EXP_PATH + packageName); // Check that expansion file path exists if (expPath.exists()) { if ( mainVersion > 0 ) { String strMainPath = expPath + File.separator + "main." + mainVersion + "." + packageName + ".obb"; File main = new File(strMainPath); if ( main.isFile() ) { ret.add(strMainPath); } } if ( patchVersion > 0 ) { String strPatchPath = expPath + File.separator + "patch." + mainVersion + "." + packageName + ".obb"; File main = new File(strPatchPath); if ( main.isFile() ) { ret.add(strPatchPath); } } } } String[] retArray = new String[ret.size()]; ret.toArray(retArray); return retArray; }
คุณสามารถเรียกใช้เมธอดนี้ได้โดยส่งContext
แอปของคุณและเวอร์ชันของไฟล์สำหรับขยายที่ต้องการ
คุณระบุหมายเลขเวอร์ชันของไฟล์ขยายได้หลายวิธี วิธีง่ายๆ วิธีหนึ่งคือการบันทึกเวอร์ชันในไฟล์ SharedPreferences
เมื่อการดาวน์โหลดเริ่มต้นขึ้น โดยค้นหาชื่อไฟล์ส่วนขยายด้วยเมธอด getExpansionFileName(int index)
ของคลาส APKExpansionPolicy
จากนั้นคุณจะได้รับรหัสเวอร์ชันโดยการอ่านไฟล์ SharedPreferences
เมื่อต้องการเข้าถึงไฟล์ส่วนขยาย
ดูข้อมูลเพิ่มเติมเกี่ยวกับการอ่านจากพื้นที่เก็บข้อมูลที่ใช้ร่วมกันได้ในเอกสารประกอบพื้นที่เก็บข้อมูล
การใช้คลัง ZIP สำหรับขยาย APK
แพ็กเกจการขยาย Apk ของ Google Market มีไลบรารีที่เรียกว่า APK Expansion Zip Library (อยู่ใน <sdk>/extras/google/google_market_apk_expansion/zip_file/
) ซึ่งเป็นไลบรารีที่ไม่บังคับซึ่งจะช่วยคุณอ่านไฟล์สำหรับขยายเมื่อบันทึกเป็นไฟล์ ZIP การใช้ไลบรารีนี้ช่วยให้คุณอ่านทรัพยากรจากไฟล์ ZIP ที่ขยายเป็นระบบไฟล์เสมือนได้อย่างง่ายดาย
ไลบรารี ZIP ของส่วนขยาย APK มีคลาสและ API ต่อไปนี้
APKExpansionSupport
- ระบุวิธีการเข้าถึงชื่อไฟล์ขยายและไฟล์ ZIP ดังนี้
getAPKExpansionFiles()
- วิธีการเดียวกันกับที่แสดงด้านบนซึ่งแสดงเส้นทางไฟล์ที่สมบูรณ์ไปยังไฟล์ขยายทั้ง 2 ไฟล์
getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion)
- แสดงผล
ZipResourceFile
ที่แสดงผลรวมของทั้งไฟล์หลักและไฟล์แพตช์ กล่าวคือ หากคุณระบุทั้งmainVersion
และpatchVersion
ระบบจะแสดงผลZipResourceFile
ที่ให้สิทธิ์การอ่านข้อมูลทั้งหมด โดยผสานข้อมูลของไฟล์แพตช์ไว้ด้านบนของไฟล์หลัก
ZipResourceFile
- แสดงไฟล์ ZIP ในพื้นที่เก็บข้อมูลที่ใช้ร่วมกันและดำเนินการทั้งหมดเพื่อให้ระบบไฟล์เสมือนตามไฟล์ ZIP คุณรับอินสแตนซ์ได้โดยใช้
APKExpansionSupport.getAPKExpansionZipFile()
หรือZipResourceFile
โดยส่งเส้นทางไปยังไฟล์การขยาย คลาสนี้มีเมธอดที่มีประโยชน์มากมาย แต่โดยทั่วไปแล้วคุณไม่จำเป็นต้องเข้าถึงเมธอดส่วนใหญ่ วิธีการสําคัญ 2 วิธี ได้แก่getInputStream(String assetPath)
- ระบุ
InputStream
เพื่ออ่านไฟล์ภายในไฟล์ ZIPassetPath
ต้องเป็นเส้นทางไปยังไฟล์ที่ต้องการ โดยสัมพันธ์กับรูทของเนื้อหาไฟล์ ZIP getAssetFileDescriptor(String assetPath)
- ระบุ
AssetFileDescriptor
สำหรับไฟล์ภายในไฟล์ ZIPassetPath
ต้องเป็นเส้นทางไปยังไฟล์ที่ต้องการ โดยสัมพันธ์กับรูทของเนื้อหาไฟล์ ZIP ซึ่งจะเป็นประโยชน์สําหรับ API ของ Android บางรายการที่ต้องใช้AssetFileDescriptor
เช่น API ของMediaPlayer
บางรายการ
APEZProvider
- แอปส่วนใหญ่ไม่จำเป็นต้องใช้คลาสนี้ คลาสนี้กำหนด
ContentProvider
ที่จัดระเบียบข้อมูลจากไฟล์ ZIP ผ่านผู้ให้บริการเนื้อหาUri
เพื่อให้สิทธิ์เข้าถึงไฟล์สำหรับ Android API บางรายการที่คาดหวังสิทธิ์เข้าถึงUri
สำหรับไฟล์สื่อ เช่น คำสั่งนี้มีประโยชน์ในกรณีที่คุณต้องการเล่นวิดีโอด้วยVideoView.setVideoURI()
การข้ามการบีบอัดไฟล์สื่อเป็น ZIP
หากคุณใช้ไฟล์สำหรับขยายเพื่อจัดเก็บไฟล์สื่อ ไฟล์ ZIP จะยังคงให้คุณใช้การเรียกใช้การเล่นสื่อของ Android ที่มีการควบคุมการเลื่อนและความยาว (เช่น MediaPlayer.setDataSource()
และ SoundPool.load()
) ได้ คุณต้องไม่ทำการบีบอัดไฟล์สื่อเพิ่มเติมเมื่อสร้างแพ็กเกจ ZIP เพื่อให้การดำเนินการนี้ทำงานได้ เช่น เมื่อใช้เครื่องมือ zip
คุณควรใช้ตัวเลือก -n
เพื่อระบุนามสกุลไฟล์ที่ไม่ควรบีบอัด
zip -n .mp4;.ogg main_expansion media_files
การอ่านจากไฟล์ ZIP
เมื่อใช้ไลบรารี ZIP ของ APK Expansion การอ่านไฟล์จาก ZIP มักจะต้องใช้สิ่งต่อไปนี้
Kotlin
// Get a ZipResourceFile representing a merger of both the main and patch files val expansionFile = APKExpansionSupport.getAPKExpansionZipFile(appContext, mainVersion, patchVersion) // Get an input stream for a known file inside the expansion file ZIPs expansionFile.getInputStream(pathToFileInsideZip).use { ... }
Java
// Get a ZipResourceFile representing a merger of both the main and patch files ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(appContext, mainVersion, patchVersion); // Get an input stream for a known file inside the expansion file ZIPs InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);
โค้ดด้านบนให้สิทธิ์เข้าถึงไฟล์ที่อยู่ในไฟล์สำหรับขยายหลักหรือไฟล์สำหรับขยายแพตช์ โดยการอ่านจากแผนที่ที่ผสานไฟล์ทั้งหมดจากทั้ง 2 ไฟล์ สิ่งที่คุณจำเป็นต้องระบุในเมธอด getAPKExpansionFile()
คือ android.content.Context
ของแอปและหมายเลขเวอร์ชันของทั้งไฟล์สำหรับขยายหลักและไฟล์สำหรับขยายแพตช์
หากต้องการอ่านจากไฟล์สำหรับขยายที่เฉพาะเจาะจง ให้ใช้คอนสตรัคเตอร์ ZipResourceFile
พร้อมเส้นทางไปยังไฟล์สำหรับขยายที่ต้องการ ดังนี้
Kotlin
// Get a ZipResourceFile representing a specific expansion file val expansionFile = ZipResourceFile(filePathToMyZip) // Get an input stream for a known file inside the expansion file ZIPs expansionFile.getInputStream(pathToFileInsideZip).use { ... }
Java
// Get a ZipResourceFile representing a specific expansion file ZipResourceFile expansionFile = new ZipResourceFile(filePathToMyZip); // Get an input stream for a known file inside the expansion file ZIPs InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ไลบรารีนี้สำหรับไฟล์ขยายได้จากคลาส SampleDownloaderActivity
ของแอปตัวอย่าง ซึ่งมีโค้ดเพิ่มเติมเพื่อตรวจสอบไฟล์ที่ดาวน์โหลดโดยใช้ CRC โปรดทราบว่าหากใช้ตัวอย่างนี้เป็นพื้นฐานสําหรับการใช้งานของคุณเอง คุณจะต้องประกาศขนาดไบต์ของไฟล์ขยายในอาร์เรย์ xAPKS
การทดสอบไฟล์สำหรับขยาย
ก่อนเผยแพร่แอป คุณควรทดสอบ 2 อย่าง ได้แก่ การอ่านไฟล์เสริมและการดาวน์โหลดไฟล์
การทดสอบการอ่านไฟล์
ก่อนอัปโหลดแอปไปยัง Google Play คุณควรทดสอบความสามารถของแอปในการอ่านไฟล์จากพื้นที่เก็บข้อมูลที่แชร์ สิ่งที่คุณต้องทำคือเพิ่มไฟล์ไปยังตำแหน่งที่เหมาะสมในพื้นที่เก็บข้อมูลที่ใช้ร่วมกันของอุปกรณ์ แล้วเปิดแอป
- ในอุปกรณ์ ให้สร้างไดเรกทอรีที่เหมาะสมในพื้นที่เก็บข้อมูลที่ใช้ร่วมกันซึ่ง Google Play จะบันทึกไฟล์
เช่น หากชื่อแพ็กเกจคือ
com.example.android
คุณจะต้องสร้างไดเรกทอรีAndroid/obb/com.example.android/
ในพื้นที่เก็บข้อมูลที่ใช้ร่วมกัน (เสียบอุปกรณ์ทดสอบเข้ากับคอมพิวเตอร์เพื่อต่อเชื่อมพื้นที่เก็บข้อมูลที่ใช้ร่วมกันและสร้างไดเรกทอรีนี้ด้วยตนเอง) - เพิ่มไฟล์สำหรับขยายลงในไดเรกทอรีดังกล่าวด้วยตนเอง อย่าลืมเปลี่ยนชื่อไฟล์ให้ตรงกับรูปแบบชื่อไฟล์ที่ Google Play จะใช้
ตัวอย่างเช่น ไฟล์เสริมหลักสำหรับแอป
com.example.android
ควรเป็นmain.0300110.com.example.android.obb
ไม่ว่าไฟล์จะเป็นประเภทใดก็ตาม รหัสเวอร์ชันจะเป็นค่าใดก็ได้ตามต้องการ โปรดทราบว่า- ไฟล์เสริมหลักจะขึ้นต้นด้วย
main
เสมอ และไฟล์แพตช์จะขึ้นต้นด้วยpatch
- ชื่อแพ็กเกจต้องตรงกับชื่อของ APK ที่แนบไฟล์ใน Google Play เสมอ
- ไฟล์เสริมหลักจะขึ้นต้นด้วย
- เมื่อไฟล์สำหรับขยายอยู่ในอุปกรณ์แล้ว คุณสามารถติดตั้งและเรียกใช้แอปเพื่อทดสอบไฟล์สำหรับขยายได้
โปรดทราบข้อมูลต่อไปนี้เกี่ยวกับการจัดการไฟล์ขยาย
- อย่าลบหรือเปลี่ยนชื่อไฟล์ขยาย
.obb
(แม้ว่าคุณจะแตกไฟล์ข้อมูลไปยังตำแหน่งอื่นก็ตาม) เนื่องจากการดำเนินการดังกล่าวจะทำให้ Google Play (หรือแอปของคุณเอง) ดาวน์โหลดไฟล์สำหรับขยายซ้ำๆ - อย่าบันทึกข้อมูลอื่นๆ ลงใน
obb/
ไดเรกทอรี หากต้องแตกไฟล์ข้อมูล ให้บันทึกข้อมูลดังกล่าวไว้ในตำแหน่งที่getExternalFilesDir()
ระบุ
การทดสอบการดาวน์โหลดไฟล์
เนื่องจากบางครั้งแอปของคุณจะต้องดาวน์โหลดไฟล์เสริมด้วยตนเองเมื่อเปิดแอปเป็นครั้งแรก คุณจึงควรทดสอบกระบวนการนี้เพื่อให้แน่ใจว่าแอปสามารถค้นหา URL, ดาวน์โหลดไฟล์ และบันทึกลงในอุปกรณ์ได้
หากต้องการทดสอบการใช้ขั้นตอนการดาวน์โหลดด้วยตนเองของแอป คุณสามารถเผยแพร่แอปไปยังแทร็กทดสอบภายในเพื่อให้พร้อมใช้งานสำหรับผู้ทดสอบที่ได้รับอนุญาตเท่านั้น หากทุกอย่างทำงานตามที่คาดไว้ แอปควรเริ่มดาวน์โหลดไฟล์ส่วนขยายทันทีที่กิจกรรมหลักเริ่มต้น
หมายเหตุ: ก่อนหน้านี้คุณสามารถทดสอบแอปโดยการอัปโหลดเวอร์ชัน "ฉบับร่าง" ที่ไม่ได้เผยแพร่ ระบบไม่รองรับฟังก์ชันนี้อีกต่อไป แต่ต้องเผยแพร่แอปไปยังแทร็กการทดสอบภายใน แบบปิด หรือแบบเปิดแทน ดูข้อมูลเพิ่มเติมได้ที่หัวข้อระบบไม่รองรับแอปฉบับร่างอีกต่อไป
การอัปเดตแอป
ประโยชน์ที่ยอดเยี่ยมอย่างหนึ่งของการใช้ไฟล์สำหรับขยายใน Google Play คือความสามารถในการอัปเดตแอปโดยไม่ต้องดาวน์โหลดเนื้อหาต้นฉบับทั้งหมดอีกครั้ง เนื่องจาก Google Play อนุญาตให้คุณระบุไฟล์สำหรับขยาย 2 ไฟล์กับ APK แต่ละไฟล์ คุณจึงใช้ไฟล์ที่ 2 เป็น "แพตช์" ที่อัปเดตและเพิ่มชิ้นงานใหม่ได้ ซึ่งจะช่วยหลีกเลี่ยงความจำเป็นในการดาวน์โหลดไฟล์ส่วนขยายหลักอีกครั้งซึ่งอาจมีขนาดใหญ่และทำให้ผู้ใช้เสียค่าใช้จ่าย
ไฟล์สำหรับขยายแพตช์นั้นในทางเทคนิคแล้วเหมือนกับไฟล์สำหรับขยายหลัก และทั้งระบบ Android และ Google Play จะไม่ทำการแพตช์จริงระหว่างไฟล์สำหรับขยายหลักและไฟล์สำหรับขยายแพตช์ โค้ดแอปของคุณต้องทำการแพตช์ที่จำเป็นด้วยตนเอง
หากคุณใช้ไฟล์ ZIP เป็นไฟล์สำหรับขยาย คลัง ZIP สำหรับขยาย APK ที่รวมอยู่ในแพ็กเกจการขยาย APK จะสามารถผสานไฟล์แพตช์เข้ากับไฟล์สำหรับขยายหลักได้
หมายเหตุ: แม้ว่าจะต้องทำการเปลี่ยนแปลงเฉพาะในไฟล์แพตช์ Expansion แต่คุณก็ยังต้องอัปเดต APK เพื่อให้ Google Play ทำการอัปเดต
หากไม่ต้องการเปลี่ยนแปลงโค้ดในแอป คุณก็เพียงแค่อัปเดต versionCode
ในไฟล์ Manifest
ตราบใดที่คุณไม่เปลี่ยนไฟล์สำหรับขยายหลักที่เชื่อมโยงกับ APK ใน Play Console ผู้ใช้ที่เคยติดตั้งแอปของคุณจะไม่ดาวน์โหลดไฟล์สำหรับขยายหลัก ผู้ใช้ปัจจุบันจะได้รับเฉพาะ APK ที่อัปเดตแล้วและไฟล์แพตช์สำหรับขยายเวอร์ชันใหม่ (เก็บไฟล์สำหรับขยายหลักเวอร์ชันก่อนหน้าไว้)
ปัญหาที่ควรทราบเกี่ยวกับการอัปเดตไฟล์ส่วนขยายมีดังนี้
- แอปของคุณจะมีไฟล์เสริมได้เพียง 2 ไฟล์พร้อมกัน ไฟล์เสริมหลัก 1 ไฟล์และไฟล์เสริมแพตช์ 1 ไฟล์ ในระหว่างการอัปเดตไฟล์ Google Play จะลบเวอร์ชันก่อนหน้า (และแอปของคุณก็จะต้องดำเนินการเช่นเดียวกันเมื่อทำการอัปเดตด้วยตนเอง)
- เมื่อเพิ่มไฟล์สำหรับขยายที่เป็นแพตช์ ระบบ Android จะไม่แพตช์แอปหรือไฟล์สำหรับขยายหลัก คุณต้องออกแบบแอปให้รองรับข้อมูลแพตช์ อย่างไรก็ตาม แพ็กเกจการขยาย Apk มีไลบรารีสำหรับใช้ไฟล์ ZIP เป็นไฟล์สำหรับขยาย ซึ่งจะผสานข้อมูลจากไฟล์แพตช์ลงในไฟล์สำหรับขยายหลักเพื่อให้คุณอ่านข้อมูลไฟล์สำหรับขยายทั้งหมดได้อย่างง่ายดาย