บทแนะนำ Bazel: สร้างแอป Android

บทแนะนำนี้กล่าวถึงวิธีสร้างแอป Android แบบง่ายๆ โดยใช้ Bazel

Bazel รองรับการสร้างแอป Android โดยใช้กฎของ Android

บทแนะนำนี้มีไว้สำหรับผู้ใช้ Windows, macOS และ Linux และไม่จำเป็นต้องมีประสบการณ์ในการพัฒนาแอป Bazel หรือ Android คุณไม่จำเป็นต้องเขียนโค้ด Android ในบทแนะนำนี้

สิ่งที่คุณจะได้เรียนรู้

ในบทแนะนำนี้ คุณจะได้เรียนรู้วิธีต่อไปนี้

  • ตั้งค่าสภาพแวดล้อมโดยการติดตั้ง Bazel และ Android Studio และดาวน์โหลดโปรเจ็กต์ตัวอย่าง
  • ตั้งค่าพื้นที่ทำงานของ Bazel ที่มีซอร์สโค้ดสำหรับแอปและไฟล์ WORKSPACE ที่ระบุระดับบนสุดของไดเรกทอรีพื้นที่ทำงาน
  • อัปเดตไฟล์ WORKSPACE ให้มีการอ้างอิงทรัพยากร Dependency ภายนอกที่จำเป็น เช่น Android SDK
  • สร้างไฟล์ BUILD
  • สร้างแอปด้วย Bazel
  • ทำให้แอปใช้งานได้และเรียกใช้แอปในโปรแกรมจำลอง Android หรืออุปกรณ์จริง

ก่อนเริ่มต้น

ติดตั้ง Bazel

ก่อนเริ่มบทแนะนำ ให้ติดตั้งซอฟต์แวร์ต่อไปนี้

  • Bazel. ในการติดตั้ง ให้ทำตามวิธีการติดตั้ง
  • Android Studio หากต้องการติดตั้ง ให้ทำตามขั้นตอนในการดาวน์โหลด Android Studio เรียกใช้วิซาร์ดการตั้งค่าเพื่อดาวน์โหลด SDK และกำหนดค่าสภาพแวดล้อม
  • (ไม่บังคับ) Git. ใช้ git เพื่อดาวน์โหลดโปรเจ็กต์แอป Android

รับโปรเจ็กต์ตัวอย่าง

สำหรับโปรเจ็กต์ตัวอย่าง ให้ใช้โปรเจ็กต์แอป Android พื้นฐานในที่เก็บตัวอย่างของ Bazel

แอปนี้มีปุ่มเดียวสำหรับพิมพ์คำทักทายเมื่อคลิก ดังนี้

คำทักทายบนปุ่ม

รูปที่ 1 คำทักทายบนปุ่มแอป Android

โคลนที่เก็บด้วย git (หรือดาวน์โหลดไฟล์ ZIP โดยตรง) โดยทำดังนี้

git clone https://github.com/bazelbuild/examples

โปรเจ็กต์ตัวอย่างสำหรับบทแนะนำนี้อยู่ใน examples/android/tutorial ในบทแนะนำที่เหลือ คุณจะได้ใช้คำสั่งในไดเรกทอรีนี้

ตรวจสอบไฟล์ต้นฉบับ

ดูไฟล์ต้นฉบับสำหรับแอป

.
├── README.md
└── src
    └── main
        ├── AndroidManifest.xml
        └── java
            └── com
                └── example
                    └── bazel
                        ├── AndroidManifest.xml
                        ├── Greeter.java
                        ├── MainActivity.java
                        └── res
                            ├── layout
                            │   └── activity_main.xml
                            └── values
                                ├── colors.xml
                                └── strings.xml

ไฟล์และไดเรกทอรีที่สำคัญมีดังนี้

ชื่อ ตำแหน่ง
ไฟล์ Manifest ของ Android src/main/AndroidManifest.xmlและsrc/main/java/com/example/bazel/AndroidManifest.xml
ไฟล์ต้นฉบับ Android src/main/java/com/example/bazel/MainActivity.javaและGreeter.java
ไดเรกทอรีไฟล์ทรัพยากร src/main/java/com/example/bazel/res/

สร้างด้วย Bazel

ตั้งค่าพื้นที่ทำงาน

พื้นที่ทำงานคือไดเรกทอรีที่มีไฟล์ต้นฉบับสำหรับโปรเจ็กต์ซอฟต์แวร์อย่างน้อย 1 โปรเจ็กต์ และมีไฟล์ WORKSPACE อยู่ที่รูท

ไฟล์ WORKSPACE อาจว่างเปล่าหรืออาจมีการอ้างอิงไปยังทรัพยากร Dependency ภายนอกที่จำเป็นต่อการสร้างโปรเจ็กต์

ก่อนอื่น ให้เรียกใช้คำสั่งต่อไปนี้เพื่อสร้างไฟล์ WORKSPACE เปล่า

ระบบปฏิบัติการ คำสั่ง
Linux และ macOS touch WORKSPACE
Windows (Command Prompt) type nul > WORKSPACE
Windows (PowerShell) New-Item WORKSPACE -ItemType file

อุปกรณ์วิ่ง Bazel

ตอนนี้คุณตรวจสอบได้ว่า Bazel ทำงานอย่างถูกต้องหรือไม่ด้วยคำสั่งต่อไปนี้

bazel info workspace

หาก Bazel พิมพ์เส้นทางของไดเรกทอรีปัจจุบัน คุณก็พร้อมใช้งาน หากไม่มีไฟล์ WORKSPACE คุณอาจเห็นข้อความแสดงข้อผิดพลาด เช่น

ERROR: The 'info' command is only supported from within a workspace.

ผสานรวมกับ Android SDK

Bazel ต้องใช้เครื่องมือสร้าง Android SDK เพื่อสร้างแอป ซึ่งหมายความว่าคุณต้องเพิ่มข้อมูลบางอย่างลงในไฟล์ WORKSPACE เพื่อให้ Bazel ทราบว่าจะหาเจอได้จากที่ใด

เพิ่มบรรทัดต่อไปนี้ในไฟล์ WORKSPACE

android_sdk_repository(name = "androidsdk")

ซึ่งจะใช้ Android SDK ในเส้นทางที่อ้างอิงโดยตัวแปรสภาพแวดล้อม ANDROID_HOME และจะตรวจหา API ระดับสูงสุดและเครื่องมือสร้างเวอร์ชันล่าสุดที่ติดตั้งภายในตำแหน่งนั้นโดยอัตโนมัติ

คุณตั้งค่าตัวแปร ANDROID_HOME เป็นตําแหน่งของ Android SDK ได้ ค้นหาเส้นทางไปยัง SDK ที่ติดตั้งโดยใช้เครื่องมือจัดการ SDK ของ Android Studio สมมติว่าติดตั้ง SDK ในตำแหน่งเริ่มต้นแล้ว คุณจะใช้คำสั่งต่อไปนี้เพื่อตั้งค่าตัวแปร ANDROID_HOME ได้

ระบบปฏิบัติการ คำสั่ง
Linux export ANDROID_HOME=$HOME/Android/Sdk/
macOS export ANDROID_HOME=$HOME/Library/Android/sdk
Windows (Command Prompt) set ANDROID_HOME=%LOCALAPPDATA%\Android\Sdk
Windows (PowerShell) $env:ANDROID_HOME="$env:LOCALAPPDATA\Android\Sdk"

คำสั่งข้างต้นจะกำหนดตัวแปรสำหรับเซสชัน Shell ปัจจุบันเท่านั้น หากต้องการให้มีผลถาวร ให้เรียกใช้คำสั่งต่อไปนี้

ระบบปฏิบัติการ คำสั่ง
Linux echo "export ANDROID_HOME=$HOME/Android/Sdk/" >> ~/.bashrc
macOS echo "export ANDROID_HOME=$HOME/Library/Android/Sdk/" >> ~/.bashrc
Windows (Command Prompt) setx ANDROID_HOME "%LOCALAPPDATA%\Android\Sdk"
Windows (PowerShell) [System.Environment]::SetEnvironmentVariable('ANDROID_HOME', "$env:LOCALAPPDATA\Android\Sdk", [System.EnvironmentVariableTarget]::User)

คุณยังระบุเส้นทางสัมบูรณ์ของ Android SDK, ระดับ API และเวอร์ชันของเครื่องมือการสร้างที่จะใช้ให้ชัดเจนได้ด้วยการรวมแอตทริบิวต์ path, api_level และ build_tools_version หากไม่ได้ระบุ api_level และ build_tools_version กฎ android_sdk_repository จะใช้เวอร์ชันล่าสุดที่เกี่ยวข้องใน SDK คุณระบุชุดค่าผสมของแอตทริบิวต์เหล่านี้ใดก็ได้ตราบใดที่แอตทริบิวต์เหล่านั้นอยู่ใน SDK เช่น

android_sdk_repository(
    name = "androidsdk",
    path = "/path/to/Android/sdk",
    api_level = 25,
    build_tools_version = "30.0.3"
)

ใน Windows โปรดทราบว่าแอตทริบิวต์ path ต้องใช้เส้นทางรูปแบบผสม ซึ่งก็คือเส้นทาง Windows ที่มีเครื่องหมายทับ ดังนี้

android_sdk_repository(
    name = "androidsdk",
    path = "c:/path/to/Android/sdk",
)

ไม่บังคับ: หากต้องการคอมไพล์โค้ดที่มาพร้อมเครื่องลงในแอป Android คุณต้องดาวน์โหลด Android NDK และบอก Bazel ว่าจะดูโค้ดดังกล่าวได้ที่ใดด้วยการเพิ่มบรรทัดต่อไปนี้ลงในไฟล์ WORKSPACE

android_ndk_repository(name = "androidndk")

เส้นทางไปยัง Android NDK จะอนุมานจากตัวแปรสภาพแวดล้อม ANDROID_NDK_HOME โดยค่าเริ่มต้น เช่นเดียวกับ android_sdk_repository นอกจากนี้ คุณยังระบุเส้นทางด้วยแอตทริบิวต์ path ใน android_ndk_repository ได้อย่างชัดเจน

สำหรับข้อมูลเพิ่มเติม โปรดอ่านการใช้ชุดเครื่องมือพัฒนาซอฟต์แวร์แบบเนทีฟสำหรับ Android กับ Bazel

api_level คือ Android API ที่ SDK และ NDK กำหนดเป้าหมาย เช่น 23 สำหรับ Android 6.0 และ 25 สำหรับ Android 7.1 หากไม่ได้กำหนดอย่างชัดแจ้ง api_level จะมีค่าเริ่มต้นเป็นระดับ API สูงสุดที่มีสำหรับ android_sdk_repository และ android_ndk_repository เป็นค่าเริ่มต้น

ไม่จำเป็นต้องตั้งค่าระดับ API เป็นค่าเดียวกันสำหรับ SDK และ NDK หน้านี้ มีแผนที่ตั้งแต่รุ่น Android ไปจนถึงระดับ API ที่รองรับ NDK

สร้างไฟล์ BUILD

ไฟล์ BUILD จะอธิบายความสัมพันธ์ระหว่างชุดเอาต์พุตของบิลด์ เช่น ทรัพยากร Android ที่คอมไพล์จาก aapt หรือไฟล์คลาสจาก javac และทรัพยากร Dependency ของทรัพยากรเหล่านั้น ทรัพยากร Dependency เหล่านี้อาจเป็นไฟล์ต้นฉบับ (Java, C++) ในพื้นที่ทำงาน หรือเอาต์พุตของบิลด์อื่นๆ ไฟล์ BUILD เขียนด้วยภาษาที่ชื่อว่า Starlark

ไฟล์ BUILD เป็นส่วนหนึ่งของแนวคิดใน Bazel ซึ่งเรียกว่าลำดับชั้นของแพ็กเกจ ลำดับชั้นของแพ็กเกจเป็นโครงสร้างเชิงตรรกะที่วางซ้อนโครงสร้างไดเรกทอรีในพื้นที่ทำงาน แพ็กเกจแต่ละรายการคือไดเรกทอรี (และไดเรกทอรีย่อย) ที่มีชุดไฟล์ต้นฉบับที่เกี่ยวข้องและไฟล์ BUILD แพ็กเกจนี้ยังประกอบด้วยไดเรกทอรีย่อย ยกเว้นรายการที่มีไฟล์ BUILD ของตนเอง ชื่อแพ็กเกจคือเส้นทางไปยังไฟล์ BUILD ที่สัมพันธ์กับ WORKSPACE

โปรดทราบว่าลำดับชั้นแพ็กเกจของ Bazel นั้นแตกต่างจากลำดับชั้นแพ็กเกจ Java ของไดเรกทอรีแอป Android ที่มีไฟล์ BUILD แม้ว่าจะมีการจัดระเบียบไดเรกทอรีให้เหมือนกันก็ตาม

สำหรับแอป Android แบบง่ายในบทแนะนำนี้ ไฟล์ต้นฉบับใน src/main/ จะมีแพ็กเกจ Bazel รายการเดียว โปรเจ็กต์ที่ซับซ้อนมากขึ้นอาจมีแพ็กเกจที่ฝังอยู่หลายแพ็กเกจ

เพิ่มกฎ android_library

ไฟล์ BUILD มีการประกาศประเภทต่างๆ สำหรับ Bazel ประเภทที่สำคัญที่สุดคือกฎการสร้าง ซึ่งจะบอกวิธีสร้างเอาต์พุตซอฟต์แวร์ระดับกลางหรือขั้นสุดท้ายจากชุดไฟล์ต้นฉบับหรือทรัพยากร Dependency อื่นๆ Bazel มีกฎการสร้าง 2 กฎ ได้แก่ android_library และ android_binary ให้คุณใช้สร้างแอป Android ได้

สำหรับบทแนะนำนี้ ก่อนอื่นคุณจะต้องใช้กฎ android_library เพื่อบอกให้ Bazel สร้างโมดูลคลัง Android จากซอร์สโค้ดและไฟล์ทรัพยากรของแอป จากนั้นใช้กฎ android_binary เพื่อบอก Bazel วิธีสร้างแพ็กเกจแอปพลิเคชัน Android

สร้างไฟล์ BUILD ใหม่ในไดเรกทอรี src/main/java/com/example/bazel และประกาศเป้าหมาย android_library ใหม่ดังนี้

src/main/java/com/example/bazel/BUILD:

package(
    default_visibility = ["//src:__subpackages__"],
)

android_library(
    name = "greeter_activity",
    srcs = [
        "Greeter.java",
        "MainActivity.java",
    ],
    manifest = "AndroidManifest.xml",
    resource_files = glob(["res/**"]),
)

กฎบิลด์ android_library มีชุดแอตทริบิวต์ที่ระบุข้อมูลที่ Bazel ต้องใช้ในการสร้างโมดูลไลบรารีจากไฟล์ต้นฉบับ และโปรดทราบว่าชื่อของกฎคือ greeter_activity คุณจะอ้างอิงกฎที่ใช้ชื่อนี้เป็นรายการขึ้นต่อกันในกฎ android_binary

เพิ่มกฎ android_binary

กฎ android_binary จะสร้างแพ็กเกจแอปพลิเคชัน Android (ไฟล์ .apk) สำหรับแอปของคุณ

สร้างไฟล์ BUILD ใหม่ในไดเรกทอรี src/main/ และประกาศเป้าหมาย android_binary ใหม่ดังนี้

src/main/BUILD:

android_binary(
    name = "app",
    manifest = "AndroidManifest.xml",
    deps = ["//src/main/java/com/example/bazel:greeter_activity"],
)

ในตัวอย่างนี้ แอตทริบิวต์ deps อ้างอิงเอาต์พุตของกฎ greeter_activity ที่คุณเพิ่มลงในไฟล์ BUILD ด้านบน ซึ่งหมายความว่าเมื่อ Bazel สร้างเอาต์พุตของกฎนี้ ระบบจะตรวจสอบก่อนเพื่อดูว่าเอาต์พุตของกฎไลบรารี greeter_activity สร้างขึ้นและเป็นข้อมูลล่าสุดหรือไม่ ไม่เช่นนั้น Bazel จะสร้างและใช้เอาต์พุตนั้นเพื่อสร้างไฟล์แพ็กเกจแอปพลิเคชัน

ตอนนี้ให้บันทึกและปิดไฟล์

สร้างแอป

ลองสร้างแอปเลย เรียกใช้คำสั่งต่อไปนี้เพื่อสร้างเป้าหมาย android_binary

bazel build //src/main:app

คำสั่งย่อย build จะสั่งให้ Bazel สร้างเป้าหมายที่ตามมา เป้าหมายจะระบุเป็นชื่อของกฎบิลด์ภายในไฟล์ BUILD พร้อมด้วยเส้นทางแพ็กเกจที่สัมพัทธ์กับไดเรกทอรีพื้นที่ทำงาน ในตัวอย่างนี้ เป้าหมายคือ app และเส้นทางแพ็กเกจคือ //src/main/

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

Bazel จะเริ่มต้นสร้างแอปตัวอย่าง ในระหว่างขั้นตอนการสร้าง เอาต์พุตของแอปจะแสดงคล้ายกับตัวอย่างต่อไปนี้

INFO: Analysed target //src/main:app (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //src/main:app up-to-date:
  bazel-bin/src/main/app_deploy.jar
  bazel-bin/src/main/app_unsigned.apk
  bazel-bin/src/main/app.apk

ค้นหาเอาต์พุตของบิลด์

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

  • bazel-bin จัดเก็บไฟล์สั่งการแบบไบนารีและเอาต์พุตบิลด์อื่นๆ ที่เรียกใช้ได้
  • bazel-genfiles จะจัดเก็บไฟล์แหล่งที่มาที่เป็นตัวกลางที่สร้างขึ้นโดยกฎ Bazel
  • bazel-out จัดเก็บเอาต์พุตบิลด์ประเภทอื่นๆ

Bazel จัดเก็บไฟล์ Android .apk ที่สร้างขึ้นโดยใช้กฎ android_binary ในไดเรกทอรี bazel-bin/src/main โดยชื่อไดเรกทอรีย่อย src/main ดึงมาจากชื่อแพ็กเกจ Bazel

ที่พรอมต์คำสั่ง ให้ระบุเนื้อหาของไดเรกทอรีนี้และค้นหาไฟล์ app.apk ดังนี้

ระบบปฏิบัติการ คำสั่ง
Linux และ macOS ls bazel-bin/src/main
Windows (Command Prompt) dir bazel-bin\src\main
Windows (PowerShell) ls bazel-bin\src\main

เรียกใช้แอป

ตอนนี้คุณทำให้แอปใช้งานได้ในอุปกรณ์ Android หรือโปรแกรมจำลองที่เชื่อมต่อจากบรรทัดคำสั่งโดยใช้คำสั่ง bazel mobile-install ได้แล้ว คำสั่งนี้ใช้ Android Debug Bridge (adb) เพื่อสื่อสารกับอุปกรณ์ คุณต้องตั้งค่าอุปกรณ์ให้ใช้ adb โดยทำตามวิธีการในบริดจ์การแก้ไขข้อบกพร่องของ Android ก่อนการติดตั้งใช้งาน นอกจากนี้ คุณยังเลือกติดตั้งแอปในโปรแกรมจำลอง Android ที่รวมอยู่ใน Android Studio ได้ด้วย โปรดตรวจสอบว่าโปรแกรมจำลองกำลังทำงานอยู่ก่อนเรียกใช้คำสั่งด้านล่าง

ป้อนข้อมูลต่อไปนี้

bazel mobile-install //src/main:app

จากนั้นค้นหาและเปิด "แอปบทแนะนำ Bazel"

แอปบทแนะนำ Bazel

รูปที่ 2 แอปบทแนะนำ Bazel

ยินดีด้วย คุณเพิ่งติดตั้งแอป Android ที่ Bazel สร้างขึ้นเป็นครั้งแรก

โปรดทราบว่าคำสั่งย่อย mobile-install ยังรองรับแฟล็ก --incremental ที่ใช้เพื่อทำให้ใช้งานได้เฉพาะส่วนของแอปที่มีการเปลี่ยนแปลงนับตั้งแต่การทำให้ใช้งานได้ครั้งล่าสุด

และยังรองรับแฟล็ก --start_app เพื่อให้เริ่มแอปได้ทันทีขณะติดตั้ง

อ่านเพิ่มเติม

ดูรายละเอียดเพิ่มเติมได้ที่หน้าเหล่านี้

ขอให้สนุกกับการสร้าง