ການແບ່ງ App environment ໃນ Flutter ດ້ວຍ Flutter Flavor Part 1: Android flavor

xangnam phiasakha
LaoITDev
Published in
4 min readAug 5, 2022
https://www.ftbchambers.co.uk/blogs/environment-act-2021-background-structure-and-targets

ການພັດທະນາແອັບໜຶ່ງໆຂຶ້ນມາມັນຄົງຈະງ່າຍຖ້າແອັບນັ້ນບໍ່ມີຄົນໃຊ້ຫຼາຍໆເປັນພັນເປັນແສນ ຫຼື ລ້ານໆຄົນ, ບໍ່ຕ້ອງມີຜູ້ຈ້າງເຮັດແອັບ ແລະ ເປັນແອັບທີ່ເຮົາເຮັດຂຶ້ນມາຫຼິ້ນໆແລ້ວແຕ່ອາລົມຂຶ້ນໆລົງໆຂອງຕົວເອງ ຫຼື ບໍ່ກໍ່ແມ່ນແອັບທີ່ update ໄປແລ້ວບໍ່ກະທົບກັບເງິນໆທອງໆຂອງຜູ້ໃຊ້ຄົງຈະເປັນການເຮັດແອັບໃນຝັນຂອງ Mobile Dev ເຊິ່ງມັນກໍ່ມີຈິງແຕ່ໃນຄວາມຝັນເພາະໂລກແຫ່ງຄວາມເປັນຈິງມັນໂຫດຮ້າຍ ແລະ ບໍ່ປານີກັບ Dev ເລີຍ!!

ຢຸດລະບາຍ! ແລ້ວເຂົ້າເລື່ອງກັນເລີຍດີກວ່າ

ການພັດທະນາແອັບທີ່ເປັນແອັບ scale ໃຫຍ່ໆລະດັບ Enterprise ຫຼື ແອັບທີ່ມີຄົນໃຊ້ຫຼາຍໆ( mobile banking, government app, financial app … etc)ສິ່ງທີ່ Mobile Dev ຕ້ອງຄຳນຶງສະເໝີກ່ອນລົງມື code ຫຼື Setup project ຂຶ້ນມານັ້ນກໍ່ຄື

ການກຽມ Environment ຂອງ App

ວ່າແອັບທີ່ກຳລັງຈະ dev ຂຶ້ນມາມີຈັກ environment ທີ່ຕ້ອງໃຊ້ຖ້າຄິດບໍ່ໄດ້ຢ່າໄດ້ລົງມືເຮັດຫຍັງທັງນັ້ນ!!.

Environment ຂອງ App

Environment ຂອງ App ກໍ່ຄືການແບ່ງແອັບອອກໄປຕາມສະພາບແວດລ້ອມທີ່ຈະນຳແອັບໄປ deploy ຫຼື ໃຊ້ງານ ຕົວຢ່າງເຊັ່ນ: ຕອນພັດທະນາແອັບຢູ່ເຮົາຈະໃຊ້ API URL ຄົນລະຢ່າງກັບແອັບທີ່ຢູ່ເທິງ store (production) ເຮັດແບບນີ້ກໍ່ເພື່ອເມື່ອມີການປ່ຽນແປງ dev api ຈະບໍ່ໄດ້ໄປກະທົບກັບ app production ຂອງເຮົາ ຫຼື ກະທົບຜູ້ໃຊ້ນັ້ນເອງ.

Environment ຂອງແອັບກໍ່ມີຫຼາກຫຼາຍຕາມ Project management methodology ຫຼື git flow (github flow, gitlab flow, git flow)ທີ່ເລືອກໃຊ້ກັນແຕ່ກໍ່ບໍ່ໄດ້ແຕກຕ່າງຫຍັງກັນຫຼາຍ. ໃນບົດຄວາມນີ້ຈະສະເໝີແຕ່ environment ທີ່ຜູ້ຂຽນຮູ້ຈັກ ແລະ ເຄີຍໃຊ້ເທົ່ານັ້ນເຊິ່ງມີ 6 environment.

  • Development ເປັນ env ທີ່ເອົາໄວ້ dev ຢ່າງດຽວເປັນບ່ອນທີ່ເຮົາຈະເອົາ code ມາຢຳໆກັນ.
  • SIT or Test/QA ເປັນ env ທີ່ຫຼັງຈາກເຮົາພັດທະນາ features ຕ່າງໆ ແລະ developer ທົດສອບຮຽບຮ້ອຍລະດັບໜຶ່ງແລ້ວກໍ່ຈະເປັນການສົ່ງໃຫ້ທີມ tester ທົດສອບເພື່ອຢືນຢັນຄວາມຖືກຕ້ອງອີກຄັ້ງ ສຳລັບການສົ່ງ test ຄວນສົ່ງ test ທຸກຄັ້ງທີ່ພັດທະນາ feature ໃດໜຶ່ງສຳເລັດ(Test early) ບໍ່ຄວນເຮັດຄົບທຸກ feature ແລ້ວຈຶ່ງສົ່ງໃຫ້ tester ທົດສອບເພາະອາດຕ້ອງໄດ້ແກ້ຫຼາຍ ແລະ ແກ້ໜັກກໍ່ໄດ້ ເຊັ່ນ: ໄປພົບບັນຫາຢູ່ feature ໜຶ່ງທີ່ໄປພົວພັນກັບອີກ feature ຈົນເຮັດໃຫ້ຕ້ອງໄດ້ re-code ກັນໃຫມ່ກໍ່ມີ!. ຈົ່ງສົ່ງ test ໃຫ້ເລື່ອຍໆ!
  • UAT ຫຼັງຈາກຜ່ານຕີນຜ່ານມື tester ມາຮຽບຮ້ອຍແລ້ວເມື່ອມາຮອດ env ນີ້ແອັບເຮົາກໍ່ພ້ອມຈະອັບຂຶ້ນ production ແລ້ວເຊິ່ງກໍ່ຈະເປັນການສົ່ງໃຫ້ PO ( project owner) ຫຼື main user ທົດສອບເພື່ອ approve ໃນການທົດສອບນັ້ນຈະເປັນໃນລັກສະນະການໃຊ້ງານຂອງ Features ໃຫມ່ໆ , look & feel ຂອງແອັບວ່າຈະໃຫ້ປັບແກ້ໄຂຫຼືບໍ່ເທົ່ານັ້ນເອງ. ສຳລັບ data ທີ່ໃຊ້ທົດສອບໃນ env ນີ້ຈະເປັນ mock production data.
  • Staging ເປັນ env ທີ່ເອົາໄວ້ທົດສອບວ່າແອັບຂອງເຮົາຈະເຮັດວຽກໄດ້ດີເມື່ອຢູ່ production ຫຼືບໍ່ data ທີ່ໃຊ້ທົດສອບນັ້ນຈະເປັນ data ທີ່ copy ຈາກ production ແລະ environment server ແບບດຽວກັບ production.
  • Pre-Production ເປັນ env ທີ່ທົດສອບກ່ອນຈະເອົາຂຶ້ນ production ໃຫ້ user ໃຊ້ຈິງໆເວົ້າກັນແບບງ່າຍໆກໍ່ເປັນ internal test, close test ຫຼື open test ຢູ່ໃນ store ນັ້ນເອງ ເຊິ່ງ env app ຂອງເຮົາກໍ່ຈະເປັນ production ແທ້ໆ data ກໍ່ເປັນ data ແທ້ໆ ຕ່າງແຕ່ບໍ່ໄດ້ public ໃຫ້ຄົນທົ່ວໄປໃຊ້ເທົ່ານັ້ນເອງ.
  • Production ເປັນ env ທີ່ແອັບເຮົາເປີດໃຫ້ຄົນທົ່ວໄປສາມາດ downlaod ໃຊ້ກັນຕາມປົກກະຕິຢູ່ store ສ່ວນໂຕແອັບແມ່ນຈະເຊື່ອມຕໍ່ poduction api ຫຼື poduction service.

ທັງນີ້ ແລະ ທັງນັ້ນການແບ່ງ environment ກໍ່ຂຶ້ນຕາມຄວາມເໝາະສົມຂອງ project ແອັບທີ່ເຮົາເຮັດຢູ່ ເພາະການແບ່ງ environment ກໍ່ເປັນການເພີ່ມຄ່າໃຊ້ຈ່າຍໃນ project ເພາະຕ້ອງ setup api ຫຼື service ຕາມ env ຂອງເຮົາ.

ການແບ່ງ ENV ໃນ flutter

ໃນ flutter ຈະມີ flavor ມາໃຫ້ເພື່ອຈັດການ Enviroment ຂອງແອັບໃຫ້ຢູ່ແລ້ວໂດຍໃຊ້ງານຜ່ານ flag --flavor ຕອນທີ່ໃຊ້ຄຳສັ່ງ run ຫຼື build app

$> flutter run --flavor dev -t lib/main_dev.dart$> flutter build apk --release --obfuscate --split-debug-info=./my_map --flavor dev -t lib/main_dev.dart

ແຕ່ກ່ອນອື່ນເຮົາຕ້ອງມາ Setup project ເຮົາໃຫ້ support ການໃຊ້ງານ flavor ເສຍກ່ອນເຊິ່ງກ່ອນອື່ນໝົດຜູ້ຂຽນຈະຍົກຕົວຢ່າງການ setup 3 env ຄື: dev, sit ແລະ prod (production). ວ່າແລ້ວກໍ່ໄປສ້າງ file main_dev.dart , main_sit.dart ແລະ main_prod.dart ຕາມລຳກັບ env ໂດຍ copy ຈາກ main.dart ນັ້ນເອງ.

ນະຕອນນີ້ project ຈະມີ entry point 3 file ຄື:

  • main_dev.dart
  • main_sit.dart
  • main_prod.dart

ເຊິ່ງໃນແຕ່ລະ file ກໍ່ຈະມີການຮ້ອງໃຊ້ config ທີ່ແຕກຕ່າງຕາມແຕ່ລະ ENV ເຊັ່ນວ່າ: API Config, disable debugger, disable logging, service … etc.

ໂຫຼດ ENV config ຈາກ .env

ເພື່ອຄວາມສະດວກຜູ້ຂຽນຈະເກັບ config ໄວ້ທີ່ .env ໂດຍຈະບໍ່ເອົາຂຶ້ນ git ແລະ ບໍ່ເອົາຄ່າຫຍັງກໍ່ຕາມທີ່ເປັນຄວາມລັບ ແລະ ສຳຄັນທີ່ມີຜົນກະທົບກັບຄວາມປອດໄພຂອງແອັບເຊັ່ນວ່າ: password database, private API key, ໄວ້ຢູ່ໃນ env (ເພາະສາມາດ reverse engineering app ເບິ່ງໄດ້) ຖ້າຈຳເປັນຕ້ອງໃຊ້ຕ້ອງໂຫຼດມາຈາກ service ທາງນອກເຊັ່ນວ່າ: google secret manager ຫຼື ເຮັດ service ເອງທີ່ໃຊ້ key exchange. ນອກຈາກນີ້ເຮົາຍັງສາມາດໂຫຼດ config ຈາກ CI/CD ກໍລະນີ build production app ໄດ້ອີກດ້ວຍ (ໄວ້ບົດຄວາມໝ້າຈະມາຂຽນເລົ່າສູ່ຟັງ).

ໃນ flutter ຫຼື dart ສາມາດໂຫຼດ config ຈາກ file .env ໂດຍໃຊ້ package

ສ້າງ folder ຊື່ env ໃນ root project ແລ້ວສ້າງ file.env ແຍກຕາມ environment ຂອງແອັບດັງນີ້

env
├── .dev.env
├── .prod.env
├── .sit.env

ຕົວຢ່າງ content ໃນແຕ່ລະ ENV

.dev.env

ENV_NAME = 'dev'API_URL="https://dev.example.com"

.sit.env

ENV_NAME = 'sit'API_URL="https://sit.example.com"

.prod.env

ENV_NAME = 'prod'API_URL="https://prod.example.com"

ຢູ່ file main ຂອງແຕ່ລະ env ທີ່ເຮົາ setup ຂຶ້ນມາກໍ່ຮ້ອງໃຊ້ method load env file

/// main applicationvoid main() async {WidgetsFlutterBinding.ensureInitialized();// load environment variablesawait dotenv.load(fileName: "env/.dev.env");// more code
// ..
//..
}

ພຽງເທົ່ານີ້ເຮົາກໍ່ສາມາດຮ້ອງໃຊ້ env config ໄດ້ແລ້ວ.

ຫຼັງຈາກນັ້ນກໍ່ສ້າງ file enviroment_config.dart ເພື່ອຮັບຄ່າ env ໃຫ້ມີ data type

import 'package:flutter_dotenv/flutter_dotenv.dart';/// env code nameenum EnvName { dev, prod, sit}
/// class type environmentclass Environment {/// get api urlstatic String get apiUrl => dotenv.env['API_URL'] ?? "";/// get env namestatic EnvName get envName =>EnvName.values.byName(dotenv.env['ENV_NAME'] ?? "dev");}

ເວລາທີ່ເຮົາຕ້ອງການດຶງຄ່າ environment ມາໃຊ້ກໍ່ພຽງແຕ່ import ໃຊ້ຜ່ານ file ນີ້ເທົ່ານັ້ນ.

Setup Android Flavor

ຫຼັງຈາກ setup dart environment ຮຽບຮ້ອຍແລ້ວຂັ້ນຕອນຕໍ່ໄປເປັນການ setup ໃນ android native ໂດຍເຂົ້າໄປທີ່ build.gradle ຂອງ android/app/src ຈາກນັ້ນໃສ່ config ດັງລຸ່ມນີ້ໃນສ່ວນຂອງ android { ... }

flavorDimensions "version"productFlavors {dev {flavorDimensions "version"resValue "string", "app_name", "Example App Dev"applicationId "com.example.dev"}sit {flavorDimensions "version"resValue "string", "app_name", "Example App SIT"applicationId "com.example.sit"}prod {flavorDimensions "version"resValue "string", "app_name", "Example App"applicationId "com.example.prod"}
}

ຈະສັງເກດເຫັນວ່າໃນແຕ່ລະ env ເຮົາຈະໃຊ້ applicationId ແຕກຕ່າງກັນໃນແຕ່ລະ envແລະ resValue "string", "app_name", "Example App" ເປັນການຕັ້ງຊື່ແອັບຂອງແຕ່ລະ env ໃຫ້ແຕກຕ່າງກັນເພື່ອໃຫ້ຈຳແນກອອກວ່າແອັບເປັນຂອງ env ໃດໃນກໍລະນີທີ່ dev ແລະ ທົດສອບໃນເຄື່ອງດຽວກັນ. ນອກຈາກ config ນີ້ແລ້ວຍັງສາມາດ config ໄດ້ຫຼາຍຢ່າງເຊັ່ນວ່າ: app icon, AndroidManifest config, … etc ສາມາດອ່ານເພີ່ມໄດ້ທີ່ Android configure build variants

ຕໍ່ມາຈະເປັນການ setup ໃຫ້ແອັບເຮົາໂຫຼດໃຊ້ resources ໃນແຕ່ລະ env ສຳລັບ android ຈະງ່າຍດາຍບໍ່ຫຍຸ້ງຍາກຄື IOS ໂດຍໄປທີ່ android/app/src ແລ້ວສ້າງ floder ຊື່ດຽວກັບ env ທີ່ເຮົາໄດ້ກຳນົດໄວ້ໃນ envໃນສ່ວນຂອງ dart ແລະ android flavor

src
├── dev
├── prod
├── sit

ໃນແຕ່ລະ folder ກໍ່ໃສ່ resource ຕົວຢ່າງເຊັ່ນ: image, firebase config file, … etc ເທົ່ານີ້ກໍ່ເປັນອັນຮຽບຮ້ອຍໂດຍມັນຈະຈັບ resource ໄປໃສ່ໃຫ້ເຮົາເອງໂດຍທີ່ເຮົາບໍ່ຕ້ອງເຮັດຫຍັງທັງນັ້ນ!!!

Magic!!!

ຫຼັງຈາກນັ້ນກໍ່ Run app ໄດ້ເລີຍໂດຍໃຊ້ command ດັ່ງນີ້:

  • Run dev environment
$> flutter run --flavor dev -t lib/main_dev.dart
  • Run sit environment
$> flutter run --flavor sit -t lib/main_sit.dart
  • Run production environment
$> flutter run --flavor prod -t lib/main_prod.dart
  • build appbundle
$> flutter build appbundle --obfuscate --split-debug-info=./build_map --release --flavor prod -t lib/main_prod.dart

ພຽງເທົ່ານີ້ເຮົາກໍ່ແບ່ງ environment ຂອງ app ເຮົາໄດ້ແລ້ວ. ຂໍ້ຈົບບົດຄວາມໄວ້ເທົ່ານີ້ກ່ອນຮູ້ສຶກມັນຍາວເກີນໄປແລ້ວ.

ບົດຄວາມຕໍ່ໄປເປັນການ setup environment ຂອງ ios ໄວ້ເຈີກັນໃນບົດຄວາມຕໍ່ໄປ!.

--

--