Android Studio : มารู้จัก Product Flavors กันเถอะ !!!

Pattadon Adhipanyasarij
4 min readSep 25, 2016

--

ในการสร้าง Application ในเวลาทำงานจริงเราอาจจะมีการทำงานที่ environment ต่างกัน เช่น
1. Application สำหรับ Production (App ที่ขึ้น PlayStore แล้ว)
2. Application สำหรับทดสอบระบบที่พัฒนาพร้อมที่จะใช้งานได้จริง (UAT : USER ACCEPTANCE TEST)

เคยเห็นแอพที่เสียตังกับแอพที่ไม่เสียตังใน playstore ซึ่ง 2 แอพนี้ความแตกต่างก็เป็นแอพที่เสียตังจะไม่มี ad เพิ่มความสามารถของ Application บลาๆๆๆ

? : ถ้าเจอแบบนี้ ปกติเวลาทำ จะทำยังไงกันละ ??
- อ้าว ง่ายๆ ผมก็แยก Project ไว้คนละ git เอาสิ

? : อ้าวแล้วถ้าแอพมีการอัพเดพ คุณก็ต้องอัพเดพทั้ง 2 ที่อะดิ
-ใช่ ก็ copy แปะไปอีก Project สิ จะไปยากอะไรละ

? : งี้ถ้าผมมีซัก 10 version ละ คุณต้องแยก Project ทั้ง 10 ที่เลยหรอ
- ก็ copy แปะทั้ง 10 ที่ จะไปยากอะไร

…………………………………………………………………………………………………………………………………………..

เสียเวลาม้ายยยยยยยยยยยยยยยยยยยยยยยยยยยยยยยยย !!!

อย่าทำแบบนี้เลย ไม่ใช่แค่เสียเวลา แต่การ copy & paste ไม่ใช่ทางเลือกที่ดีแน่ๆ

มันเลยมีวิธีที่เรียกกันว่า Product Flavors ขึ้นมา

คราวนี้หลายๆคนที่อาจจะสงสัยว่า Product Flavors คืออะไรละ ???
ถ้าอธิบายสั้นๆมันคือการสร้าง Project แยกออกมาอีกอัน โดยแยกการทำงาน แต่มี Source code ตัวนึงเป็นตัวกลางในการ build

งงละสิ มันคืออะไร งั้นลองทำเลยดีกว่า ลงมือทำนี้ละจะได้เข้าใจ !!

เคยเห็นเจ้าสิ่งนี้กันมั้ย

ปกติทุกครั้งที่เรา Create Project ขึ้นมาจะมีแค่ debug กับ release ซึ่ง 2 อันนี้ไม่ใช่ flavor นะครับ แต่เป็น Build Types เฉยๆ ซึ่งปกติมันมีตั้งแต่ตอนสร้าง Project ขึ้นมาแล้วละ

คราวนี้เราจะทำการสร้าง Flavor ให้มันกัน !
ไปที่ build gradle ระดับ module เพิ่มจากสิ่งนี้ลงไปใน

android {...productFlavors {
production {
applicationId "com.example.testflavorpro"
proguardFile 'proguard-rules.pro'
}

uat{
applicationId "com.example.testflavorprouat"
proguardFile 'proguard-rules.pro'
}
}
...}

หรือจะเพิ่มผ่าน ui ของ Android Studio ที่มีให้อยู่แล้วใน build >> Edit Favors… ก็ได้นะ แล้วแต่สะดวกเลย

sync gradle ซักรอบนึง คราวนี้เราก็จะ Product Flavor มา 2 อันแล้ว ตามภาพข้างล่าง !!

ยังไม่จบนะครับ สำหรับการสร้าง เราจะต้องสร้างที่อยู่ให้กับ Flavor ทั้ง 2 อันก่อนตามนี้

กด RUN เลย !! บึ้มมมมมม

Error:(7, 8) error: duplicate class:

อ้าว !! เห้ย ทำไมไม่ได้อะ เกิดไรขึ้น !?

เจอ Error แบบนี้ไม่ต้องตกใจครับ ไม่ต้องไป search google ให้เสียเวลา
อ่านก่อนครับ !! มันก็บอกอยู่แล้วว่า class มัน duplicate กัน

ตรงจุดนี้ลบ MainActivity ของไฟล์ main ออกซะ

ทีงี้ หลายๆคนน่าจะพอเข้าใจละว่าทำไมถึง duplicate กันได้ ทั้งๆที่อยู่คนละ folder

นั่นคือ main นั้นได้ถูกรวมเข้าไปถึง Production และ uat นั่นเอง อธิบายง่ายๆก็ประมาณนี้นะครับ
1. ถ้าเรา ฺBuild Variant ที่ Production จะได้ source ของ production + main
2. ถ้าเรา ฺBuild Variant ที่ uatจะได้ source uat + main

ไม่สามารถรวม production + uat ได้นะครับ

สังเกตเห็นจะมีการสร้าง Folder production และ uat เพิ่มเข้ามา ซึ่งข้างในทุกอย่างเหมือน main เลยครับ ทั้ง java , res รวมถึง AndroidManifest.xml ด้วย แต่ gradle เราใช้งานร่วมกันทั้ง Flavor นะครับ

ทีนี้เราก็จะสามารถใช้ flavor ได้แว้วววว ! เพียงแค่เพิ่มแค่นี้เอง ง่ายมากกกกก
เวลาที่เราต้องการ build เป็น build Version ไหนให้เปลี่ยนใน ฺBuild Variant ได้เลย ไม่ต้องสลับ project ล่ะ

คราวนี้มาลองเล่นๆกันหน่อย ผมจะสร้าง resource string ตัวกลางของ main เป็นแบบนี้นะครับ

<resources>
<string name="app_name">TestFlavor</string>
<string name="value">flavor</string>
</resources>

คราวนี้ เราจะแยก String สำหรับ Flavor uat และ production นะครับ

uat

<resources>
<string name="app_name">Trail Version</string>
<string name="value">trail</string>
</resources>

production

<resources>
<string name="app_name">Pro Version</string>
<string name="value">pro version</string>
</resources>

ส่วนของ java ก็แค่แสดง textview เฉยๆ ไม่มีอะไรนะครับ

TextView tv = (TextView)findViewById(R.id.tv);
tv.setText(getString(R.string.value));

เอาละ RUN !!! ลองเดาสิว่า ผลจะเป็นอย่างไรกัน

..
..
..
..
..
..
..
..
..

Production
uat

ซึ่งจากผลที่เห็น มันก็คือการที่เรา Override Resource ของ production ไปแทนที่ของ main นั้นเอง

แล้วถ้ามันไม่เจอ resource ของ Flavor มันเองละ มันจะไปใช้ตัวไหน ??

หลายคนน่าจะคิดออกกันแล้ว ทุกอย่างมันดู makesense ของมัน ถ้ามันไม่เจอ มันก็ไปใช้ของตัว main นะสิ

ที่นี้น่าจะพอเข้าใจแล้วว่า Product Flavor ทำงานอย่างไรกันแล้วนะครับ ลองไปปรับใช้กันได้ตามสะดวกเลยยยยย

** บางครั้งที่มีการเปลี่ยน Flavor จะมีการ sync ใหม่ทุกครั้งที่ทำการเลือก

ไงละ Flavor ทำให้ชีวิตดีขึ้นเยอะเลยมั้ยละครับ :)

ก็เป็นการเขียน blog สั้นๆครั้งแรก ถ้ามีอะไรอัพเดพเกี่ยวกับ Android ก็จะพยายามเขียน blog ออกมาอธิบายนะครับ

มาเขียน Blog กันเถอะ ~~~~~~~~~~~~ !!

https://developer.android.com/studio/build/build-variants.html#product-flavors

Update 17 Nov 2017
ตอนนี้เปลี่ยนรูปแบบการใช้งานมีการเปลี่ยนแปลงเล็กน้อยแล้วสำหรับ Android Studio 3.0 เป็นเรื่องเกี่ยวกับ flavor dimensions ลองศึกษาดูครับ

Update 13 July 2018

หากใครยังไม่อยากใช้ flavor dimension ให้เราประกาศ

android {
...
flavorDimensions "default" ...
}

ใน File build.gradle นะครับ

​Flavor dimension คืออะไร ?
ง่ายๆคือ เป็นเหมือน Product flavor อีก 1 ชั้น เช่น
- อยาก build uat ใน android api level 21
- อยาก build uat ใน android api level 23
- อยาก build production ใน android api level 21
- อยาก build production ใน android api level 23

ตัว Flavor dimension จะสามารถแยกเจ้า build uat กับ production ให้รันบน 21 23 ได้โดยผ่าน flavor dimension ครับ

ตัวอย่างการใช้งานจาก requirement ข้างบน

flavorDimensions "api", "environment"productFlavors {
uat{
dimension "environment"
...
}

production {
dimension "environment"
...
}

minApi21 {
dimension "api"
minSdkVersion 21
}

minApi23 {
dimension "api"
minSdkVersion 23
}
}

เรียบร้อยครับ

เพียงเท่านี้ใน build variant เราจะได้ variant เพิ่มมาอีก 2 ชิ้น

ซึ่ง Variant ทั้งหมดที่เราจะได้ก็คือ minApi21uat , minApi23uat , minApi21production , minApi21production

ถ้าชื่อมันไม่สวยงาม งั้นเราก็เอาชื่อ flavordimension สลับมันซะ แบบนี้

flavorDimensions "environment", "api"

ซึ่งเราก็จะได้ ซึ่ง Variant ทั้งหมดที่เราจะได้ก็คือ uatMinApi21 , uatMinApi23 , productionMinApi21 , productionMinApi23

ก็ประมาณนี้ครับ
happy coding ครับ

--

--