ผู้ที่หลงเข้ามาอ่านหลายๆคนอาจจะรู้จักกับ Android App Bundle กันบ้างแล้ว เพราะว่า Google Play เริ่มแนะนำให้นักพัฒนาแอปเปลี่ยนมาใช้ Android App Bundle แทน APK เพื่อส่งแอปขึ้น Google Play และในวันนี้ขอหยิบเรื่องราวต่างๆของ Android App Bundle เพื่อให้เข้าใจกันมากขึ้นครับ

บทความในซีรีย์เดียวกัน

Android App Bundle (AAB) คืออะไร?

Android App Bundle หรือ AAB เป็น Publishing Format แบบใหม่ ที่ทีมพัฒนาของ Google ประกาศเปิดตัวในงาน Google I/O 2018 โดยเป็น Format ที่มีนามสกุลไฟล์เป็น .aab เพื่อให้นักพัฒนาใช้ส่งขึ้น Google Play แทน APK แบบเดิมๆ แล้วทาง Google Play จะนำ AAB ไปสร้างเป็น APK ให้ผู้ใช้ในทีหลัง

จุดชูโรงของ AAB ก็คือ APK ที่ Google Play ส่งให้กับผู้ใช้จะเป็น Optimized APK โดยตัดไฟล์ที่ไม่จำเป็นต่อเครื่องนั้นๆออกไป ทำให้ผู้ใช้เวลาดาวน์โหลดน้อยลง เพราะไฟล์มีขนาดเล็กลง

ซึ่ง AAB จะช่วยอำนวยความสะดวกให้กับนักพัฒนาในเรื่อง App Distribution โดยไม่ส่งผลอะไรต่อ Development เลย (ตราบใดที่ทำตาม Best Practice Guideline ของแอนดรอยด์อยู่แล้ว)

โดย Google Play ก็ไม่ได้บังคับให้นักพัฒนาเปลี่ยนจาก APK เป็น AAB เลยนะ แต่เพิ่มเข้ามาเป็นทางเลือก (ที่ดีกว่า) ให้กับนักพัฒนาเท่านั้น

ปัญหา App Distribution แบบเก่าและที่มาของ Android App Bundle

เพื่อให้เข้าใจถึงความสำคัญของ AAB มากขึ้น มาดูกันว่านักพัฒนาในอดีตจะต้องทำอะไร และเจอปัญหาอะไรจากการส่ง APK ขึ้น Google Play โดยตรง

Universal APK Publishing

เวลาที่พัฒนาแอปจนเสร็จ และต้องการส่งขึ้น Google Play เพื่อให้ผู้ใช้สามารถดาวน์โหลดได้ นักพัฒนาก็จะต้อง Build ให้กลายเป็น Signed APK แล้วอัปโหลดไฟล์นี้ขึ้น Google Play

ถ้าไม่ได้ทำอะไรกับ APK มากนัก มักจะเป็น APK ที่เรียกกันว่า Universal APK ไม่ว่าจะเป็นอุปกรณ์แอนดรอยด์รุ่นไหนก็ติดตั้งผ่าน APK ตัวนี้ได้ทั้งหมด (เว้นแต่ว่านักพัฒนาตั้งใจทำให้ไม่รองรับเสียเอง)

วิธีนี้ง่ายที่สุด แต่ก็ทำให้ผู้ใช้แบกรับขนาดไฟล์ที่ใหญ่มากเช่นกัน

จากภาพตัวอย่างข้างบนจะเห็นว่าเมื่อติดตั้ง Universal APK ลงใน Google Pixel 4 ก็จะมี Resource บางส่วนที่ไม่ได้ใช้งานบนเครื่องนั้นเลย

โดย Resource ที่ไม่จำเป็นเหล่านั้นก็มีขนาดรวมกันไม่ใช่น้อยๆ เพราะนอกจากเสียเวลาโหลดนานขึ้นแล้ว ขนาดแอปที่ติดตั้งลงในเครื่องก็มีขนาดใหญ่ด้วยเช่นกัน และกลายเป็นเหตุผลที่ทำให้ผู้ใช้ไม่พอใจ

เพื่อแก้ปัญหาแอปที่มีขนาดใหญ่เกินจำเป็น จึงเปลี่ยนมาใช้วิธี…

Multiple APK Publishing

นั่นก็คือการสร้าง APK เป็นหลายๆไฟล์ โดยแยกตาม Resource ที่เหมาะสมกับแต่ละเครื่อง

สำหรับแอปที่ไม่ได้มีขนาดใหญ่มากนัก การใช้ Multiple APK จะนิยมแยกตาม Native Library เท่านั้น เพราะว่าเป็นไฟล์ที่มีขนาดใหญ่จนมีนัยยะสำคัญ

แต่ถ้าเป็นแอปที่ใหญ่มากๆระดับนึง ต่อให้เป็น Android Resource ก็อาจจะมีขนาดใหญ่มากได้เช่นกัน ทว่าการแยกทั้ง Native Library และ Android Resource นั้น ไม่ใช่เรื่องตลกซักเท่าไรสำหรับนักพัฒนา

ยิ่งมี Factor สำหรับการสร้าง Multiple APK มากเท่าไร จำนวน APK ที่จะต้องสร้างก็จะทวีคูณมากขึ้นเท่านั้น และส่งผลให้ Build Time สำหรับการ Release ในแต่ละครั้งนานมากขึ้นตามจำนวน APK ที่ต้องสร้าง

ลองนึกภาพว่าแอปของผู้ที่หลงเข้ามาอ่านมีขนาดใหญ่มาก พยายาม Optimize Build Time มากที่สุดเท่าที่ทำได้แล้ว แต่ก็ยังมี Build Time นานถึง 10 นาทีต่อ APK นั่นหมายความว่าถ้าต้องการแยก Multiple APK ตามภาพข้างบน ก็จะต้องใช้เวลาทั้งหมด 160 นาทีหรือก็คือ 2 ชั่วโมง 40 นาที!?

จึงเป็นที่มาของ

Android App Bundle Publishing

เพื่อให้อุปกรณ์แอนดรอยด์แต่ละเครื่องโหลด APK ที่มีแต่ Resource เท่าที่จำเป็น จะได้เป็น APK ที่มีขนาดเล็ก ติดตั้งลงเครื่องแล้วกินพื้นที่น้อยลง และนักพัฒนาไม่ต้องเสียเวลาทำ Multiple APK ให้เยอะแยะ จึงสร้าง AAB ขึ้นมา เพื่อให้นักพัฒนาไม่ต้องสร้าง APK เอง แต่เปลี่ยนไปสร้าง AAB แค่ไฟล์เดียวก็พอ แล้วส่งขึ้น Google Play ซะ

แล้ว Google Play ก็จะสร้าง APK จาก AAB ออกมาเป็นหลายๆชุด เพื่อส่งให้ผู้ใช้ในตอนที่ดาวน์โหลดแอปนั่นเอง

ประโยชน์อื่นๆจากการใช้ Android App Bundle

นอกจากความสะดวกในเรื่อง App Distribution แล้ว การใช้ Android App Bundle ยังทำให้นักพัฒนาสามารถเพิ่มลูกเล่นและความสามารถพิเศษเข้าไปในแอปได้ ดังนี้

On-demand Dynamic Feature หรือ Dynamic Feature Delivery

นักพัฒนาสามารถกำหนดได้ว่าจะให้ Feature ไหนในแอปแยกออกมาสำหรับให้ผู้ใช้เลือกดาวน์โหลดทีหลังได้ และเมื่อผู้ใช้ต้องการใช้ Feature นั้นๆ ก็ให้แอปดาวน์โหลด Feature เพิ่มเข้ามาในเครื่องทีหลัง

ความสามารถนี้จะเหมาะกับแอปที่มี Feature เยอะมากๆจนแอปมีขนาดใหญ่ เพราะสามารถแยกได้ว่า Feature ไหนสำคัญและจำเป็นต้องมี ก็ดาวน์โหลดตั้งแต่ตอนติดตั้งแอปเลย และ Feature ไหนไม่ได้สำคัญมาก บางคนใช้ บางคนไม่ได้ใช้ ก็ให้ดาวน์โหลดเพิ่มทีหลังได้

ซึ่งจะช่วยให้แอปที่ผู้ใช้ดาวน์โหลดเพื่อติดตั้งในตอนแรกมีขนาดเล็ก และ Feature ไหนที่ผู้ใช้ไม่ได้ใช้ก็ไม่ต้องติดตั้งให้กินพื้นที่เครื่องโดยเปล่าประโยชน์

Dynamic Asset Delivery

จะคล้ายกับ Dynamic Feature Delivery แต่เปลี่ยนมาเป็น Asset แทน ซึ่งจะเหมาะกับแอปจำพวกเกมขนาดใหญ่ที่เก็บไว้เป็น Asset และอยากให้ผู้ใช้ดาวน์โหลดเพิ่มทีหลังในเวลาที่ต้องการ

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

ซึ่งปกติแล้วนักพัฒนาจะต้องทำระบบสำหรับดาวน์โหลดข้อมูลในเกมเพิ่มเอง แต่เมื่อใช้ AAB ก็จะใช้ความสามารถนี้ได้ทันที โดยสามารถกำหนดเงื่อนไขในการดาวน์โหลด Asset ได้ถึง 3 แบบด้วยกัน

  • Install Time : ดาวน์โหลดตั้งแต่ตอนติดตั้งแอป
  • Fast Follow : เริ่มดาวน์โหลดทันทีเมื่อผู้ใช้เปิดใช้งานแอป
  • On Demand : ดาวน์โหลดในระหว่างที่ใช้งานแอปอยู่

Dynamic Language Delivery

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

โดยปกติแล้วความสามารถนี้จะทำงานโดยอัตโนมัติเมื่อใช้งาน AAB เมื่อผู้ใช้ทำการเปลี่ยนภาษาในเครื่องของตัวเองเป็นภาษาอื่นๆนอกเหนือจากที่ดาวน์โหลดไว้ Google Play ก็จะทำการดาวน์โหลดเพิ่มให้ทันที

และสำหรับแอปที่สามารถเปลี่ยนภาษาได้ในตัว ก็สามารถใช้คำสั่งเพื่อให้ดาวน์โหลดภาษาเพิ่มจาก Google Play ได้เช่นกัน

Google Play Instant Supporting

นักพัฒนาสามารถทำให้แอปรองรับกับ Google Play Instant ได้ทันที ถ้า Core หรือ Base Module นั้นสามารถทำงานได้ในตัวและตรงกับเงื่อนไขของแอปที่จะรองรับ Google Play Instant

เบื้องหลังในการทำงานของ Android App Bundle

ด้วยความสามารถอันน่ามหัศจรรย์จึงทำให้นักพัฒนาแอปส่วนใหญ่เริ่มเปลี่ยนมาใช้ AAB กันแล้ว จากเมื่อก่อนที่มีการตั้งคำถามหรือข้อสงสัยกันมากมายถึงปัญหาที่อาจจะเกิดขึ้นจากการใช้ AAB แทน APK

ทำไมการใช้ AAB ถึงทำให้ผู้ใช้สามารถดาวน์โหลด Resource เพิ่มเข้าไปทีหลังได้ล่ะ? เป็นความสามารถของ Google Play อย่างนั้นหรือ?

จริงๆแล้ว เบื้องหลังความสามารถของ AAB นี้มาจากความสามารถที่ชื่อว่า Split APKs ในแอนดรอยด์

Split APKs คืออะไร?

ตั้งแต่ Android 5.0 Lollipop เป็นต้นมา ระบบแอนดรอยด์นั้นรองรับการติดตั้งแอปแบบ Split APKs ได้ ซึ่งเป็นการติดตั้งแอปด้วย APK หลายๆไฟล์ในแอปนั้นๆ โดยที่ APK แต่ละตัวจะต้องมี Resource ข้างในไม่ Conflict กัน

มันเป็นยังไงหว่า? นึกภาพไม่ออกละสิ

โดยปกติแล้ว APK ที่สมบูรณ์และสามารถทำงานได้ จะต้องประกอบไปด้วยข้อมูลข้างในดังนี้

ถ้าขาดอย่างใดอย่างนึงไป แอปก็จะทำงานไม่ได้ หรือทำงานได้ไม่สมบูรณ์

แต่สำหรับ Split APKs นั้นคือการแยกข้อมูลเหล่านี้ออกมาเป็น APK ของใครของมัน โดยที่ข้อมูลใน APK แต่ละตัวก็ไม่ได้ทับซ้อนกัน

ในแต่ละ APK ก็จะมี Manifest อยู่ด้วย แต่ข้อมูลที่อยู่ใน Manifest จะเก็บข้อมูลแยกกัน และจะไม่ Conflict กับ Manifest ที่อยู่ใน APK ตัวอื่น

และ APK ทุกตัวนั้นก็จะรวมไว้ในไฟล์ที่เรียกว่า APKS โดยมีนามสกุลเป็น .apks

โดยที่ Split APKs จะแบ่ง APK ออกเป็น 2 ประเภทด้วยกัน

Base APK (หรือ Master)

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

Configuration APK

APK สำหรับเก็บข้อมูลแยกตามเงื่อนไขต่างๆ ที่อาจจะสำคัญต่อ Configuration สำหรับอุปกรณ์แอนดรอยด์บางเครื่องเท่านั้น โดยสามารถมีได้มากกว่า 1 ตัว และเก็บข้อมูลได้เหมือนกับ Base APK แต่ห้าม Conflict กัน

จึงสามารถสร้าง Configuration APK แยกออกมาเป็นหลายๆตัวได้ เพื่อในการติดตั้งแอปสำหรับแต่ละเครื่องที่ต้องการ Resource แตกต่างกัน

เมื่อลองใช้ ADB Command เพื่อเช็ค Path ของแอปที่ติดตั้งอยู่ในเครื่อง ก็จะเห็นว่าแอปที่เป็น AAB นั้นมีการติดตั้ง APK ไว้มากกว่า 1 ตัว

akexorcist-mbp:~ akexorcist$ adb shell pm path com.twitter.android
package:/data/app/com.twitter.android-r4qFye0Q5_AP4bNd8upcxw==/base.apk
package:/data/app/com.twitter.android-r4qFye0Q5_AP4bNd8upcxw==/split_config.arm64_v8a.apk
package:/data/app/com.twitter.android-r4qFye0Q5_AP4bNd8upcxw==/split_config.en.apk
package:/data/app/com.twitter.android-r4qFye0Q5_AP4bNd8upcxw==/split_config.th.apk
package:/data/app/com.twitter.android-r4qFye0Q5_AP4bNd8upcxw==/split_config.xxhdpi.apk

โดย Base APK จะใช้ชื่อไฟล์ว่า base.apk ส่วน Configuration APK จะใช้ชื่อไฟล์ขึ้นต้นด้วยคำว่า split นั่นเอง

ด้วยความสามารถของ Split APKs จึงทำให้ Google Play นำมาประยุกต์ใช้งานใน Android App Bundle เพื่อช่วยให้ APK ที่แต่ละเครื่องต้องดาวน์โหลดมีขนาดลดลง รวมไปถึงความสามารถอย่าง Dynamic Feature Delivery ด้วย

และแน่นอนว่า Feature ใน Dynamic Feature Delivery ก็จะถูก Google Play จับแบ่งเป็น APK หลายๆตัวเช่นกัน

ซึ่งการ Build จาก AAB ให้กลายเป็น APK หลายๆตัวแบบนี้จะมีชื่อเรียกว่า Configuration APKs

ความแตกต่างระหว่างการ Build แบบ Multiple APKs กับแบบ Configuration APKs

การ Build แบบ Multiple APKs เป็นการสร้าง APK ออกมาหลายๆตัว โดยแต่ละตัวจะเกิดจากการผสม Configuration ระหว่างแต่ละ Dimension เข้าด้วยกัน และเมื่อผู้ใช้ติดตั้งแอปที่ Build แบบนี้ ก็จะติดตั้งแค่ APK ตัวเดียวเท่านั้น

จึงทำให้จำนวน APK ทวีคูณตามจำนวน Configuration และ Dimension

แต่สำหรับการ Build แบบ Configuration APKs จะเป็นการแยก APK สำหรับแต่ละ Configuration แต่ละ Dimension เลย และเมื่อผู้ใช้ติดตั้งแอปที่ Build แบบนี้ ก็จะติดตั้ง APK หลายๆตัว เพื่อให้ครบตาม Configuration ของเครื่องนั้นๆ

จึงทำให้จำนวน APK ที่ Build แบบ Configurations APKs มีจำนวนไฟล์น้อยและขนาดเล็กกว่าแบบ Multiple APKs

สำหรับการ Build แบบ Configuration APKs นักพัฒนาจะต้องกำหนดเลขเวอร์ชันสำหรับ APK ในทุกๆตัวห้ามซ้ำกัน แต่สำหรับ Configuration APKs จะสามารถใช้เลขเวอร์ชันเดียวได้ปกติเหมือนกับ Universal APK เลย

นอกจากนี้ Multiple APKs จะไม่รองการแยกภาษาด้วย มีแค่ Configuration APKs เท่านั้นที่ทำได้ และถ้าต้องการรองรับ Instant App ด้วย จะต้อง Build แบบ Configuration APKs เท่านั้น

Google Play จะแยกตาม Configuration อะไรบ้าง?

เพื่อให้แอปมีขนาดลดลงเมื่อติดตั้งลงในเครื่องของผู้ใช้ จึงแยกเป็น Configuration APKs ให้เพื่อให้สามารถนำไปรวมเป็น APKS ได้สะดวก โดยมีปัจจัยที่สำคัญดังนี้

  • CPU ABI : แยกตามสถาปัตยกรรมของ CPU
  • Screen Density : แยกตาม Density ที่แอปสามารถรองรับได้
  • Locale : แยกตามภาษาที่แอปสามารถรองรับได้

และทั้งนี้ก็ขึ้นอยู่กับแอปด้วยว่ามีการเตรียม Resource เหล่านั้นไว้หรือป่าว ถ้าไม่ได้เตรียมไว้ก็จะไม่แยกเป็น Split APK ออกมา เช่น

  • แอปที่ไม่มีการเรียกใช้งาน Native Library ก็จะไม่มีการแยก APK ตาม CPU ABI
  • Split APK จะแยกภาษาเท่าที่แอปนั้นได้เตรียมไว้เท่านั้น

แต่สำหรับ Screen Density จะค่อนข้างพิเศษหน่อย ถ้านักพัฒนาเตรียม Drawable Resource ไว้ไม่ครบทุกอัน หรือขาดบางภาพไป เจ้า Google Play ก็จะหยิบไฟล์ภาพที่ใกล้เคียงที่สุดมาใส่ให้แทน แต่ข้อเสียคือไม่ทำการปรับขนาดภาพให้เหมาะสม จึงอาจจะเกิดปัญหาแสดงขนาดภาพผิดเพี้ยนได้ ดังนั้นทางที่ดีควรเตรียมไว้ให้ครบดีกว่า และอย่ากำหนดให้ Layout มีขนาดตามไฟล์ภาพโดยตรง

สิ่งที่เกิดขึ้นเมื่อผู้ใช้ติดตั้งแอปจาก Google Play

เมื่อรู้กันแล้วว่า AAB ที่นักพัฒนาส่งขึ้น Google Play เนี่ย จะถูกสร้างเป็น Split APKs เตรียมไว้เพื่อรอผู้ใช้มากดดาวน์โหลด จากนั้น Google Play ก็จะดึง Profile ของอุปกรณ์แอนดรอยด์นั้นๆออกมาเช็คก่อน

สมมติว่าเป็น Google Pixel 4 ก็จะมี Profile ที่มีหน้าตาเป็น JSON แบบนี้

{
  "supportedAbis": ["arm64-v8a", "armeabi-v7a", "armeabi"],
  "supportedLocales": ["en-US", "th-TH"],
  "deviceFeatures": ["reqGlEsVersion=0x30002", "android.hardware.audio.low_latency", ...],
  "glExtensions": ["GL_OES_EGL_image", "GL_OES_EGL_image_external", "GL_OES_EGL_sync", ...],
  "screenDensity": 440,
  "sdkVersion": 29
}

และเมื่อ Google Play ได้ Profile ของเครื่องนั้นๆ ก็จะรู้ได้ทันทีว่าต้องใช้ APK ตัวไหนบ้าง แล้วทำการรวม APK เหล่านั้นให้กลายเป็น APKS แล้วส่งให้ดาวน์โหลด

และเมื่อดาวน์โหลดลงเครื่องเสร็จแล้วก็จะทำการติดตั้ง APK ทั้งหมดที่อยู่ใน APKS ลงในเครื่องนั่นเอง

โปรดติดตามชมตอนต่อไป

ทั้งหมดนี้ก็เป็นการทำงานของ Android App Bundle ที่ใช้ความสามารถ Split APKs ที่แอนดรอยด์นั้นรองรับอยู่แล้ว มาประยุกต์ใช้งานเพื่อช่วยให้นักพัฒนาสามารถส่งแอปขึ้น Google Play ได้ง่ายขึ้น และยังเพิ่มความสามารถและลูกเล่นอย่าง Dynamic Feature Delivery เพื่ออำนวยความสะดวกให้ทั้งนักพัฒนาและผู้ใช้อีกด้วย

ส่วน APKS จะติดตั้งลงในอุปกรณ์แอนดรอยด์ได้อย่างไร? การสร้าง Android App Bundle นั้นต้องทำอย่างไร? แล้วการทำ App Signing จะต้องใช้วิธีแบบไหน? โปรดเก็บคำถามเหล่านี้ไว้ก่อน แล้วรออ่านกันได้ในบทความหน้านะครับ

แหล่งข้อมูลอ้างอิง