1. Flutter Flavors & Multiple Environments là gì?
Trong quá trình phát triển một ứng dụng Flutter, lập trình viên thường phải xây dựng, kiểm thử và phát hành ứng dụng qua nhiều giai đoạn khác nhau.
Ví dụ, khi mới phát triển ứng dụng, lập trình viên cần kết nối với Backend đang chạy trên máy tính cá nhân để kiểm tra chức năng. Khi ứng dụng gần hoàn thiện, nhóm phát triển có thể triển khai một máy chủ thử nghiệm để kiểm tra các chức năng trong điều kiện gần giống thực tế. Cuối cùng, khi ứng dụng được phát hành cho người dùng, ứng dụng phải kết nối với máy chủ chính thức.
Nếu tất cả những giai đoạn này đều sử dụng chung một cấu hình, quá trình phát triển sẽ gặp nhiều rủi ro.
Ví dụ, lập trình viên đang kiểm thử chức năng xóa đơn hàng nhưng ứng dụng lại kết nối với cơ sở dữ liệu thật của cửa hàng. Điều này có thể khiến dữ liệu đang được sử dụng trong thực tế bị ảnh hưởng.
Để hạn chế những vấn đề như vậy, ứng dụng thường được tổ chức thành nhiều môi trường hoạt động khác nhau, gọi là Multiple Environments.
Đồng thời, Flutter hỗ trợ việc xây dựng các biến thể ứng dụng với những cấu hình riêng thông qua cơ chế thường được gọi là Flavors.
Có thể hiểu:
- Multiple Environments: Là cách tổ chức các môi trường phát triển, thử nghiệm và vận hành chính thức với những cấu hình hoặc tài nguyên khác nhau.
- Flutter Flavors: Là cơ chế hỗ trợ tạo những biến thể của cùng một ứng dụng, cho phép mỗi biến thể có cấu hình riêng, chẳng hạn tên ứng dụng, biểu tượng, application ID hoặc thông tin kết nối dịch vụ.
Hai khái niệm này thường được sử dụng cùng nhau nhưng không hoàn toàn giống nhau.
Multiple Environments mô tả những môi trường mà hệ thống sử dụng. Flutter Flavors giúp tạo và cấu hình những bản ứng dụng phù hợp với từng môi trường hoặc mục đích phát hành.
Ví dụ, một ứng dụng bán hàng có thể được tổ chức thành ba môi trường:
Development → Staging → Production
Mỗi môi trường có thể sử dụng Backend, cơ sở dữ liệu, cấu hình Firebase và những quy tắc vận hành riêng.
2. Tại sao cần nhiều môi trường trong phát triển phần mềm?
Khi mới bắt đầu học lập trình, một dự án nhỏ có thể chỉ cần một Backend và một cơ sở dữ liệu.
Tuy nhiên, khi dự án phát triển lớn hơn, nhiều lập trình viên cùng làm việc và ứng dụng bắt đầu có người dùng thực tế, việc sử dụng chung một môi trường sẽ trở nên bất tiện.
Giả sử một nhóm đang phát triển ứng dụng thương mại điện tử. Một lập trình viên đang kiểm thử chức năng tạo sản phẩm, người khác đang kiểm tra chức năng thanh toán, trong khi khách hàng thực tế vẫn đang sử dụng ứng dụng.
Nếu tất cả cùng thao tác trên cơ sở dữ liệu production, những hoạt động kiểm thử có thể tạo dữ liệu giả, làm thay đổi tồn kho hoặc ảnh hưởng đến đơn hàng thật.
Vì vậy, việc tách môi trường giúp nhóm phát triển có không gian kiểm thử mà không trực tiếp tác động đến hệ thống đang vận hành.
Ngoài ra, các môi trường khác nhau còn phục vụ những mục tiêu riêng:
- Development giúp lập trình viên xây dựng và kiểm tra chức năng.
- Staging giúp nhóm phát triển kiểm thử trước khi phát hành.
- Production phục vụ người dùng thật.
Việc tách môi trường cũng giúp quản lý cấu hình API, Firebase, thông tin dịch vụ và quy trình triển khai một cách rõ ràng hơn.
Tuy nhiên, tách môi trường không tự động bảo đảm an toàn. Các cấu hình, quyền truy cập và quy trình triển khai vẫn cần được thiết kế đúng.
3. Development Environment là gì?
Development Environment là môi trường được sử dụng trong quá trình phát triển phần mềm.
Ở môi trường này, lập trình viên thường xuyên thay đổi code, kiểm tra giao diện, thử nghiệm API và sửa lỗi.
Ví dụ, khi phát triển ứng dụng Flutter bán hàng, Backend có thể chạy trên máy tính cá nhân tại địa chỉ:
http://localhost:8000
Tuy nhiên, cần lưu ý rằng localhost được hiểu là chính thiết bị đang thực hiện kết nối.
Nếu Flutter chạy trên điện thoại thật, localhost sẽ trỏ đến điện thoại chứ không phải máy tính đang chạy Backend.
Vì vậy, khi kiểm thử trên thiết bị thật, ứng dụng thường cần sử dụng địa chỉ IP có thể truy cập của máy tính trong mạng nội bộ hoặc một địa chỉ Backend phù hợp.
Đối với Android Emulator, địa chỉ 10.0.2.2 thường được sử dụng để truy cập dịch vụ chạy trên máy tính chủ trong cấu hình Android Emulator tiêu chuẩn.
Development Environment thường có những đặc điểm như bật nhiều công cụ debug, sử dụng dữ liệu thử nghiệm và cho phép thay đổi cấu hình thường xuyên.
Môi trường này không nên sử dụng dữ liệu nhạy cảm của người dùng thật nếu không có lý do và biện pháp bảo vệ phù hợp.
4. Staging Environment là gì?
Staging Environment là môi trường dùng để kiểm thử ứng dụng trước khi triển khai lên production.
Staging thường được cấu hình gần giống môi trường production hơn so với development.
Ví dụ, nếu production sử dụng Backend triển khai trên máy chủ và cơ sở dữ liệu MySQL, staging cũng có thể sử dụng kiến trúc tương tự nhưng với tài nguyên và dữ liệu riêng.
Mục đích của staging là kiểm tra xem ứng dụng có hoạt động đúng trong điều kiện gần giống thực tế hay không.
Các công việc thường thực hiện trên staging gồm kiểm thử API, kiểm thử tích hợp, kiểm tra chức năng đăng nhập, đặt hàng, gửi thông báo và xác minh những thay đổi trước khi phát hành.
Ví dụ, trước khi cập nhật chức năng thanh toán cho người dùng thật, nhóm phát triển có thể kiểm tra toàn bộ quy trình trên staging.
Một điểm quan trọng là staging không nên tùy tiện sử dụng cơ sở dữ liệu production. Nếu cần dữ liệu gần giống thực tế để kiểm thử, nên sử dụng dữ liệu giả lập hoặc dữ liệu đã được xử lý bảo vệ phù hợp.
5. Production Environment là gì?
Production Environment là môi trường chính thức mà người dùng thực tế sử dụng.
Ví dụ, ứng dụng đã được phát hành trên Google Play hoặc App Store và kết nối với hệ thống Backend chính thức của doanh nghiệp.
Ở môi trường production, dữ liệu có thể bao gồm tài khoản khách hàng, đơn hàng, giao dịch và những thông tin quan trọng khác.
Vì vậy, production thường yêu cầu mức độ ổn định, bảo mật và giám sát cao hơn.
Những thay đổi đối với production cần được kiểm thử và triển khai theo quy trình phù hợp.
Ví dụ, nếu cần cập nhật API đặt hàng, nhóm phát triển nên kiểm tra khả năng tương thích với phiên bản ứng dụng đang được người dùng sử dụng trước khi triển khai.
Ngoài ra, production thường hạn chế các chức năng debug, tránh ghi log nhạy cảm và sử dụng những dịch vụ giám sát cần thiết.
6. Flutter Flavor là gì?
Flutter Flavor là một biến thể cấu hình của ứng dụng được xây dựng từ cùng một codebase.
Ví dụ, cùng một dự án Flutter có thể tạo ra hai ứng dụng:
- MilkStore Dev.
- MilkStore.
Hai ứng dụng này có thể sử dụng cùng phần lớn mã nguồn nhưng khác tên hiển thị, biểu tượng, địa chỉ API hoặc cấu hình Firebase.
Trên Android, Flutter Flavors thường được triển khai thông qua Android Product Flavors trong Gradle.
Trên iOS, cơ chế tương ứng thường sử dụng Xcode Schemes và Build Configurations.
Điều này có nghĩa là Flutter Flavors không chỉ là một biến Dart đơn giản. Nó còn liên quan đến cấu hình build của từng nền tảng.
Ví dụ, một bản development có thể sử dụng application ID:
com.example.milkstore.dev
Trong khi bản production sử dụng:
com.example.milkstore
Khi có application ID khác nhau, hai bản ứng dụng có thể được cài đặt song song trên cùng một thiết bị Android, nếu những cấu hình liên quan được thiết lập phù hợp.
Đây là một lợi ích lớn trong quá trình kiểm thử vì lập trình viên có thể giữ bản production trên điện thoại và cài thêm bản development mà không cần thay thế bản chính thức.
7. Phân biệt Flavor và Environment
Đây là một trong những nội dung quan trọng nhất của keyword này.
Flavor và Environment có liên quan nhưng không đồng nghĩa.
Environment là môi trường hoạt động mà ứng dụng sử dụng, chẳng hạn Backend development, staging hoặc production.
Flavor là biến thể ứng dụng được cấu hình trong quá trình build.
Ví dụ, một dự án có flavor dev và prod.
Flavor dev có thể được cấu hình để kết nối đến Backend development, còn flavor prod kết nối đến Backend production.
Tuy nhiên, không có quy tắc bắt buộc rằng mỗi environment phải có một flavor riêng.
Một flavor có thể nhận thêm cấu hình runtime hoặc build-time để kết nối đến môi trường phù hợp.
Ngược lại, một môi trường có thể được sử dụng bởi nhiều biến thể ứng dụng, chẳng hạn bản dành cho nhân viên và bản dành cho khách hàng.
Vì vậy, khi thiết kế dự án, cần xác định rõ những khác biệt nào thuộc về biến thể ứng dụng và những khác biệt nào thuộc về môi trường Backend.
8. Build Mode trong Flutter có giống Flavor không?
Flutter hỗ trợ những build mode như Debug, Profile và Release.
Các chế độ này không giống với Flavor.
Debug Mode phục vụ phát triển và gỡ lỗi, hỗ trợ những công cụ như hot reload và debugging.
Profile Mode phục vụ việc phân tích hiệu năng trong điều kiện phù hợp.
Release Mode phục vụ xây dựng ứng dụng được tối ưu hóa để phát hành.
Trong khi đó, Flavor xác định một biến thể cấu hình của ứng dụng.
Ví dụ, lập trình viên có thể chạy flavor dev ở Debug Mode để phát triển.
Sau đó, có thể build flavor prod ở Release Mode để phát hành.
Như vậy, build mode và flavor là hai chiều cấu hình khác nhau.
Không nên mặc định rằng Debug Mode luôn kết nối đến development và Release Mode luôn kết nối đến production. Việc lựa chọn môi trường phải dựa trên cấu hình rõ ràng, không chỉ dựa vào chế độ build.
9. Cách cấu hình Flutter Flavors trên Android
Trên Android, các flavor thường được khai báo trong cấu hình Gradle của module ứng dụng.
Ví dụ minh họa bằng Kotlin DSL trong tệp android/app/build.gradle.kts:
android {
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
applicationIdSuffix = ".dev"
resValue(
"string",
"app_name",
"MilkStore Dev"
)
}
create("prod") {
dimension = "environment"
resValue(
"string",
"app_name",
"MilkStore"
)
}
}
}
Đây là phần cấu hình minh họa cần được đặt trong cấu trúc Gradle phù hợp với dự án hiện tại.
Trong đoạn code trên:
flavorDimensions khai báo chiều phân loại flavor.
productFlavors chứa những flavor được tạo.
dev là flavor phục vụ phát triển.
prod là flavor phục vụ production.
applicationIdSuffix = ".dev" giúp tạo application ID khác cho bản development.
resValue khai báo giá trị tài nguyên Android có thể sử dụng làm tên ứng dụng khi Android Manifest được cấu hình tham chiếu đến tài nguyên đó.
Nếu muốn tên hiển thị thực sự thay đổi, cần bảo đảm android:label trong Android Manifest sử dụng tài nguyên @string/app_name hoặc cấu hình tương ứng.
Sau khi thiết lập đúng, có thể chạy flavor development bằng lệnh:
flutter run --flavor dev
Hoặc chạy flavor production:
flutter run --flavor prod
Tuy nhiên, việc có thể chạy được còn phụ thuộc vào những cấu hình Android, Firebase và các thành phần liên quan.
10. Flutter Flavors trên iOS
Trên iOS, Flutter Flavors thường được triển khai thông qua Xcode Schemes và Build Configurations.
Khác với Android, iOS không sử dụng Android Product Flavors.
Ví dụ, dự án có thể tạo các scheme như dev và prod, kết hợp với những cấu hình build phù hợp.
Mỗi scheme có thể được cấu hình để sử dụng bundle identifier, tên ứng dụng, biểu tượng hoặc thông tin dịch vụ khác nhau.
Việc cấu hình iOS cần chú ý đến signing, provisioning profile, bundle identifier và các dịch vụ gắn với định danh ứng dụng.
Ví dụ, nếu sử dụng Firebase Cloud Messaging, mỗi biến thể iOS có bundle identifier khác nhau có thể cần đăng ký ứng dụng Firebase tương ứng và cấu hình APNs phù hợp.
Do đó, khi làm Flutter Flavors cho cả Android và iOS, lập trình viên cần hiểu rằng hai nền tảng sử dụng cơ chế cấu hình khác nhau, dù cùng phục vụ mục đích tạo các biến thể ứng dụng.
11. Quản lý API Base URL theo từng môi trường
Một trong những ứng dụng phổ biến nhất của Multiple Environments là thay đổi API Base URL.
API Base URL là địa chỉ gốc được sử dụng để gọi những endpoint của Backend.
Ví dụ:
Development:
https://dev-api.example.com
Staging:
https://staging-api.example.com
Production:
https://api.example.com
Những địa chỉ trên chỉ là ví dụ minh họa.
Nếu ứng dụng gọi endpoint /products, địa chỉ hoàn chỉnh có thể được tạo bằng cách kết hợp Base URL với đường dẫn endpoint.
Thay vì ghi trực tiếp địa chỉ API ở nhiều vị trí trong code, ứng dụng nên quản lý cấu hình tại một nơi tập trung.
Ví dụ, có thể tạo lớp:
class AppConfig {
static const String apiBaseUrl =
String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'https://dev-api.example.com',
);
}
String.fromEnvironment() cho phép đọc giá trị từ compilation environment được cung cấp khi biên dịch.
Ví dụ, khi chạy ứng dụng:
flutter run \
--flavor dev \
--dart-define=API_BASE_URL=https://dev-api.example.com
Đối với PowerShell trên Windows, có thể viết lệnh trên một dòng:
flutter run --flavor dev --dart-define=API_BASE_URL=https://dev-api.example.com
Khi build bản production:
flutter build apk --release --flavor prod --dart-define=API_BASE_URL=https://api.example.com
Như vậy, cùng một đoạn code Dart có thể sử dụng địa chỉ API khác nhau tùy theo cấu hình được cung cấp khi chạy hoặc build.
Cần lưu ý rằng --dart-define là cấu hình được đưa vào ứng dụng khi biên dịch, không phải cơ chế lưu trữ bí mật an toàn. Người khác có thể phân tích ứng dụng để tìm những giá trị được nhúng trong bản build.
Vì vậy, không nên đưa mật khẩu cơ sở dữ liệu, private key hoặc những bí mật của Backend vào --dart-define.
12. Sử dụng nhiều tệp cấu hình môi trường
Khi số lượng cấu hình tăng lên, việc truyền từng biến qua dòng lệnh có thể trở nên bất tiện.
Ví dụ, ứng dụng có thể cần quản lý API Base URL, tên môi trường, một số feature flag không nhạy cảm và những giá trị cấu hình khác.
Flutter hỗ trợ cách cung cấp nhiều giá trị cấu hình thông qua tệp JSON với --dart-define-from-file.
Ví dụ, tạo tệp env/dev.json:
{
"API_BASE_URL": "https://dev-api.example.com",
"APP_ENV": "development"
}
Tệp env/prod.json:
{
"API_BASE_URL": "https://api.example.com",
"APP_ENV": "production"
}
Sau đó có thể chạy:
flutter run --flavor dev --dart-define-from-file=env/dev.json
Hoặc build:
flutter build apk --release --flavor prod --dart-define-from-file=env/prod.json
Trong Dart, đọc giá trị bằng String.fromEnvironment().
Cách tổ chức này giúp quản lý cấu hình rõ ràng hơn, đặc biệt khi dự án có nhiều môi trường.
Tuy nhiên, các tệp cấu hình được dùng để build ứng dụng không nên chứa bí mật máy chủ. Nếu lưu tệp trong Git, cần xem xét rõ nội dung nào có thể công khai và nội dung nào phải được quản lý bằng hệ thống bảo mật phù hợp.
13. Kết hợp Flutter Flavors với Dio
Trong Flutter, Dio thường được sử dụng để gửi HTTP Request đến Backend.
Khi có nhiều môi trường, ứng dụng có thể cấu hình Dio sử dụng Base URL được lấy từ AppConfig.
Ví dụ:
import 'package:dio/dio.dart';
class AppConfig {
static const apiBaseUrl =
String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'https://dev-api.example.com',
);
}
final dio = Dio(
BaseOptions(
baseUrl: AppConfig.apiBaseUrl,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 15),
),
);
Trong đoạn code này, Dio không cần biết ứng dụng đang chạy flavor nào.
Dio chỉ sử dụng địa chỉ API được cung cấp bởi lớp cấu hình.
Ví dụ, nếu API_BASE_URL là https://dev-api.example.com, yêu cầu:
final response = await dio.get('/products');
sẽ được gửi đến Backend development.
Nếu API_BASE_URL được thay bằng https://api.example.com, yêu cầu tương tự sẽ được gửi đến Backend production.
Cách làm này giúp tách logic gọi API khỏi thông tin cấu hình môi trường.
Tuy nhiên, ứng dụng cần có cơ chế kiểm tra cấu hình trước khi phát hành. Nếu vô tình build bản production với Base URL development, người dùng có thể gặp lỗi hoặc sử dụng nhầm dữ liệu thử nghiệm.
14. Quản lý Firebase theo từng Flavor
Một ứng dụng Flutter có thể sử dụng Firebase Authentication, Firebase Cloud Messaging, Firebase Analytics hoặc Crashlytics.
Khi có nhiều môi trường, nhóm phát triển có thể muốn tách Firebase development và production.
Ví dụ, nếu cùng sử dụng một Firebase Project, các sự kiện Analytics do lập trình viên kiểm thử có thể ảnh hưởng đến dữ liệu phân tích của môi trường chính thức nếu không được tổ chức và lọc phù hợp.
Ngoài ra, thông báo FCM thử nghiệm có thể gây nhầm lẫn nếu cấu hình không được phân tách rõ.
Một cách tổ chức là sử dụng những Firebase Project riêng cho development và production.
Ví dụ:
milkstore-developmentmilkstore-production
Mỗi Firebase Project có những thông tin cấu hình và tài nguyên riêng.
Khi ứng dụng được build với flavor development, ứng dụng sử dụng cấu hình Firebase development.
Khi build flavor production, ứng dụng sử dụng cấu hình Firebase production.
Việc thiết lập có thể được thực hiện thông qua FlutterFire CLI kết hợp cấu hình riêng theo từng flavor và nền tảng.
Cần lưu ý rằng chỉ đổi API Base URL bằng --dart-define không tự động thay đổi Firebase Project. Firebase phải được khởi tạo với cấu hình phù hợp, đồng thời các tệp và định danh ứng dụng của Android hoặc iOS cũng cần khớp với dự án Firebase tương ứng.
15. Flavor có thể thay đổi những gì?
Flutter Flavor không chỉ dùng để thay đổi địa chỉ API.
Tùy cấu hình nền tảng, flavor có thể được sử dụng để thay đổi:
Tên ứng dụng: Ví dụ “MilkStore Dev” và “MilkStore”.
Biểu tượng ứng dụng: Bản development có thể dùng biểu tượng có chữ DEV để dễ phân biệt.
Application ID hoặc Bundle Identifier: Giúp quản lý các biến thể ứng dụng riêng biệt.
Cấu hình Firebase: Mỗi bản có thể kết nối với Firebase Project phù hợp.
API Base URL: Sử dụng Backend tương ứng với môi trường.
Một số tính năng thử nghiệm: Có thể bật hoặc tắt những chức năng nhất định theo cấu hình.
Cấu hình logging: Bản development có thể ghi nhiều thông tin phục vụ debug hơn bản production.
Tuy nhiên, không phải mọi khác biệt đều nên được triển khai bằng flavor.
Nếu một tính năng cần thay đổi linh hoạt mà không phát hành lại ứng dụng, có thể cần cơ chế cấu hình từ xa hoặc feature flag phù hợp.
16. Mối liên hệ giữa Flavors và CI/CD
CI/CD là quá trình tự động hóa những công việc như kiểm tra code, chạy test, build và triển khai ứng dụng.
Khi dự án có nhiều flavor, CI/CD có thể sử dụng những cấu hình build khác nhau tùy mục đích.
Ví dụ, khi lập trình viên đẩy code lên nhánh development, hệ thống có thể chạy test và build bản development.
Khi nhóm chuẩn bị phát hành, CI/CD có thể build bản staging để kiểm thử.
Sau khi các bước kiểm tra được hoàn tất và có phê duyệt phù hợp, hệ thống có thể build bản production.
Một pipeline đơn giản có thể được hình dung như sau:
Code → Kiểm tra → Test → Build Flavor phù hợp → Phân phối hoặc phát hành
Ví dụ, lệnh build production:
flutter build appbundle \
--release \
--flavor prod \
--dart-define-from-file=env/prod.json
Lệnh này tạo Android App Bundle theo cấu hình production, với điều kiện các thành phần liên quan đã được thiết lập đúng.
Trong CI/CD, cần quản lý thông tin ký ứng dụng, quyền truy cập dịch vụ và những dữ liệu nhạy cảm bằng cơ chế secret management phù hợp.
Ngoài ra, pipeline nên có bước xác nhận môi trường đích để tránh vô tình phát hành một bản build có cấu hình không đúng.
17. Những lỗi thường gặp khi sử dụng Flutter Flavors
17.1. Cấu hình sai API Base URL
Ứng dụng được build ở môi trường production nhưng lại kết nối với Backend development.
Điều này có thể khiến người dùng không đăng nhập được hoặc nhìn thấy dữ liệu thử nghiệm.
Cách hạn chế là quản lý cấu hình tập trung và kiểm tra giá trị môi trường trong quá trình build.
17.2. Trùng Application ID
Nếu các biến thể không được cấu hình định danh phù hợp, việc cài đặt song song hoặc quản lý ứng dụng trên nền tảng có thể gặp vấn đề.
Cần phân biệt rõ application ID hoặc bundle identifier của từng biến thể.
17.3. Cấu hình Firebase không khớp
Ứng dụng có thể gặp lỗi khi cấu hình Firebase không tương ứng với application ID, bundle identifier hoặc Firebase Project đã đăng ký.
Vấn đề này thường xuất hiện khi thêm flavor nhưng không cập nhật cấu hình Firebase liên quan.
17.4. Nhầm Flavor với Build Mode
Lập trình viên có thể cho rằng chỉ cần build Release là ứng dụng tự động sử dụng production.
Thực tế, Release Mode chỉ là chế độ build. Môi trường được sử dụng vẫn phụ thuộc vào cấu hình của ứng dụng.
17.5. Đưa bí mật vào ứng dụng
Một sai lầm nghiêm trọng là đưa mật khẩu cơ sở dữ liệu, service account private key hoặc những bí mật của Backend vào tệp cấu hình Flutter.
Các giá trị được đóng gói trong ứng dụng phía client không thể được xem là bí mật an toàn.
Những thông tin cần bảo mật phải được lưu và xử lý ở Backend hoặc hệ thống quản lý bí mật phù hợp.
17.6. Không kiểm thử từng môi trường
Một bản ứng dụng chạy đúng trên development không có nghĩa sẽ hoạt động giống hệt trên production.
Các môi trường có thể khác nhau về dữ liệu, quyền truy cập, cấu hình mạng và dịch vụ bên ngoài.
Vì vậy, cần kiểm thử những chức năng quan trọng trên môi trường tương ứng trước khi phát hành.
18. Ví dụ thực tế về một dự án Flutter bán hàng
Giả sử nhóm phát triển đang xây dựng ứng dụng MilkStore trên Flutter.
Ứng dụng có các chức năng đăng nhập, xem sản phẩm, giỏ hàng, đặt hàng, nhận thông báo FCM và theo dõi hành vi người dùng bằng Firebase Analytics.
Nhóm có thể tổ chức ba môi trường.
Development
Lập trình viên sử dụng môi trường này để xây dựng chức năng mới.
Ứng dụng kết nối với Backend development, cơ sở dữ liệu thử nghiệm và Firebase development.
Có thể bật những công cụ debug cần thiết.
Staging
Nhóm kiểm thử sử dụng môi trường này để xác nhận chức năng trước khi phát hành.
Ứng dụng kết nối với Backend staging và dữ liệu thử nghiệm được quản lý riêng.
Các chức năng như đặt hàng, cập nhật trạng thái, thông báo FCM và xử lý lỗi API được kiểm tra trước khi chuyển sang production.
Production
Người dùng thật sử dụng bản ứng dụng chính thức.
Ứng dụng kết nối với Backend production và những dịch vụ production tương ứng.
Các cấu hình debug không cần thiết được hạn chế, đồng thời hệ thống sử dụng cơ chế giám sát và bảo vệ dữ liệu phù hợp.
Nhờ cách tổ chức này, nhóm phát triển có thể tiếp tục xây dựng chức năng mới mà không phải thử nghiệm trực tiếp trên dữ liệu đang phục vụ khách hàng.
19. Một số nguyên tắc khi thiết kế Multiple Environments
Thứ nhất, cần xác định rõ mục đích của từng môi trường. Không nhất thiết mọi dự án nhỏ đều phải có ba hoặc bốn môi trường ngay từ đầu.
Thứ hai, nên sử dụng cùng một codebase cho những biến thể có chung chức năng, hạn chế sao chép toàn bộ dự án chỉ để thay đổi địa chỉ API.
Thứ ba, cần quản lý cấu hình tập trung, tránh ghi trực tiếp Base URL ở nhiều vị trí.
Thứ tư, phải tách dữ liệu thử nghiệm khỏi dữ liệu production theo yêu cầu của hệ thống.
Thứ năm, không lưu thông tin bí mật của Backend trong ứng dụng Flutter.
Thứ sáu, cần kiểm tra cấu hình Firebase, thông báo và Analytics theo từng môi trường.
Thứ bảy, nên xây dựng quy trình build rõ ràng, đặc biệt khi sử dụng CI/CD để tự động phát hành ứng dụng.
Cuối cùng, cần nhớ rằng Flavor là công cụ hỗ trợ quản lý biến thể ứng dụng, còn việc bảo đảm an toàn và ổn định của môi trường phụ thuộc vào toàn bộ kiến trúc và quy trình triển khai.
20. Kết luận
Flutter Flavors & Multiple Environments là những khái niệm quan trọng khi phát triển và triển khai ứng dụng Flutter trong dự án thực tế.
Multiple Environments giúp phân chia hệ thống thành các môi trường phục vụ phát triển, kiểm thử và vận hành chính thức. Nhờ đó, nhóm phát triển có thể kiểm tra chức năng mới mà hạn chế ảnh hưởng đến hệ thống đang được người dùng sử dụng.
Flutter Flavors hỗ trợ tạo nhiều biến thể ứng dụng từ cùng một codebase. Mỗi biến thể có thể có tên, biểu tượng, định danh ứng dụng và những cấu hình riêng.
Trong thực tế, Flavors thường được kết hợp với --dart-define, cấu hình API Base URL, Firebase và CI/CD để xây dựng quy trình phát triển rõ ràng hơn.
Điều quan trọng là phải phân biệt Flavor, Environment và Build Mode, vì đây là ba khái niệm có mục đích khác nhau.
Khi hiểu và áp dụng đúng, Flutter Flavors & Multiple Environments giúp dự án dễ quản lý, dễ kiểm thử, thuận tiện khi triển khai và giảm nguy cơ sử dụng nhầm cấu hình giữa môi trường phát triển và môi trường chính thức.
21. Tài liệu tham khảo
- Flutter – Set up Flavors for Android: https://docs.flutter.dev/deployment/flavors
- Flutter – Set up Flavors for iOS: https://docs.flutter.dev/deployment/flavors-ios
- Dart – Configuration using environment declarations: https://dart.dev/libraries/core/environment-declarations
- FlutterFire CLI: https://firebase.google.com/docs/flutter/setup
- Flutter – Build and Release an Android App: https://docs.flutter.dev/deployment/android








Khoá học lập trình game con rắn cho trẻ em




