เล่าเรื่อง Android Build Process ระหว่าง Build เกิดอะไรขึ้นบ้างนะ

Taweewong Tocharoen
5 min readJun 7, 2021

--

เคยสงสัยกันไหมครับว่าระหว่างที่เรายืนดริปกาแฟรอ Application ของเรา build เนี่ย ระหว่างนั้นมันเกิดอะไรขึ้นบ้าง และคำที่เราเห็นบ่อยๆ ตอน build เช่นคำว่า Dex มันคืออะไรกันนะ

ในบทความนี้ผมอยากจะแนะนำให้คุณผู้อ่านรู้จักกับ Compiler, Android Virtual Machine และขั้นตอนในการ Build Application ของ Android แบบคร่าวๆ ครับ

มาเริ่มที่ตัวแรกกันเลยครับ

Compiler

อย่างที่รู้กันดีว่า source code ที่เราเขียนขึ้นนั้น computer ไม่เข้าใจแน่นอน มันต้องมีการ compile เพื่อให้ computer เข้าใจในสิ่งที่เราเขียนซะก่อน

การเขียน Java ก็เช่นกัน code ที่เราเขียนจะถูก compile ด้วย Java compiler ออกมาเป็น Java bytecode หรือไฟล์ .class แล้วจะนำไฟล์นี้ไป execute บน JVM (Java Virtual Machine)

ถ้าเป็น Java application โดยปกติ หลังจากได้ไฟล์ .class มาแล้วก็จะใช้งานได้เลย ส่วน Android ไม่ได้ใช้ Java bytecode ในการทำงานนะ แต่มี bytecode ที่เป็น format ของตัวเองเลย เรียกว่า .dex (Dalvik Executable)

ซึ่งการจะได้ไฟล์ .dex มา จะต้องเอาไฟล์ .class กับ library ต่างๆ ใน project เช่น .jar .aar มา compile ผ่าน tool อีกตัวนึงชื่อว่า DX และจะได้ bytecode ที่พร้อมใช้งานกับ Android ออกมาเป็นไฟล์ชื่อว่า classes.dex

D8 and R8

ใน Android Studio 3.4 ขึ้นไปจะใช้ compiler ตัวใหม่ชื่อ D8 ซึ่งมาแทน DX โดยที่ D8 จะทำงานได้เร็วกว่าและได้ไฟล์ .dex ที่เล็กกว่านั่นเอง แต่เหนือกว่า D8 ก็จะมีอีกตัวนึงคือ R8 เจ้านี่ก็คือ D8 ที่เพิ่มความสามารถเข้าไป เช่น การ obfuscate หรือลบ class ที่ไม่ได้ใช้ออกเพื่อลดขนาดแอปของเรา แต่ R8 ไม่ได้เปิดใช้เป็น Default นะ ถ้าอยากเปิดใช้ก็เพียงใส่ minifyEnabled true เข้าไปในไฟล์ build.gradle ประมาณนี้

android {
...
buildTypes {
release {
minifyEnabled true
...
}
}
}

ส่วน Dalvik bytecode หรือไฟล์ classes.dex ที่ได้มานั้น จะถูกนำไป execute บน Virtual Machine ที่ทีม Android ทำขึ้นมาต่างจาก Java bytecode ที่จะ execute บน JVM ซึ่งจะพูดถึงในหัวข้อต่อไปครับ

Virtual Machine

เนื่องจากโลกของเรามี CPU Architecture อยู่หลายแบบ มันเลยเป็นการยากที่จะทำให้ Java code ของเราทำงานได้ในทุกที่ เราเลยต้องมีสิ่งที่เรียกว่า JVM (Java Virtual Machine) ที่จะทำให้ code Java ของเราสามารถทำงานได้โดยไม่ต้องคำนึงถึง Architecture ที่ใช้

อย่างที่กล่าวไปก่อนหน้านี้ว่าสำหรับ Android แล้ว code ที่ compile ออกมาจะเป็นไฟล์ classes.dex จะเป็น Dalvik bytecode ซึ่งไม่ใช่ Java bytecode เลยต้องทำ Virtual Machine ขึ้นมารองรับโดยเฉพาะ และมันมีชื่อว่า Dalvik Virtual Machine

Dalvik Virtual Machine

นอกจากจะถูกสร้างขึ้นมาเพื่อ execute Dalvik bytecode แล้ว เจ้าตัว Dalvik เองยังใช้ storage น้อยกว่า กินแบตน้อยกว่า และ load เร็วกว่า JVM ซึ่งก็ทำออกมาเพื่อให้เหมาะกับ mobile device โดยเฉพาะเลยนั่นแหละ

Dalvik ถูกใช้มาตั้งแต่ Android 1 จนถึง Android 4.4 (KitKat) และตอนนั้นเอง Google ก็ได้ออกสิ่งใหม่ที่จะมาแทนที่ Dalvik ชื่อว่า Android Runtime หรือ ART

แต่ใน Android 4.4 ตัว Dalvik ยังไม่ถูกแทนที่นะ ตอนนั้นเราสามารถเลือกได้เลยว่าจะใช้ Dalvik หรือ ART

Dalvik VS ART (Android Run Time)

ในเมื่อ ART มาแทน Dalvik แล้วแสดงว่ามันต้องมีการปรับเปลี่ยนให้ดีกว่าแน่นอน โดยอย่างแรกที่แตกต่างกันก็คือ แอปของเราจะเปิดเร็วกว่าเมื่อใช้ ART ที่เป็นแบบนี้ก็เพราะว่า Dalvik ใช้การ compile แบบ JIT (Just In Time) หรือก็คือ compile ตอน run time นั่นเอง พูดง่ายๆ ว่า compile ตอนเปิดแอปนั่นแหละ ส่วน ART ใช้การ compile แบบ AOT (Ahead Of Time) หรือก็คือ compile รอไว้ตั้งแต่ตอนติดตั้งแล้ว ทำให้ตอนเปิดแอปเร็วกว่าแต่ก็แลกมากับเวลาติดตั้งที่เพิ่มขึ้นและขนาดของแอปที่ใหญ่ขึ้นด้วย

นอกจากนี้หากคุณเคยพัฒนา application ที่รองรับ Android ต่ำกว่า version 5.0 (Lollipop) ซึ่ง version เหล่านั้นจะยังคงใช้ Dalvik อยู่ คุณอาจจะเคยเจอ Error ตัวนี้

The number of method references in a .dex file cannot exceed 64k

เพราะว่าในไฟล์ classes.dex สามารถบรรจุ method ไว้ได้แค่ 65,536 method เท่านั้น และ Dalvik นั้นยังรองรับ classes.dex ของเราได้แค่ไฟล์เดียวอีก เลยทำให้มีโอกาสเกิด error ดังกล่าวได้หาก Application ของเรามี method เยอะเกิน 65,536 method (แต่ทางทีม Android ก็มี library สำหรับแก้ปัญหานี้ไว้แล้วนะ) แต่ถ้า Application ของคุณรองรับ Android 5.0 ขึ้นไปก็ไม่ต้องเป็นกังวลเพราะ ART นั้นรองรับ classes.dex ได้หลายไฟล์อยู่แล้ว

เอาล่ะทบทวนกันสักเล็กน้อย ตอนนี้ขั้นตอนการ build จะเป็นแบบแผนภาพด้านล่างนี้

ในตอนนี้เราก็ได้ bytecode ที่ทำงานได้มาแล้ว อีกสิ่งหนึ่งที่เราจะลืมไปไม่ได้ก็คือ resource ไม่ว่าจะเป็น xml, รูปภาพ และอื่นๆ ซึ่งตัวที่จะมาช่วยเรา pack resouce ต่างๆ เหล่านี้ก็คือเจ้า AAPT

AAPT (Android Asset Packaging Tool)

AAPT จะรับหน้าที่จัดการกับ Resouces, Assets และ Application Manifest โดยการจับพวกเขาเหล่านี้ใส่เข้าไปในไฟล์ที่พวกเราคุ้นเคย APK นั่นเอง

สำหรับคนที่สงสัยว่า Application Manifest คืออะไร ที่เราเห็นๆ กันใน project แต่ละ module หรือแต่ละ library จะมีไฟล์ Android Manifest เป็นของตัวเอง ก่อนที่จะส่ง Android Manifest ให้กับ AAPT เจ้าพวกนี้ต้องโดน Merge กันก่อน สิ่งที่ได้ออกมาก็คือ Application Manifest

และเพิ่มเติมสักเล็กน้อย ในระหว่างที่ AAPT จัดการกับ Resouce ทั้งหมดมันจะทำการเก็บ id ของ resource ต่างๆ มาสร้างเป็นไฟล์ R.java ที่เราคุ้นเคยขึ้นมาด้วย แต่ไฟล์นี้จะถูกนำไป compile รวมกับ code ของเรานะ (แน่ล่ะ มันเป็นไฟล์ java นี่นา)

ตอนนี้เราก็มาถึงขึ้นตอนที่สำคัญมากๆ ก็คือการ pack ของต่างๆ เข้าด้วยกัน ประกอบด้วย

  1. classes.dex ที่ได้จากการ compile code ของเรา
  2. Resouces ต่างๆ ที่ AAPT จัดการมาให้เราแล้ว

ถ้าดูแผนภาพสรุปจะได้หน้าตาประมาณนี้ครับ

หลังจากผสม น้ำตาล เครื่องเทศ สารพัดของกุ๊กกิ๊ก ในที่สุดเราก็ได้ APK (Android Package Kit) ออกมาแล้วว~

แต่ช้าก่อนสหาย ก่อนที่เราจะนำ apk ไป install บนมือถือได้เรายังเหลือขั้นตอนสุดท้ายอยู่นั่นก็คือการ sign apk

Signing APK

APK จะต้องถูก sign ก่อนเสมอ ไม่เช่นนั้นเราจะไม่สามารถนำไปติดตั้งหรือ upload ขึ้น Play Store ได้ การที่เราต้อง sign ก่อนก็เพื่อระบุตัวตนว่า APK นี้มาจากใคร เชื่อถือได้ไหม ถ้ามี update ก็จะมั่นใจได้ว่ามาจากผู้สร้างแอปจริงๆ เพราะมีเพียงผู้ที่ถือ keystore เท่านั้นที่สามารถ sign APK นั้นๆ ได้ และ Android ก็ใช้ tool ที่ชื่อว่า jarsigner สำหรับ sign ไฟล์ .jar นี่แหละในการ sign APK

Sign debug build

หลายๆ คนอาจจะยังเข้าใจว่า debug APK นั้นไม่ได้ถูก sign เพราะตอนที่เรา build debug APK มันไม่มีให้เราใส่ keystore หรือ password อะไรเลยนี่นา จริงๆ แล้ว debug APK ก็ถูก sign เหมือนกันนะ

ด้วยความที่มันเป็น “Debug” APK มันเกิดมาเพื่อใช้ทดสอบเท่านั้น จึงไม่มีความจำเป็นที่ผู้พัฒนาจะต้องมาห่วงเรื่องการ sign อยู่แล้ว Android Studio จะสร้าง keystore สำหรับ sign debug APK ไว้ให้เราอยู่แล้วซึ่งจะเก็บไว้ที่ path ตามนี้

  • OS X & Linux
    ~/.android/debug.keystore
  • Windows
    C:\Users\<user>\.android\debug.keystore

Debug certificate เองก็มีวันหมดอายุด้วยนะ โดยมันจะมีอายุถึง 30 ปี ถ้าหมดอายุแล้วตอนที่เรา build debug apk ก็จะเกิด error ขึ้น ส่วนวิธีแก้ก็ง่ายๆ แค่เข้าไปลบ keystore ตาม path ที่กล่าวไปด้านบนแล้วกด build debug apk ใหม่ Android Studio ก็จะสร้าง keystore ใหม่มาให้ แต่คงไม่น่ามีใครเก็บ debug keystore ไว้นานขนาดนั้นนะ

Sign release build

ในการ sign release build ผู้พัฒนาจะต้องสร้าง keystore ขึ้นมาโดยเราจะต้องใส่ข้อมูลไว้ว่าเราเป็นใครพร้อมกับ password สำหรับ keystore ของเรา แล้วเราจะได้ไฟล์ keystore ที่เป็นนามสกุล .jks ออกมา แล้วเอาก็เอา key ที่เราสร้างไป sign APK ของเรา และเราก็จะได้ APK ที่พร้อมใช้งานและสามารถ upload ขึ้น Play Store ได้

Play App Signing by Google

โดยปกติแล้วเวลาเราสร้าง keystore ขึ้นมาแล้วเนี่ย สิ่งหนึ่งที่นักพัฒนาอย่างเราห้ามทำเลยคือ ห้ามทำหาย! เพราะถ้าหายไปแล้วเราจะไม่สามารถเข้าไป update แอปของเราได้อีกเลย ด้วยเหตุนี้ทาง Google จึงมีบริการมาจัดการเก็บ key ไว้ให้เรา ชื่อว่า Play App Signing ก็คือทาง Google จะเป็นคนสร้าง key สำหรับ sign ไว้ให้เรา แต่ว่าเราก็ต้องสร้าง keystore เหมือนที่ทำตามปกติอยู่ดีนะ แต่ key ที่เราสร้างนั้นเราจะเรียกมันว่า upload key ส่วน key ที่ Google สร้างให้เราจะเรียกว่า app signing key เราจะ sign แอปของเราด้วย upload key แล้วส่งให้ Google sign แอปของเราด้วย key จริงๆ อีกที

https://developer.android.com/studio/publish/app-signing#app-signing-google-play

อ้าว! แล้วมันต่างยังไงกับตอนแรกล่ะ สิ่งที่ต่างคือ key ที่เรามีจะเป็นแค่ key สำหรับ upload ซึ่งใช้ระบุว่าใครเป็นคน upload ขึ้นไปเท่านั้น ไม่ได้ถูก sign ลงไปในแอปเราและไม่จำเป็นต้องเป็น key เดิมเสมอไป นั่นแปลว่าถ้าเราทำ key หาย Google ยังสามารถสร้าง upload key อันใหม่ให้เราได้นั่นเอง

และถ้าเราใช้ Play App Signing กับแอปไหนแล้วเราจะต้องใช้มันตลอดไปเพราะ signing key ของเราอยู่ที่ Google ไปแล้วน่ะสิและเราไม่สามารถขอ key นั้นมาเก็บไว้เองได้ด้วยนะ

จบแล้ว!

เอาล่ะครับ ที่เล่ามาทั้งหมดก็คือสิ่งที่เกิดขึ้นระหว่างการ build แบบคร่าวๆ จริงๆ แล้วเรื่องพวกนี้ก็เป็นเรื่องใกล้ตัวที่หลายๆ คนอาจไม่ได้ให้ความสำคัญมากนัก ส่วนนึงคงเพราะมันเป็นสิ่งที่ Android Studio จัดการให้เราอยู่แล้ว แต่ผมว่ามันก็เป็นพื้นฐานอย่างนึงที่นักพัฒนา Android อย่างเราๆ รู้ไว้ก็ไม่เสียหายครับ

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

--

--

Taweewong Tocharoen
Taweewong Tocharoen

No responses yet