การพัฒนาแบบวนซ้ำอย่างรวดเร็วสำหรับ Android
หน้านี้จะอธิบายวิธีที่ bazel mobile-install ช่วยให้การพัฒนาแบบวนซ้ำสำหรับ Android เร็วขึ้นมาก โดยจะอธิบายถึงประโยชน์ของแนวทางนี้เมื่อเทียบกับ
ข้อเสียของการสร้างและการติดตั้งแยกกัน
สรุป
หากต้องการติดตั้งการเปลี่ยนแปลงเล็กๆ น้อยๆ ในแอป Android อย่างรวดเร็ว ให้ทำดังนี้
- ค้นหา
android_binaryของแอปที่ต้องการติดตั้ง - เชื่อมต่ออุปกรณ์กับ
adb - วิ่ง
bazel mobile-install :your_targetการเริ่มต้นแอปจะช้ากว่าปกติเล็กน้อย - แก้ไขโค้ดหรือทรัพยากร Android
- วิ่ง
bazel mobile-install :your_target - เพลิดเพลินกับการติดตั้งแบบเพิ่มทีละน้อยที่รวดเร็วและเรียบง่าย
ตัวเลือกบรรทัดคำสั่งบางอย่างสำหรับ Bazel ที่อาจเป็นประโยชน์มีดังนี้
--adbบอก Bazel ว่าจะใช้ไบนารี adb ใด--adb_argใช้เพื่อเพิ่มอาร์กิวเมนต์พิเศษลงในบรรทัดคำสั่งของadbได้ การใช้งานที่มีประโยชน์อย่างหนึ่งคือการเลือกอุปกรณ์ที่ต้องการติดตั้ง หากมีอุปกรณ์หลายเครื่องเชื่อมต่อกับเวิร์กสเตชันbazel mobile-install :your_target -- --adb_arg=-s --adb_arg=<SERIAL>
หากไม่แน่ใจ ให้ดูตัวอย่าง ติดต่อเราใน Google Groups หรือแจ้งปัญหาใน GitHub
บทนำ
คุณสมบัติที่สำคัญที่สุดอย่างหนึ่งของ Toolchain สำหรับนักพัฒนาซอฟต์แวร์คือความเร็ว ความแตกต่างระหว่างการเปลี่ยนโค้ดและดูโค้ดทำงานภายใน 1 วินาทีกับการต้องรอหลายนาทีหรือบางครั้งอาจเป็นชั่วโมงก่อนที่จะได้รับความคิดเห็นว่าการเปลี่ยนแปลงของคุณทำงานได้ตามที่คาดไว้หรือไม่นั้นมีมาก
น่าเสียดายที่ Toolchain แบบเดิมของ Android สำหรับการสร้าง .apk นั้นมีขั้นตอนแบบลำดับที่ซับซ้อนหลายขั้นตอน และต้องทำทั้งหมดนี้เพื่อสร้างแอป Android ที่ Google การรอ 5 นาทีเพื่อสร้างการเปลี่ยนแปลงบรรทัดเดียวไม่ใช่เรื่องแปลกในโปรเจ็กต์ขนาดใหญ่ เช่น Google Maps
bazel mobile-install ช่วยให้การพัฒนาแบบวนซ้ำสำหรับ Android เร็วขึ้นมากด้วยการใช้การผสมผสานระหว่างการตัดทอนการเปลี่ยนแปลง การแบ่งงาน และการจัดการที่ชาญฉลาดขององค์ประกอบภายในของ Android โดยไม่ต้องเปลี่ยนแปลงโค้ดของแอป
ปัญหาเกี่ยวกับการติดตั้งแอปแบบเดิม
การสร้างแอป Android มีปัญหาบางอย่าง เช่น
Dexing โดยค่าเริ่มต้น เครื่องมือ Dexer (เดิมคือ
dxปัจจุบันคือd8หรือr8) จะเรียกใช้เพียงครั้งเดียวในบิลด์ และไม่ทราบวิธีนำงานจากบิลด์ก่อนหน้ามาใช้ซ้ำ จึงทำการ Dex ทุกเมธอดอีกครั้ง แม้ว่าจะมีการเปลี่ยนแปลงเพียงเมธอดเดียวก็ตามการอัปโหลดข้อมูลไปยังอุปกรณ์ adb ไม่ได้ใช้แบนด์วิดท์ทั้งหมดของการเชื่อมต่อ USB 2.0 และแอปขนาดใหญ่อาจใช้เวลาในการอัปโหลดนานมาก ระบบจะอัปโหลดทั้งแอปแม้ว่าจะมีการเปลี่ยนแปลงเพียงเล็กน้อย เช่น ทรัพยากรหรือเมธอดเดียว ซึ่งอาจเป็นจุดคอขวดที่สำคัญ
การคอมไพล์เป็นโค้ดแบบเนทีฟ Android L ได้เปิดตัว ART ซึ่งเป็นรันไทม์ใหม่ของ Android ที่คอมไพล์แอปแบบล่วงหน้าแทนที่จะคอมไพล์แบบทันทีเหมือน Dalvik ซึ่งจะทำให้แอปทำงานได้เร็วขึ้นมาก แต่จะใช้เวลาในการติดตั้งนานขึ้น ซึ่งเป็นข้อแลกเปลี่ยนที่ดีสำหรับผู้ใช้ เนื่องจากโดยปกติแล้วผู้ใช้จะติดตั้งแอปเพียงครั้งเดียวและใช้งานหลายครั้ง แต่จะทำให้การพัฒนาช้าลงในกรณีที่แอปมีการติดตั้งหลายครั้งและแต่ละเวอร์ชันจะทำงานเพียงไม่กี่ครั้งเท่านั้น
แนวทางของ bazel mobile-install
bazel mobile-install ได้ทำการปรับปรุงดังนี้
การแยกส่วนการยกเลิกการเพิ่มน้ำตาลและการแปลงเป็น DEX หลังจากสร้างโค้ด Java ของแอปแล้ว Bazel จะ แบ่งไฟล์คลาสออกเป็นส่วนๆ ที่มีขนาดใกล้เคียงกัน และเรียกใช้
d8แยกกันd8จะไม่เรียกใช้ใน Shard ที่ไม่มีการเปลี่ยนแปลงตั้งแต่ การสร้างครั้งล่าสุด จากนั้นจะคอมไพล์ Shard เหล่านี้เป็น APK ที่ Shard แยกกันการโอนไฟล์แบบเพิ่ม ระบบจะนำทรัพยากร Android, ไฟล์ .dex และไลบรารีแบบเนทีฟ ออกจาก .apk หลักและจัดเก็บไว้ในไดเรกทอรีการติดตั้งบนอุปกรณ์เคลื่อนที่แยกต่างหาก ซึ่งช่วยให้คุณอัปเดตโค้ดและทรัพยากร Android ได้อย่างอิสระโดยไม่ต้องติดตั้งแอปทั้งแอปใหม่ ดังนั้น การโอนไฟล์จึงใช้เวลาน้อยลง และระบบจะคอมไพล์ไฟล์ .dex ที่มีการเปลี่ยนแปลงใหม่ในอุปกรณ์เท่านั้น
การติดตั้งที่แยกส่วน การติดตั้งบนอุปกรณ์เคลื่อนที่จะใช้เครื่องมือ
apkdeployerของ Android Studio เพื่อรวม APK ที่แยกส่วนในอุปกรณ์ที่เชื่อมต่อและมอบประสบการณ์การใช้งานที่สอดคล้องกัน
การจัดทำดัชนีแบบชาร์ด
การแบ่ง DEX ออกเป็นส่วนๆ นั้นค่อนข้างตรงไปตรงมา เมื่อสร้างไฟล์ .jar แล้ว เครื่องมือจะ
แบ่งไฟล์เหล่านั้นออกเป็นไฟล์ .jar แยกกันซึ่งมีขนาดใกล้เคียงกัน จากนั้นจะเรียกใช้
d8 ในไฟล์ที่มีการเปลี่ยนแปลงนับตั้งแต่การสร้างครั้งก่อน ตรรกะที่กำหนดว่าควรใช้ Dex กับ Shard ใดไม่ได้เจาะจงสำหรับ Android แต่ใช้อัลกอริทึมการตัดแต่งการเปลี่ยนแปลงทั่วไปของ Bazel
อัลกอริทึมการแบ่งข้อมูลเวอร์ชันแรกเพียงแค่จัดเรียงไฟล์ .class ตามลำดับตัวอักษร แล้วตัดรายการออกเป็นส่วนๆ ที่มีขนาดเท่ากัน แต่ปรากฏว่าวิธีนี้ไม่เหมาะสม หากมีการเพิ่มหรือนำคลาสออก (แม้จะเป็นคลาสที่ซ้อนกันหรือคลาสที่ไม่ระบุชื่อ) ก็จะทำให้คลาสทั้งหมดที่อยู่หลังคลาสนั้นตามลำดับตัวอักษรเลื่อนไป 1 ตำแหน่ง ส่งผลให้ต้องทำการ Dexing Shard เหล่านั้นอีกครั้ง จึงตัดสินใจที่จะ Shard แพ็กเกจ Java แทนที่จะเป็นคลาสแต่ละคลาส แน่นอนว่าการดำเนินการนี้ยังคงส่งผลให้มีการจัดทำดัชนีหลายๆ ชิ้นหากมีการเพิ่มหรือนำแพ็กเกจใหม่ออก แต่การดำเนินการนี้จะเกิดขึ้นไม่บ่อยเท่ากับการเพิ่มหรือนำคลาสเดียวออก
การกำหนดค่าบรรทัดคำสั่งจะควบคุมจำนวน Shard โดยใช้ Flag
--define=num_dex_shards=N ในโลกที่สมบูรณ์แบบ Bazel จะกำหนดจำนวนชาร์ดที่เหมาะสมที่สุดโดยอัตโนมัติ แต่ปัจจุบัน Bazel ต้องทราบชุดการดำเนินการ (เช่น คำสั่งที่จะดำเนินการระหว่างการบิลด์) ก่อนที่จะดำเนินการใดๆ จึงไม่สามารถกำหนดจำนวนชาร์ดที่เหมาะสมที่สุดได้ เนื่องจากไม่ทราบว่าในท้ายที่สุดจะมีคลาส Java กี่คลาสในแอป โดยทั่วไปแล้ว ยิ่งมีชาร์ดมากเท่าใด การบิลด์และการติดตั้งก็จะยิ่งเร็วขึ้น แต่การเริ่มต้นแอปจะช้าลงเนื่องจากลิงก์เกอร์แบบไดนามิกต้องทำงานมากขึ้น โดยปกติแล้ว จำนวนที่เหมาะสมจะอยู่ระหว่าง 10 ถึง 50 ชิ้น
การติดตั้งใช้งานแบบเพิ่มทีละรายการ
ตอนนี้การโอนและการติดตั้ง Shard ของ APK แบบเพิ่มทีละรายการจะได้รับการจัดการโดยยูทิลิตี apkdeployer ที่อธิบายไว้ใน "แนวทางของ mobile-install"
ในขณะที่เวอร์ชันก่อนหน้า (เนทีฟ) ของการติดตั้งบนอุปกรณ์เคลื่อนที่ต้องมีการติดตามการติดตั้งครั้งแรกด้วยตนเอง
และใช้แฟล็ก --incremental
กับการติดตั้งครั้งต่อๆ ไปแบบเลือกได้ แต่เวอร์ชันล่าสุดใน rules_android
ได้รับการปรับปรุงให้ง่ายขึ้นมาก คุณสามารถใช้การเรียกใช้การติดตั้งบนอุปกรณ์เคลื่อนที่เดียวกันได้ไม่ว่าแอปจะได้รับการติดตั้ง
หรือติดตั้งซ้ำกี่ครั้งก็ตาม
ในระดับสูง apkdeployerเครื่องมือนี้เป็น Wrapper สำหรับadb
คำสั่งย่อยต่างๆ ตรรกะของจุดแรกเข้าหลักจะอยู่ในคลาส
com.android.tools.deployer.Deployer
โดยมีคลาสยูทิลิตีอื่นๆ อยู่ในแพ็กเกจเดียวกัน
คลาส Deployer จะรับรายการเส้นทางไปยัง Split APK และ Protobuf ที่มีข้อมูลเกี่ยวกับการติดตั้ง รวมถึงใช้ประโยชน์จากฟีเจอร์การติดตั้งใช้งานสำหรับ Android App Bundle
เพื่อสร้างเซสชันการติดตั้งและติดตั้งใช้งานการแยกแอปทีละรายการ
ดูรายละเอียดการติดตั้งใช้งานได้ในคลาส ApkPreInstaller
และ ApkInstaller
ผลลัพธ์
ประสิทธิภาพ
โดยทั่วไปแล้ว bazel mobile-install จะช่วยให้การสร้าง
และการติดตั้งแอปขนาดใหญ่หลังจากมีการเปลี่ยนแปลงเล็กน้อยเร็วขึ้น 4-10 เท่า
เราคำนวณตัวเลขต่อไปนี้สำหรับผลิตภัณฑ์บางอย่างของ Google
ซึ่งแน่นอนว่าขึ้นอยู่กับลักษณะของการเปลี่ยนแปลง การคอมไพล์ใหม่หลังจากเปลี่ยนไลบรารีพื้นฐานจะใช้เวลานานกว่า
ข้อจำกัด
กลเม็ดที่แอปพลิเคชัน Stub ใช้ไม่ได้ผลในบางกรณี กรณีต่อไปนี้แสดงให้เห็นว่าฟีเจอร์นี้ทำงานไม่เป็นไปตามที่คาดไว้
การติดตั้งแอปบนอุปกรณ์เคลื่อนที่รองรับเฉพาะผ่านกฎ Starlark ของ
rules_androidเท่านั้น ดูรายละเอียดเพิ่มเติมได้ที่"ประวัติโดยย่อของการติดตั้งบนอุปกรณ์เคลื่อนที่"รองรับเฉพาะอุปกรณ์ที่ใช้ ART เท่านั้น การติดตั้งบนอุปกรณ์เคลื่อนที่จะใช้ API และฟีเจอร์รันไทม์ ที่มีอยู่ในอุปกรณ์ที่ใช้ ART เท่านั้น ไม่ใช่ Dalvik รันไทม์ Android ที่ใหม่กว่า Android L (API 21 ขึ้นไป) ควรจะใช้งานร่วมกันได้
Bazel เองต้องทำงานด้วยรันไทม์ Java ของเครื่องมือและเวอร์ชันภาษา 17 ขึ้นไป
Bazel เวอร์ชันก่อน 8.4.0 ต้องระบุแฟล็กเพิ่มเติมสำหรับการติดตั้งบนอุปกรณ์เคลื่อนที่ ดูบทแนะนำ Bazel สำหรับ Android แฟล็กเหล่านี้จะแจ้งให้ Bazel ทราบว่า Aspect การติดตั้งบนอุปกรณ์เคลื่อนที่ของ Starlark อยู่ที่ใดและรองรับกฎใดบ้าง
ประวัติโดยย่อของการติดตั้งบนอุปกรณ์เคลื่อนที่
Bazel เวอร์ชันก่อนหน้ามีกฎการบิลด์และการทดสอบในตัวโดยค่าเริ่มต้นสำหรับ ภาษาและระบบนิเวศยอดนิยม เช่น C++, Java และ Android ดังนั้นกฎเหล่านี้จึงเรียกว่ากฎเนทีฟ Bazel 8 (เปิดตัวในปี 2024) ได้นำการรองรับกฎเหล่านี้ออกเนื่องจากมีการย้ายข้อมูลกฎหลายรายการไปยังภาษา Starlark ดูรายละเอียดเพิ่มเติมได้ที่"บล็อกโพสต์เกี่ยวกับ Bazel 8.0 LTS"
กฎ Android เนทีฟเดิมยังรองรับฟังก์ชันการติดตั้งบนอุปกรณ์เคลื่อนที่เวอร์ชันเนทีฟเดิมด้วย ปัจจุบันเราเรียกแคมเปญประเภทนี้ว่า "การติดตั้งบนอุปกรณ์เคลื่อนที่ v1" หรือ "การติดตั้งบนอุปกรณ์เคลื่อนที่แบบเนทีฟ" เราได้ลบฟังก์ชันการทำงานนี้ใน Bazel 8 พร้อมกับกฎ Android ในตัว
ตอนนี้ฟังก์ชันการติดตั้งบนอุปกรณ์เคลื่อนที่ทั้งหมด รวมถึงกฎการสร้างและการทดสอบ Android ทั้งหมด
ได้รับการติดตั้งใช้งานใน Starlark และอยู่ในที่เก็บ rules_android GitHub
เวอร์ชันล่าสุดเรียกว่า "การติดตั้งบนอุปกรณ์เคลื่อนที่ v3" หรือ "MIv3"
หมายเหตุเกี่ยวกับการตั้งชื่อ: เราเคยมี "การติดตั้งแอปบนอุปกรณ์เคลื่อนที่ v2" ที่ใช้ได้ภายใน Google เท่านั้น แต่เราไม่เคยเผยแพร่ภายนอก และมีเพียง v3 เท่านั้นที่ยังคงใช้สำหรับการติดตั้งใช้งานทั้งกฎภายในของ Google และกฎ OSS_android