ติดตั้ง bazel ผ่านมือถือ

การพัฒนา Android แบบวนซ้ำอย่างรวดเร็ว

หน้านี้จะอธิบายวิธีที่ bazel mobile-install ช่วยให้การพัฒนาแบบวนซ้ำ สำหรับ Android เร็วขึ้นมาก โดยจะอธิบายถึงประโยชน์ของแนวทางนี้เมื่อเทียบกับ ข้อเสียของการสร้างและติดตั้งแยกกัน

สรุป

หากต้องการติดตั้งการเปลี่ยนแปลงเล็กๆ น้อยๆ ในแอป Android อย่างรวดเร็ว ให้ทำดังนี้

  1. ค้นหาandroid_binaryของแอปที่ต้องการติดตั้ง
  2. เชื่อมต่ออุปกรณ์กับ adb
  3. เรียกใช้ bazel mobile-install :your_target การเริ่มต้นแอปจะช้ากว่าปกติเล็กน้อย
  4. แก้ไขโค้ดหรือทรัพยากร Android
  5. เรียกใช้ bazel mobile-install :your_target
  6. เพลิดเพลินกับการติดตั้งที่รวดเร็วและง่ายดาย

ตัวเลือกบรรทัดคำสั่งบางอย่างสำหรับ Bazel ที่อาจเป็นประโยชน์มีดังนี้

  • --adb บอก Bazel ว่าจะใช้ไบนารี adb ใด
  • --adb_arg ใช้เพื่อเพิ่มอาร์กิวเมนต์พิเศษลงในบรรทัดคำสั่งของ adb ได้ การใช้งานที่มีประโยชน์อย่างหนึ่งคือการเลือกอุปกรณ์ที่ต้องการติดตั้ง หากคุณมีอุปกรณ์หลายเครื่องที่เชื่อมต่อกับเวิร์กสเตชัน bazel mobile-install :your_target -- --adb_arg=-s --adb_arg=<SERIAL>

หากไม่แน่ใจ ให้ดูตัวอย่าง ติดต่อเราใน Google Groups หรือแจ้งปัญหาใน GitHub

บทนำ

คุณสมบัติที่สำคัญที่สุดอย่างหนึ่งของเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์คือความเร็ว ความแตกต่างระหว่างการเปลี่ยนโค้ดและดูโค้ดทำงานภายใน 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 ที่มีการเปลี่ยนแปลงอีกครั้งในอุปกรณ์เท่านั้น

  • การติดตั้งแบบ Shard การติดตั้งบนอุปกรณ์เคลื่อนที่จะใช้เครื่องมือ apkdeployer ของ Android Studio เพื่อรวม APK ที่แยกส่วนในอุปกรณ์ที่เชื่อมต่อและมอบประสบการณ์การใช้งานที่สอดคล้องกัน

การจัดทำดัชนีแบบชาร์ด

การแบ่ง DEX ออกเป็นส่วนๆ นั้นค่อนข้างตรงไปตรงมา เมื่อสร้างไฟล์ .jar แล้ว เครื่องมือจะ แบ่งไฟล์เหล่านั้นออกเป็นไฟล์ .jar แยกกันซึ่งมีขนาดใกล้เคียงกัน จากนั้นจะเรียกใช้ d8 ในไฟล์ที่มีการเปลี่ยนแปลงนับตั้งแต่การสร้างครั้งก่อน ตรรกะที่กำหนดว่าควร dex ชาร์ดใดไม่ได้เจาะจงสำหรับ Android แต่ใช้อัลกอริทึมการตัดแต่งการเปลี่ยนแปลงทั่วไปของ Bazel

อัลกอริทึมการแบ่งข้อมูลเวอร์ชันแรกเพียงแค่จัดเรียงไฟล์ .class ตามลำดับตัวอักษร แล้วแบ่งรายการออกเป็นส่วนๆ ที่มีขนาดเท่ากัน แต่ปรากฏว่าวิธีนี้ไม่เหมาะสม หากมีการเพิ่มหรือนำคลาสออก (แม้จะเป็นคลาสที่ซ้อนกันหรือคลาสที่ไม่ระบุชื่อ) ก็จะทำให้คลาสทั้งหมดที่อยู่หลังคลาสนั้นตามลำดับตัวอักษรเลื่อนไป 1 ตำแหน่ง ซึ่งส่งผลให้ต้องทำการ Dexing Shard เหล่านั้นอีกครั้ง จึงตัดสินใจที่จะแบ่งแพ็กเกจ Java แทนที่จะแบ่งคลาสแต่ละรายการ แน่นอนว่าการดำเนินการนี้ยังคงส่งผลให้มีการจัดทำดัชนีหลายๆ ชาร์ดหากมีการเพิ่มหรือนำแพ็กเกจใหม่ออก แต่การดำเนินการนี้จะเกิดขึ้นไม่บ่อยเท่ากับการเพิ่มหรือนำคลาสเดียวออก

การกำหนดจำนวน Shard จะควบคุมโดยการกำหนดค่าบรรทัดคำสั่งโดยใช้ Flag --define=num_dex_shards=N ในโลกที่สมบูรณ์แบบ Bazel จะ กำหนดจำนวน Shard ที่ดีที่สุดโดยอัตโนมัติ แต่ปัจจุบัน Bazel ต้องทราบ ชุดการดำเนินการ (เช่น คำสั่งที่จะดำเนินการระหว่างการสร้าง) ก่อน ที่จะดำเนินการใดๆ ดังนั้นจึงไม่สามารถกำหนดจำนวน Shard ที่เหมาะสมได้ เนื่องจากไม่ทราบว่าในที่สุดแล้วจะมีคลาส Java กี่คลาสใน แอป โดยทั่วไปแล้ว ยิ่งมี Shard มากเท่าใด การสร้างและการ ติดตั้งก็จะยิ่งเร็วขึ้น แต่การเริ่มต้นแอปจะช้าลงเนื่องจากลิงก์เกอร์แบบไดนามิก ต้องทำงานมากขึ้น โดยปกติแล้ว จำนวนที่เหมาะสมจะอยู่ระหว่าง 10 ถึง 50 ชาร์ด

การติดตั้งใช้งานแบบค่อยเป็นค่อยไป

ตอนนี้ยูทิลิตี apkdeployer ที่อธิบายไว้ใน "แนวทางของ mobile-install" จะจัดการการโอนและการติดตั้ง Shard ของ APK แบบเพิ่มทีละรายการ ในขณะที่เวอร์ชันก่อนหน้า (เนทีฟ) ของการติดตั้งบนอุปกรณ์เคลื่อนที่ต้องมีการติดตามการติดตั้งครั้งแรกด้วยตนเอง และใช้แฟล็ก --incremental ในการติดตั้งครั้งต่อๆ ไปแบบเลือกได้ แต่เวอร์ชันล่าสุดใน rules_android ได้รับการปรับปรุงให้ง่ายขึ้นมาก คุณสามารถใช้การเรียกใช้การติดตั้งบนอุปกรณ์เคลื่อนที่เดียวกันได้ไม่ว่าแอปจะได้รับการติดตั้ง หรือติดตั้งซ้ำกี่ครั้งก็ตาม

ในระดับสูง apkdeployer คือ Wrapper สำหรับadb คำสั่งย่อยต่างๆ ตรรกะของจุดแรกเข้าหลักจะอยู่ในคลาส com.android.tools.deployer.Deployer โดยมีคลาสยูทิลิตีอื่นๆ อยู่ในแพ็กเกจเดียวกัน คลาส Deployer จะรับรายการเส้นทางไปยัง 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 ต้องระบุแฟล็กเพิ่มเติมบางอย่างสำหรับ mobile-install ดูบทแนะนำ 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