มาเพิ่ม Skill ของ Android Developer ด้วยการทำ Android Library กันเถอะ

Android Oct 21, 2022

เราเชื่อว่า Android Developer ทุกคนเคยใช้ library แต่ก็ไม่ใช่ทุกคนที่เคยทำ library ใช่ป้ะ?

บทความนี้เป็นเนื้อหาที่พูดในงาน Android Bangkok 2022 นะ

แล้วทำไมเราต้องทำ library ด้วยนะ ?

อาจจะเกิดจาก developer คนนึง อยากทำ library อะไรสักอย่าง เพื่อใช้เอง หรือแบ่งปันให้เพื่อนๆได้ใช้งาน เช่น อยากทำ library สำหรับ scan QR Code, ทำแอพแชทหน้าตาเหมือน Facebook Messenger, ทำ view แบบปัดซ้ายขวาเหมือน Tinder หรือทำ library แบบ IG Story ที่มันมี indicator ข้างบน

หรือถ้าเป็นงานเป็นการหน่อย …

สมมุติทีม A ทำ product app A ขึ้นมา มี 9 features

วันดีคืนดี ทีม B อยากได้ feature 1 ไปใช้บ้าง และ PM คำนวณแล้ว การเอา feature ที่มีอยู่แล้วในองค์กรมาใช้ ก็น่าจะมี cost ที่น้อยกว่าทำใหม่ทั้งหมดเนอะ แล้ว feature นั้น ก็ดั้นไปอยู่ใน module app ที่อ้วนตาม feature ที่เพิ่มขึ้นมาด้วยหน่ะสิ

บางที่เขาก็แยกทีมทำ library ไปเลย โดยสร้าง library module สำหรับ feature ต่างๆ ไปไว้ใน SDK repository

ซึ่งการที่เราจะทำ library หรืออะไรต่างๆได้นั้น ควรจะต้องใช้ modular architecture นะ เพื่อให้สะดวก และง่ายต่อการประกอบของต่างๆที่มี เข้าด้วยกันได้ หรือถอดออกจากกันก็ง่าย

เช่น ตัวอย่างนี้ module app เป็น module ที่ใช้ในการรันแอพขึ้นมา ซึ่งข้างในไม่ได้ implement อะไร นอกจากเรียกใช้งาน module อื่นๆ ไม่ว่าจะเป็น module ที่เป็น feature หรือ core

ทำให้เราสามารถดูแลของข้างในได้ง่ายขึ้น ทำให้บิ้วแอพได้เร็วขึ้น และนำบาง feature ที่ทำไปให้ทีมอื่นเอาไปใช้ได้ด้วยหล่ะ

สำหรับเรื่องของ modular architecture เราเคยเล่าเรื่อง concept อะไรต่างๆไว้แล้ว สามารถไปฟังเพิ่มเติมได้ที่คลิปนี้นะ

และเราจะสร้าง android library อย่างไรหล่ะ ?

แน่นอนว่า build.gradle ของ module app จะเป็น apply plug-in แบบนี้ เพื่อบอกว่า module นี้เป็น module application นะ

apply plugin: 'com.android.application’

วิธีการสร้าง library module ก็แสนจะง่าย เพียงแค่คลิกขวาสร้าง module ใหม่

เลือก Android Library แล้วกรอก module name และ package name ให้เรียบร้อย และอย่าลืมเลือก minimum SDK ด้วยนะ พยายามเลือกขั้นตํ่าที่สุด อาจจะเลือก API 16 หรือ API 21 ก็ได้ ตามความเหมาะสม

เมื่อทำการสร้าง library ของเราเรียบร้อยแล้ว สังเกตว่า ใน build.gradle ของ library นี้ จะ apply plugin Android Library มาแล้วนะ

apply plugin: 'com.android.library'

จากนั้นก็ coding ไปเรื่อยๆจนเสร็จสิ้น พร้อมส่งมอบ library ให้กับคนอื่นๆต่อแล้วนะ

แล้วเราจะสร้างปล่อย android library ที่เราทำเสร็จแล้ว ให้คนอื่นได้ใช้งานได้อย่างไร?

มีวิธีที่เราหยิบมาพูดถึง 2 วิธีด้วยกัน โดยในตอนนี้จะพูดถึงการปล่อย library ที่เราทำเสร็จให้ทีมอื่น ๆ ได้นำไปใช้งานกัน คือ AAR และ POM เราจะมาค่อยๆดูไปทีละอันกัน

AAR (Android ARchive)

วิธีการ generate AAR ไฟล์นั้นก็แสนจะง่ายดาย เมื่อเราทำ Library จนพอใจแล้ว ก็ทำการ build ซะ โดยจิ้มไปดังนี้

{Project_Name} -> {Library_Module} -> Tasks -> build -> build

ไฟล์ AAR ที่ได้ จะอยู่ใน

{Project_Name} -> {Library_Module} -> build -> outputs -> aar

วิธีการนำไฟล์ AAR ไปใช้งาน มีหลายๆวิธี เช่น

แบบแรก วิธีแรก ให้สร้าง library module ขึ้นมาใหม่ และลบไฟล์ทุกอย่างทิ้ง จากนั้นใส่ไฟล์ aar ของเราลงไป

จากนั้นแก้ไฟล์ build.gradle ของ library ที่เพิ่งสร้าง เป็นหน้าตาแบบนี้ จากนั้น sync gradle 1 รอบ

แล้วค่อยเอาไปใช้งานตามปกติแบบนี้

ซึ่ง ref มาจากบล็อกพี่เอก

วิธีใช้งาน AAR Library ในโปรเจคแอนดรอยด์ของเรา
บ่อยครั้งที่การพัฒนาแอปแอนดรอยด์ก็ต้องพึ่งพาไลบรารีต่างๆมากมาย แต่บางครั้งก็อาจจะต้องใช้ไลบรารีที่เป็นไฟล์ AAR มาใช้ในโปรเจค

แบบที่สอง เป็นวิธีที่เราใช้ประจำ คือเอา AAR มาใส่ใน folder libs จากนั้นนำมา implement ใน build.gradle ของ module ที่เราต้องการ จากนั้น sync gradle 1 รอบก็ใช้งานได้หล่ะ

พอได้แล้วก็นำไปให้คนอื่น ๆ ได้นำไปใช้งานกัน

แต่ก็มีปัญหา คือ แต่ก็เกิดปัญหาขึ้นมา จากการนำเจ้า AAR ไปใช้ต่อ คือ พวก dependency ที่ใช้ใน Library นั้น มันไม่ตามมาด้วยจ้าาาาาา

เรามีดูข้างในเจ้า AAR ไฟล์กันหน่อย ว่าข้างในมีอะไรบ้าง

จากใน document เขาบอกว่า เจ้า aar file เหมือน zip file มีไฟล์ที่บังคับที่มีในนั้น คือ AndroidManifest ส่วนข้างล่างไฟล์ aar จะมีพวกนี้ติดมาด้วยนะ

https://developer.android.com/studio/projects/android-library#aar-contents

อ่ะไหนๆลองพิสูจน์ดูซิ ว่าตรงกันไหม

เราเปลี่ยนสกุลไฟล์ AAR เป็น zip เพราะใน Document บอกว่า AAR เป็น zip ที่รวมไฟล์ต่างๆของ Library เข้าด้วยกัน

ปล. ของ macos อย่าลืมกด Add ไม่เช่นนั้นเวลา extract ไฟล์นี้ออกมันจะดันกลับมาเป็น AAR เหมือนเดิมจ้า

จากนั้นลอง extract file ออกมาดู จะพบกับ AndroidManifest แล้วก็ไฟล์ source code ต่างๆ อยู่ใน classes.jar มีไฟล์ resource ต่างๆ รวมไปถึง proguard ด้วย

แน่นอนว่า ไม่น่าจะมีสิ่งที่เกี่ยวข้องกับ dependency ที่ library เราเรียกใช้อยู่นะ

วิธีแก้ปัญหา ต้องไปบอกทีมหรือคนที่ใช้ AAR นี้ ให้เราได้ทราบ เช่น ไปใส่ใน README.md ในโปรเจก ว่า ต้องใส่ dependency เพิ่มด้วยนะ ไม่งั้นใส่แล้วแอปจะ crash นะ เพราะไม่ได้เพิ่ม dependency ที่ library ใช้ เข้ามาด้วย

แล้วเราทำไฟล์ AAR ที่ติดพวก dependency ที่ library ใช้มาด้วยได้ไหมนะ?

คำตอบคือได้นะ ที่ทีมเคยทำจะประมาณนี้นะ เดี๋ยวเรามาอธิบายเรื่อง POM กันต่อเลย

POM (Project Object Model)

แจ้งเตือน: แต่ละเจ้าจะที่ทำ private maven repository มีการ set config หรืออะไรบางอย่างที่แตกต่างกันไป แต่โดยรวมขั้นตอนและหลักการเหมือนกัน แนะนำให้ไปอ่าน document แต่ละเจ้าเอานะ

pom คืออะไร?

ย่อมาจาก Project Object Model

เป็นไฟล์ xml ที่ประกอบไปด้วยข้อมูลของเจ้า library ของเรา ประกอบไปด้วย groupId, artifactId, version ของ library ของเรา และ dependencies ต่างๆใช้ใน library ทำให้เราสามารถนำตัวนี้ไปใช้ได้เลย โดยไม่ต้องบอกให้คนที่ใช้งาน library เรานั้น ไปใส่ dependency ต่างๆที่เกี่ยวข้องเอง

ขั้นตอนการเอา pom ขึ้นไป ก่อนอื่นสร้างไฟล์ใหม่ ชื่อว่า upload.gradle ก็แล้วกันเนอะ อยู่ folder เดียวกับ build.gradle ของ module แล้วก็พิมพ์คำสั่งแบบนี้ ซึ่งคำสั่งนี้ทำงานกับ gradle 7 แต่ถ้าใช้ version ของ gradle ตํ่ากว่านี้ก็ท่าประมาณนี้แหละ syntax ใกล้เคียงกัน

  • การใส่พวก groupId artfaceId version แรกๆเราจะงงว่าใส่ยังไง จริงๆถ้าเราอัพ pom ขึ้นไปเสร็จแล้ว หน้าตาจะเป็น format แบบนี้เลย มี colon คั่น
{groupId}:{artifactId}:{version}
Ex. androidx.recyclerview:recyclerview:1.2.1
  • url ถ้าเราขึ้นแบบ local บนเครื่องเราเอง จะใส่เป็นแบบนี้ก็ได้ แต่ถ้าใช้ของเจ้าอื่นเขาจะมี url format ให้ใส่ตาม document
  • ถ้าขึ้น local บนเครื่องของเราเอง ไม่ต้องใส่ credentials ก็ได้ แต่ถ้าขึ้นบางทีอาจจะต้องใช้ เพราะว่ามันมีเรื่อง permission ว่าคนไหนเข้าได้ไม่ได้ ได้แค่ไหน

และเราสามารถไปเก็บพวก url หรือ username password ได้ที่ไฟล์ gradle.properies หรือเก็บไว้ใน local.properties ถ้าไม่อยากเอาขึ้น git นะ อันนี้แล้วแต่สะดวกเลย

url=”/helloaar/”
username=USERNAME
password=PASSWORD

หน้าตาโค้ดโดยรวมเนอะ

การบิ้ว pom ของเราขึ้นไป ไปที่แถบ gradle แล้วจิ้ม

{Project_Name} -> {Library_Module} -> Tasks -> publishing -> publish

เมื่อเรา upload POM เสร็จแล้ว จะได้ผลลัพธ์อะไรกลับมากันนะ ?

จากรูปนี้ เราจะเห็นของ 2 ส่วนด้วยกัน คือ folder ที่มีเลข version และ metadata เราจะมาดูทีละส่วนกัน

  • folder ของเลข version จะมีไฟล์ aar และไฟล์ pom

ข้างในไฟล์ pom จะประกอบไปด้วย groupId artifaceId version เจ้า packaging เป็น aar แล้วก็ dependency ต่าง ๆ ที่ library ของเราใช้งานด้วย โดยถ้าเราเรียกใช้ library ตัวนี้ จะดึงของ dependency มาที่ local นะ

  • metadata ข้างในประกอบด้วย groupId และ artifactId เช่นเดิม ส่วน versioning จะมี release คือ version ล่าสุด และ versions คือ version ทั้งหมด แล้วก็ lastUpdated บอกว่าอัพเดตล่าสุดเมื่อไหร่ โดยมันจะเป็น milliseconds นะ

การนำ POM มาใช้งาน

ไปที่ build.gradle ของ project ใส่เพิ่มเติมไปดังนี้ ตรง allproject ที่ build.gradle ที่ชั้น root นะ ถ้าอันนั้นมี credentials ก็ใส่ไปด้วย

//build.gradle of project
allprojects {    
    apply plugin: 'maven-publish'    
    repositories {        
        maven {            
            url '/helloaar/'            
            credentials {                
                username "${username}"                
                password "${password}"            
            }        
        }    
    }
}

การใช้งาน ไปที่ build.gradle ของ module แล้วก็เรียก dependency ไปตามปกติเลย แล้วก็ build ไปสักหนึ่งรอบก็ใช้งานได้หล่ะ

//build.gradle of module
implementation "{groupId}:{artifactId}:{version}"
implementation "androidx.recyclerview:recyclerview:1.2.1"

ข้อควรระวัง

  • minSdkVersion & targetSdkVersion: ควรทำให้มัน compat ให้แอพอื่นๆสามารถใช้งาน library ของเราได้นะ ไม่ใช้อันใหม่จนเกินไป ไม่งั้นจะใช้ไม่ได้
  • Library Conflict: อันนี้ทำ modular architecture ก็เจอได้ สมมุติถ้าใน library หรือไม่ก็ module ชั้นในใช้ version library ที่ใหม่กว่าชั้นนอก เช่น module app ก็ทำให้โปรเจกต์ของเรา build ไม่ผ่านเนอะ

วิธีแก้ก็คือ set version ของ library ไว้ที่ build.gradle ชั้นนอกสุดเลย และตัวแปรนี้ไปใช้งาน ก็จะหมดปัญหาไปหนึ่ง

แต่ถ้าในโปรเจกต์เราใช้ version เดียวกันหมดแล้ว แต่ใน pom ใช้ version ที่ไม่เหมือนกัน ให้ใช้ force scope เมื่อมี dependency version ที่ไม่เท่ากัน เพื่อให้เอามาจาก global หรือใน pom แทนในโปรเจกต์

  • Resource Conflict: เราควรหลีกเลี่ยงการตั้งชื่อ resource ที่เหมือนกัน ไม่เช่นนั้นจะถูกแอปหลัก override ได้

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

วิธีแก้ ให้ใส่ชื่อ library เป็น prefix ไว้ข้างหน้า เป็นการหลีกเลี่ยงการถูก override ของ resource นะ

ถ้าเราต้องใส่ prefix เยอะมาก ๆ แล้วกลัวหลุด อาจจะใช้อันนี้ในการช่วย check ในการที่เราใส่ prefix ต่างๆของแต่ละ xml หรือ resource ว่าเราใส่ไปแล้วนะ ถ้าเราไม่ได้ใส่มันจะเตือนแดงๆให้

//module build.gradle of library
android {
    sdkResourcesPrefix 'YOUR_PREFIX_'
}
  • Proguard + minify: ถ้าเรา enable ProGuard และทำ minify ตอนที่จะเอา library ขึ้นไป ชื่อไฟล์อาจจะถูกเปลี่ยนเป็นประมาณ a.b ซึ่ง library อื่นอาจจะโดนเปลี่ยนชื่อแล้วโดนชื่อเหมือนกันได้ และเมื่อแอพเราใช้ lib 2 ตัวนี้ มันจะโดน duplicate file เป็น compile error

วิธีแก้ ใช้ option -repackageclasses a.example.package บน ProGuard เวลา obfuscate มันจะย้ายไป folder ที่เรากำหนด a.example.package

  • Don’t forget Unit Testing: สุดท้าย ก่อนส่ง library ให้คนอื่นใช้ อย่าลืมทำ Unit Test และถ้าใช้ในองค์กร ให้ tester สุดน่ารักของเราช่วยดูอีกรอบก็ได้นะ

Beyond to open source

สำหรับใครที่อยากเอา library ของเราออกสู่ชาวโลก เป็น open source เนอะ

การทำ README.md

โปรเจกต์ open source ที่ดี ต้องมี readme ที่อ่านแล้วเข้าใจง่าย ง่ายๆคือคนที่จะมาใช้ เขาต้องรู้ว่า library นี้ทำอะไรได้บ้าง เอาไปติดตั้งยังไง เอาไปใช้งานยังไงต่อ ตอนนี้ version เท่าไหร่ และตบท้ายด้วย license ของ project

อันนี้เป็นตัวอย่าง เอามาประยุกต์ใช้ได้

หรือเข้าเว็บนี้ก็ได้นะ มี template ให้เลย

Make a README
Learn how to make a great README for your programming project, and use the editable template to get started.

ตัวอย่าง Android Library ที่เป็น open source ว่าเขาใส่ readme ยังไงเนอะ ซึ่งทางเราหยิบ library ตัวนี้ของพี่เอกมาศึกษาดูจ้า

GitHub - akexorcist/ScreenshotDetection: [Android] Screenshot detection while user using your app
[Android] Screenshot detection while user using your app - GitHub - akexorcist/ScreenshotDetection: [Android] Screenshot detection while user using your app
  • ด้านบนเราสังเกตว่า จะมี badge ต่างๆ บอกว่า library นี้อยู่บนเว็บ Android Arsenal นะ ตอนนี้เป็น version เท่าไหร่ มี minSdkVersion เท่าไหร่ เทสเป็นไง
  • library นี้คืออะไร
  • วิธีติดตั้งให้โปรเจกต์
  • การใช้งาน library ตัวนี้
  • demo เพื่อบอกว่าเอ้ออ ใช้แล้วผลเป็นยังไง มีหน้าตายังไง เอาให้เราตัดสินใจได้ว่า library นี้ตรงกับที่ต้องการหรือไม่
  • สุดท้าย license ส่วนใหญ่จะใช้ Apache License, Version 2.0 กันนะ

ซึ่ง document ของ Android ก็พูดเรื่องนี้ไว้เช่นกัน

https://source.android.com/docs/setup/about/licenses

การใส่ license ของ library จะมีผลต่อแอพที่ใส่เจ้า Open Source Notices ด้วยนะ อันนี้เป็นตัวอย่าง เราลองส่อง library ในตำนานของพี่เอก ที่ตอนนี้ไมได้ทำต่อแล้ว เพราะ Android 13 support เรื่องภาษาในแอพแล้ว เมื่อกดไปดูเราก็จะเห็น license ของ library นั้น ๆ

เมื่อไป check บน github พบว่าตรงกันเนอะ คือดึงจากตรงแถวๆนี้

สามารถอ่านเรื่อง Open Source Notices ต่อได้ที่นี่เลย
สร้างหน้า Open Source Notices บน Android Application
พอดีมีเหตุที่แอพทั้งออฟฟิศต้องทำ แล้วก็สงสัยด้วยแหละว่าจริงๆต้องทำยังไง ต้องทำเองไหม ต้องเอา license มาจากไหน บลาๆ

ปล. อยากอ่านเรื่อง license เพิ่ม ไปดูได้ที่นี่เลย

Licensing a repository — User Documentation
Public repositories on GitHub are often used to share open source software. For your repository to truly be open…
Adding a license to a repository - GitHub Docs
You can include an open source license in your repository to make it easier for other people to contribute.

Create Release in Github & Publish Library with Jitpack

สามารถอ่านต่อได้ที่บล็อกนี้เลยจ้า

การเผยแพร่ Library ของเราผ่าน JitPack เพื่อ Contribute to Open Source
การปล่อย Library ออกเป็น Open Source วิธีนึงที่คนใช้กันเยอะมากๆ นั่นคือ การเอาไปฝากที่ JitPack นั่นเองงงงง~~~

Bonus

  • Jitpack สามารถทำ private repo ได้ด้วยนะ ดูตามราคาในนี้ได้เลย
  • สามารถอ่านวิธีการ set pom ขึ้น jitpack จากบล็อกคุณคนนี้ได้ ซึ่งเขาใช้ gradle 7 ทำไม่ยาก แล้วก็ตัวของที่ต้องใช้จะคล้ายๆกัน แล้วแต่แต่ละเจ้าว่าใส่อะไรเพิ่มเติมไปบ้าง
Publishing Android library using Gradle 7.0 to Jitpack
We always want to keep ourselves updated, and also our code. Updates being enhancements, newer features, performance improvements and…

อันนี้สไลด์ที่ขึ้นพูดนะ

.

สุดท้ายขอบคุณทีม ที่ช่วยเหลือในเรื่องของข้อมูล ทำให้ session นี้สมบูรณ์ยิ่งขึ้น

ขอบคุณทุกคนที่มาฟัง ที่เสียสละวันศุกร์ที่เป็นวันทำงาน มางานนี้ และมาฟัง session ของเรา

และขอบคุณงาน Android Bangkok 2022 ด้วยนะคะ สำหรับโอกาสที่ได้ขึ้นพูดอีกครั้งนึง

ปิดท้ายบล็อกนี้ด้วยรูปจากพี่ตี๋นะคะ ขอบคุณค่า


สามารถ support ค่ากาแฟเจ้าของบล็อกได้ที่ปุ่มแดงส้มสุดน่ารักที่มุมซ้ายล่าง หรือกดปุ่มตรงนี้ก็ได้จ้า

Buy Me a Coffee at ko-fi.com

ช่องทาง Twitter ติดตามข่าวสารแบบไว ๆ

ติดตามข่าวสารและบทความใหม่ ๆ ได้ที่

อย่าลืมกด like กด share บทความกันด้วยนะคะ :)

Posted by MikkiPastel on Sunday, 10 December 2017

ช่องทางใหม่ ติดตามทุก ๆ สตรีมของเราได้ที่

Twitch
Twitch is the world’s leading video platform and community for gamers.
https://www.twitch.tv/mikkipastel

Subscribe ช่อง YouTube ของเราได้ที่

mikkicoding
Android Developer & Content Creator
https://www.youtube.com/c/mikkicoding

download แอพอ่านบล็อกใหม่ของเราได้ที่นี่

MikkiPastel - Apps on Google Play
First application from “MikkiPastel” on play store beta feature- read blog from https://www.mikkipastel.com by this application- read blog content by chrome custom tab- update or refresh new content by pull to refresh- share content to social network
https://play.google.com/store/apps/details?id=com.mikkipastel.blog

Tags

Minseo Chayabanjonglerd

I am a full-time Android Developer and part-time contributor with developer community and web3 world, who believe people have hard skills and soft skills to up-skill to da moon.