อยากจะ Publish App ขึ้น F-Droid ต้องทำอะไรบ้าง
ช่วงนี้เจ้าของบล็อกมีเหตุที่ต้องเอาแอปตัวหนึ่งขึ้น F-Droid เลยเขียนบทความนี้เพื่อเล่าสู่กันอ่าน เผื่อว่ามีนักพัฒนาคนไหนต้องการส่งแอปขึ้น F-Droid เหมือนกัน
F-Droid คืออะไร?
สำหรับผู้ใช้แอนดรอยด์ทั่วไปเวลาจะโหลดแอปผ่าน App Store ซักเจ้าก็คงไม่พ้น Google Play เป็นหลัก และก็อาจจะมี App Store ทางเลือกของแต่ละแบรนด์ เช่น ถ้าใช้ของ Samsung ก็จะมี Galaxy Store เป็นอีกทางเลือก เป็นต้น
แต่ F-Droid นั้นจะเป็น App Store ที่ไม่ได้ขึ้นอยู่กับแบรนด์ใด เพราะเป็น Open Source App Store สำหรับแอนดรอยด์ที่มีจุดเด่นดังนี้
- ผู้ใช้สามารถติดตั้งและดาวน์โหลดแอปโดยไม่ต้องลงทะเบียนและไม่มีการเก็บข้อมูลส่วนตัวของผู้ใช้
- แอปทุกตัวใน F-Droid จะเป็น Open Source Project ทั้งหมดและจะต้องผ่านการตรวจสอบจากทีมงาน F-Droid ทุกครั้งไม่ว่าจะเป็นแอปใหม่หรืออัปเดตในภายหลังก็ตาม
ไม่ได้เหมาะกับผู้ใช้แอนดรอยด์ทุกคน
การติดตั้ง F-Droid และแอปที่ดาวน์โหลดจาก F-Droid จะเป็นการติดตั้งแอปแบบ Sideload ที่ต้องดาวน์โหลดไฟล์ APK ลงในเครื่องเพื่อติดตั้งด้วยตัวเอง ดังนั้น F-Droid จึงไม่เหมาะกับผู้ใช้ทั่วไป แต่เหมาะกับผู้ใช้ที่มีความเชี่ยวชาญในการใช้งานแอนดรอยด์หรือที่เรียกกันว่า Superuser มากกว่า
เทียบไฟล์ APK จาก Source Code โดยตรง
F-Droid จะไม่ได้แค่รับไฟล์ APK จากนักพัฒนาไปตรวจสอบเท่านั้น แต่จะตรวจสอบด้วยว่าไฟล์ APK นั้นมาจาก Source Code ที่ Commit SHA นั้นจริงตามที่นักพัฒนาแจ้งไว้ด้วย
นั่นจึงทำให้มั่นใจได้ว่าแอปที่ดาวน์โหลดจาก F-Droid เป็นแอปที่มาจาก Source Code ที่เป็น Open Source Project ตัวนั้นจริง ๆ ไม่ใช่ไฟล์ APK ที่นักพัฒนาแอปใส่โค้ดอย่างอื่นเพิ่มเข้ามาในภายหลัง
มีตรวจสอบความถูกต้องและความปลอดภัย
F-Droid มี CI/CD ในระบบเพื่อตรวจสอบโค้ดภายในโปรเจค เช่นทำ Security & Privacy Analysis ด้วย VirusTotal และ Pithus เป็นต้น
สิ่งที่ต้องควรรู้และควรทำก่อน Submit App ขึ้น F-Droid
ในบทความนี้จะอ้างอิงจากโปรเจคที่อยู่บน GitHub เป็นหลัก ถ้าใช้ Git Hosting เจ้าอื่นก็อาจจะมีจุดที่แตกต่างกันเล็กน้อยนะ
Git Repo ของ F-Droid ที่เกี่ยวข้อง
ขั้นตอนทั้งหมดของ F-Droid จะอยู่บน GitLab ดังนั้นนักพัฒนาจะต้องมี GitLab Account เพื่อเข้าไป Contribute Git Repo เหล่านี้ของ F-Droid
- fdroid/fdroiddata [Data] – เปิด Merge Request (aka Pull Request) เพื่อส่งข้อมูลที่เรียกว่า Build Metadata สำหรับโปรเจคของเรา
- fdroid/rfp [Requests For Packaging] – เปิด Issue เพื่อขอ Submit App ขึ้น F-Droid
เงื่อนไขของโปรเจคที่จะ Submit App ขึ้น F-Droid
- โปรเจคจะต้องเป็น FLOSS (Free, Libre and Open Source Software)
- Library ที่ใช้ก็จะต้องเป็น Free License ทั้งหมด
- ไม่รองรับ Library ของ Google Play Services และ Firebase เพราะเป็น Non-free License
- ไม่รองรับ Non-free Build Tools ใด ๆ เช่น Oracle JDK
- ต้องเป็น Public Project ที่สามารถเข้าถึงผ่าน git, hg, svn, หรือ bzr
- ห้ามมีการดาวน์โหลดไฟล์จำพวก Executable Binary โดยไม่ได้รับอนุญาตจากผู้ใช้ ต้องเป็นแบบ Opt-in เท่านั้น
F-Droid มีการตรวจสอบว่าไฟล์ APK ถูก Build มาจาก Source Code ต้นทางจริงหรือไม่
F-Droid มีกระบวนการที่เรียกว่า Reproducible Builds ที่ทำให้ตรวจสอบได้ว่าไฟล์ APK ที่นักพัฒนาส่งเข้ามาเป็นไฟล์ที่ถูกสร้างมาจาก Commit SHA ตามที่แจ้งไว้
โดยใช้เทคนิคที่เรียกว่า APK Signature Copying ที่จะทำการ Build App จาก Commit SHA นั้น ๆ แล้วเทียบว่า APK Signature ตรงกับไฟล์ APK ของนักพัฒนาหรือไม่
นั่นจึงทำให้ผู้ใช้มั่นใจได้ว่าไฟล์ APK ที่ดาวน์โหลดจาก F-Droid นั้นมาจาก Source Code ชุดนั้น, Tag นั้น, หรือ Commit SHA นั้นจริง ไม่ใช่ไฟล์ APK ที่แอบใส่โค้ดอื่นนอกเหนือจากที่เห็นใน Source Code ทีหลัง
เพิ่ม SHA256 ของ Gradle Wrapper ที่ใช้ในโปรเจค
เพราะใน CI ของ F-Droid จะตรวจสอบ Gradle Wrapper ที่ใช้ในโปรเจคโดยเทียบกับ SHA256 ที่กำหนดไว้ในโปรเจค และถ้านักพัฒนาไม่ได้กำหนด SHA256 ไว้ ก็จะถือว่าโปรเจคดังกล่าวใช้ Insecure Gradle Wrapper และโดนเตือนใน CI Report จาก F-Droid Bot
เพื่อเลี่ยงปัญหาดังกล่าว นักพัฒนาจะต้องเพิ่ม Properties ที่ชื่อว่า distributionSha256Sum
ไว้ใน gradle/wrapper/gradle-wrapper.properties
# gradle/wrapper/gradle-wrapper.properties
distributionSha256Sum=<sha256_by_gradle_version>
โดย SHA256 ของ Gradle Wrapper สามารถดูได้ที่ Gradle distribution and wrapper JAR checksum reference [Gradle Build Tool]
ยกตัวอย่างเช่น โปรเจคที่ใช้ Gradle 8.9 ก็จะต้องกำหนด SHA256 ไว้แบบนี้
# gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
และใช้ Gradle Command ในโปรเจคเพื่ออัปเดต Gradle Wrapper ให้เป็นเวอร์ชันเดียวกับที่กำหนดไว้
./gradlew wrapper --gradle-version 8.9 \
--gradle-distribution-sha256-sum d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
เตรียม Upstream Metadata สำหรับ F-Droid ไว้ในโปรเจค
เพื่อให้ F-Droid สามารถนำข้อมูลพื้นฐานเกี่ยวกับแอปไปแสดงในหน้าดาวน์โหลดได้ เช่น ชื่อแอป, คำอธิบายเกี่ยวกับแอป, หรือภาพตัวอย่างแอป เป็นต้น นักพัฒนาจะต้องเตรียมข้อมูลที่ F-Droid เรียกว่า Upstream Metadata ไว้ในโปรเจค
# App name
<project>/metadata/<locale>/title.txt
# Short description (30-50 characters, no trailing dot)
<project>/metadata/<locale>/short_description.txt
# Full description
<project>/metadata/<locale>/full_description.txt
# App icon
<project>/metadata/<locale>/images/icon.png
# Feature Graphic
<project>/metadata/<locale>/images/featureGraphic.png
# Screenshot
<project>/metadata/<locale>/images/phoneScreenshots/<file_1>.png
<project>/metadata/<locale>/images/phoneScreenshots/<file_2>.jpg
# Changelogs
<project>/metadata/<locale>/changelogs/<version_code>.txt
<locale>
จะขึ้นอยู่กับภาษาที่ต้องการให้รองรับ เช่นen-US
หรือth
เป็นต้น- ไฟล์ภาพรองรับได้ทั้ง
png
,jpg
, และjpeg
แต่ไม่รองรับwebp
โดยข้อมูลเหล่านี้บน Google Play จะเรียกว่า Store Listing นั่นเอง ดังนั้นนักพัฒนาสามารถใช้ข้อมูลเดียวกับที่ใช้บน Google Play ได้เช่นกัน
ถ้าไม่มั่นใจก็สามารถดูตัวอย่าง Upstream Metadata ได้จาก fdroid/fdroidclient [GitLab]
สร้าง Tag และ Release สำหรับเวอร์ชันแอปที่ต้องการ Submit
โดยเลขเวอร์ชันสำหรับ Tag และ Release จะต้องขึ้นต้นด้วย v เสมอ (เช่น v1.0.0) และสร้าง Release ที่มีไฟล์ APK ที่ Build มาจากโค้ดของ Tag นั้น ๆ ด้วย
โดยทีมงาน F-Droid จะตรวจสอบไฟล์ APK ใน Release ด้วยว่าเป็นไฟล์ที่มาจาก Commit SHA ของ Tag นั้นด้วยหรือไม่
เตรียม SHA256 ของไฟล์ APK
ในขั้นตอนการ Submit App จะมีการใส่ SHA256 ของไฟล์ APK เพื่อให้ F-Droid ตรวจสอบความถูกต้อง ซึ่งจะได้มาจากคำสั่ง
apksigner verify --print-certs <apk_file_path> | grep SHA-256
โดยจะได้ผลลัพธ์ออกมาประมาณนี้
Signer #1 certificate SHA-256 digest: 1111222233334444555566667777888899990000111122223333444455556666
ให้เก็บ SHA256 ไว้เพื่อใช้ตอนการสร้าง Build Metadata ในภายหลัง
เตรียม URL ของไฟล์ APK
เพื่อให้ F-Droid เข้าถึงไฟล์ APK ที่นักพัฒนาทำ App Signing มาตรวจสอบ จึงต้องใส่ URL ของไฟล์ดังกล่าวในตอนที่สร้าง Build Metadata ด้วย และถ้านักพัฒนาใช้ GitHub เหมือนกัน ไฟล์ APK ที่อยู่ใน Release ของแต่ละ Tag จะมี URL ดังนี้
https://github.com/<username>/<repo>/releases/download/<release>/<filename>.apk
เนื่องจาก <release>
จะเปลี่ยนไปตามเลขเวอร์ชันของแต่ละ Tag ทำให้ F-Droid กำหนดว่า URL ส่วนใดที่เป็นเลขเวอร์ชันให้แทนที่ด้วย v%v
แทน ยกตัวอย่างเช่น
https://github.com/akexorcist/sfl/releases/download/v%v/app-release.apk
ขั้นตอนการ Submit App ขึ้น F-Droid
เมื่อเตรียมข้อมูลและโปรเจคสำหรับแอปของเราพร้อมแล้ว ขั้นตอนต่อไปก็คือการเปิด Issue และเปิด Merge Request สำหรับ Build Metadata ใน Git Repository ของ F-Droid
Merge Request ของ GitLab ก็คือ Pull Request ใน GitHub น่ะแหละ
Fork Repository สำหรับ Build Metadata
เข้าไปที่ fdroid/fdroiddata เพื่อ Fork Repository มาไว้ใน GitLab ของตัวเองแล้วสร้าง Branch ขึ้นมาเพื่อเพิ่ม Build Metadata ของแอปที่ต้องการ Submit (แนะนำให้สร้าง Branch แยกออกมาจาก master
)
สร้างไฟล์ yml ใน metadata
โดยใช้ชื่อไฟล์เป็น Package Name ของแอป ยกตัวอย่างเช่น metadata/com.akexorcist.sleepingforless.yml
แล้วทำการเพิ่มข้อมูลเข้าไปใน Build Metadata โดยอ้างอิงข้อมูลจากไฟล์ที่อยู่ใน templates/build-gradle.yml
หรือจะอิงจากตัวอย่างข้างล่างนี้ก็ได้
# metadata/<package_name>.yml
Categories:
- <app_categories>
License: <software_license>
AuthorName: <name>
AuthorEmail: <email>
AuthorWebSite: <website>
SourceCode: <source_code_url>
IssueTracker: <issue_tracker_url>
AutoName: <app_name>
RepoType: git
Repo: <git_url>
Binaries: <apk_file_url>
Builds:
- versionName: <app_version_name>
versionCode: <app_version_code>
commit: <tag>
subdir: app
gradle:
- yes
AllowedAPKSigningKeys: <apk_signing_keys>
AutoUpdateMode: Version
UpdateCheckMode: Tags
CurrentVersion: <app_version_name>
CurrentVersionCode: <app_version_code>
- Categories – หมวดหมู่ของแอป สามารถดูได้จาก Categories [Build Metadata Reference] (กำหนดได้มากกว่า 1 หมวดหมู่)
- License – Software License ของ Source Code
- AuthorName – ชื่อ
- AuthorEmail – อีเมล
- SourceCode – URL ของ Source Code
- IssueTracker – URL ของ Issue Tracker
- AutoName – ชื่อแอป
- Repo – URL ของ Source Code ที่ลงท้ายด้วย
.git
- Binaries – URL ของไฟล์ APK ของ Tag นั้น (ที่ให้เตรียมไว้ในตอนแรก)
- Version Name – Version Name ของแอป เช่น
1.0.0
- Version Code – Version Code ของแอปที่เป็น Incremental Version Number
- Commit – ชื่อ Tag ของเวอร์ชันนั้น เช่น
v1.0.0
- AllowedAPKSigningKeys – SHA256 ของไฟล์ APK (ที่ให้เตรียมไว้ในตอนแรก)
- CurrentVersion – Version Name ของแอป
- CurrentVersionCode – Version Code ของแอป
เมื่อเตรียมเสร็จแล้วก็ให้ Commit แล้ว Push ขึ้น GitLab เพื่อทดสอบว่า CI Pipeline สามารถทำงานได้ถูกต้องทั้งหมดหรือไม่ (CI Pipeline จะเริ่มทำงานทันทีที่ Push ขึ้น Upstream)
โดยนักพัฒนาจะต้องรอให้ CI Pipeline ผ่านทั้งหมดก่อนถึงจะไปขั้นตอนต่อไปได้ ถ้ามีปัญหาใน CI Job ใด ๆ ก็ควรเข้าไปตรวจสอบการทำงานของ Log และแก้ปัญหาให้เรียบร้อยก่อน
สร้าง Issue สำหรับ Request For Packaging (RFP)
เข้าไปที่ Issue ของ fdroid/rfp เพื่อสร้าง Issue
สร้าง Issue โดยกำหนดหัวข้อ Issue ว่า "New app: <ชื่อแอป>" แล้วให้เลือก Type เป็น "Issue" ส่วน Description ให้เลือกจาก Template ที่ชื่อว่า "Minimal"
โดย Template ดังกล่าวจะมีรายละเอียดที่นักพัฒนาต้องกรอกข้อมูลดังนี้
- ยืนยันว่าแอปอยู่ภายใต้เงื่อนไขของ Inclusion Policy
- ยืนยันว่าแอปไม่เคยอยู่ใน Repository ของ F-Droid และไม่เคยสร้าง Issue มาก่อน
- ยืนยันว่าได้รับการยินยอมจากเจ้าของแอป
- ได้บริจาคเงินเพื่อสนับสนุน F-Droid หรือไม่ (ไม่บังคับ)
- URL ของ Source Code
- Software License ที่ใช้
- หมวดหมู่ของแอป (Category) แบบเดียวกับที่กำหนดไว้ใน Build Metadata
- คำอธิบายเกี่ยวกับแอปโดยย่อ (Summary)
- คำอธิบายเกี่ยวกับแอปแบบเต็ม (Description)
ถ้าไม่มั่นใจในหัวข้อไหน สามารถดูตัวอย่าง Issue ของเจ้าของบล็อกได้ที่ New app: Ruam Mij [RFP]
สร้าง Merge Request สำหรับ Build Metadata
เข้าไปที่ Merge Request ของ fdroid/data เพื่อสร้าง Merge Request จาก Branch ที่นักพัฒนาได้เตรียม Build Metadata ไว้แล้ว
สร้าง Merge Request โดยกำหนดหัวข้อว่า "New app: <ชื่อแอป>" (เหมือนกับตอนเปิด Issue ใน RFP) แล้วให้เลือก Description ให้เลือกจาก Template ที่ชื่อว่า "App Inclusion"
โดย Template ดังกล่าวจะมีรายละเอียดที่นักพัฒนาต้องกรอกข้อมูลดังนี้
- ยืนยันว่าแอปอยู่ภายใต้เงื่อนไขของ Inclusion Policy
- ยืนยันว่าได้รับการยินยอมจากเจ้าของแอป
- ยืนยันว่าข้อมูล Build Metadata และ RFP ถูก Reference จาก Merge Request นี้
- ยืนยันว่า CI Pipeline ของ Build Metadata ผ่านทั้งหมดแล้ว
- ยืนยันว่าใน Source Code มีข้อมูลของ Upstream Metadata เรียบร้อยแล้ว
- ยืนยันว่าใน Source Code ได้ทำ Release ที่อ้างอิงจาก Tag ตามเลขเวอร์ชันเรียบร้อยแล้ว
- (ไม่จำเป็น) ถ้ามี External Repository ในโปรเจค ได้เปลี่ยนจาก
srclibs
เป็น Git Submodule เรียบร้อยแล้ว - (ไม่จำเป็น) ยินยอมให้ F-Droid สามารถทำ Reproducible Build ได้
- (ไม่จำเป็น) ให้ทำเป็น Multiple APKs สำหรับแอปที่มี Native Code เพื่อให้ไฟล์ APK มีขนาดเล็กลง
- ให้ใส่เลข Issue ของ RPF ไว้ในช่องที่ Template ได้เตรียมไว้ เช่น "Closes rfp#1234"
- เลขของ fdroiddata ไม่ต้องกำหนด สามารถลบออกได้เลย
- Label ของ Merge Request จะถูกกำหนดเป็น "New App" เตรียมไว้ให้แล้ว ไม่ต้องกำหนดอะไรเพิ่ม
ถ้าไม่มั่นใจในหัวข้อไหน สามารถดูตัวอย่าง Issue ของเจ้าของบล็อกได้ที่ New app: Ruam Mij [Build Metadata]
รอการรีวิวจาก F-Droid
หลังจากที่สร้าง Issue ใน fdroid/rfp และ Merge Request ใน fdroid/data เสร็จเรียบร้อยแล้ว CI Pipeline ของ fdroid/data ก็จะทำงานทันทีเพื่อตรวจสอบว่า Build Metadata ของนักพัฒนาทำงานได้ถูกต้องครบถ้วน และในระหว่างนั้นก็จะมี F-Droid Bot มาแนบ Report ใน Comment ของ Merge Request นั้น
นอกจาก F-Droid Bot ก็จะมีทีมงานของ F-Droid เข้ามารีวิวและดูผลลัพธ์ของ CI และอาจจะเปิด Thread เพื่อให้นักพัฒนาแก้ไขปัญหาตามคำแนะนำด้วย
โดยจุดสังเกตสำคัญในระหว่างนี้ก็คือการใส่ Label ของทีมงานที่จะบ่งบอกว่า Merge Request ของเราอยู่ในสถานะใด ถ้า Label เป็น waiting-for-upstream
คือทีมงานรอการแก้ไขหรือคำตอบจากเรา
เมื่อขั้นตอนทั้งหมดผ่านไปได้ด้วยดี ทีมงาน F-Droid จะใส่ Label ว่า reproducible-builds
กับ review-requested
ก็แปลว่า Merge Request นั้นพร้อมจะถูก Merge เข้าไปใน Main Branch ของ fdroid/data แล้วนั่นเอง
สามารถดูตัวอย่าง Merge Request ของเจ้าของบล็อกได้ที่ New App: Ruam Mij [Merge Request]
และเมื่อ Merge Request ถูก Merge เรียบร้อย Issue ของ RFP ที่เปิดไว้ก็จะถูกปิดไปพร้อมกันด้วย ถือว่าเป็นอันเสร็จสิ้นขั้นตอนการ Submit App ขึ้น F-Droid แล้ว
รอจนกว่าแอปจะโผล่อยู่บนหน้าเว็ปหรือแอป F-Droid
F-Droid จะไม่ได้นำแอปของนักพัฒนาขึ้นในระบบให้ทันที เหมือนกับ App Store เจ้าอื่น เพราะระบบของ F-Droid จะมี Build Cycle หรือรอบในการเพิ่มแอปเข้าไปในระบบที่ไม่ได้ถี่มาก ซึ่งจะใช้เวลา 3-7 วัน โดยอ้างอิงจาก Genera FAQ [F-Droid Wiki]
แอปเจ้าของบล็อกใช้เวลารอไป 7 วัน
และเมื่อระบบนำแอปของเราขึ้นไปอยู่บนหน้าเว็ปหรือแอปของ F-Droid เป็นที่เรียบร้อยแล้ว ก็ขอแสดงความยินดีด้วยครับ 🎉🎉