Chuyển đến nội dung chính

Bài đăng

Hiển thị các bài đăng có nhãn Build

Flavor trong Flutter: một codebase, ba ứng dụng, không copy-paste cấu hình

Phiên bản tệ của việc xử lý môi trường trông như thế này: const bool isProd = false ; final apiBase = isProd ? 'https://api.example.com' : 'https://staging.api.example.com' ; Nó chạy được cho tới khi ai đó phát hành với cờ bật sai chiều, hoặc tới khi QA cần cài song song staging và production rồi phát hiện cả hai có cùng bundle id. Flavor giải quyết cả hai vấn đề ở tầng build: ba ứng dụng cài được riêng biệt, mỗi cái được biên dịch kèm cấu hình của chính nó. Phía Dart trước đã Bắt đầu từ đây vì đây là phần quyết định mọi thứ còn lại. // lib/config/app_config.dart enum Flavor { dev, staging, prod } final class AppConfig { const AppConfig ._({ required this .flavor, required this .apiBase, required this .appName, }); final Flavor flavor; final String apiBase; final String appName; static const _flavorName = String . fromEnvironment ( 'FLAVOR' , defaultValue : 'dev' , ...

Thu nhỏ ứng dụng Flutter: megabyte thật sự nằm ở đâu

Câu chuyện về kích thước ứng dụng thường bắt đầu sau khi một người có tiếng nói so sánh file APK với đối thủ và hỏi vì sao một app ghi chú việc cần làm lại nặng 40 MB. Phản ứng của đội kỹ thuật thường là bắt đầu xoá package — vốn vừa là cần gạt đau đớn nhất, vừa thường không phải cần gạt quan trọng. Ứng dụng Flutter có một sàn kích thước: engine, runtime Dart, Skia hoặc Impeller, và dữ liệu ICU. Cái sàn đó là thật và bạn không gỡ được. Mọi thứ nằm trên nó là của bạn, và trong hầu hết ứng dụng tôi từng xem, phần lớn cái “của bạn” đó là asset và mã native được đóng gói nhưng không dùng, chứ không phải Dart. Nên nước đi đầu tiên không phải là xoá gì cả. Mà là đo. Đo trước: --analyze-size flutter build apk --release --analyze-size flutter build appbundle --release --analyze-size flutter build ipa --release --analyze-size Lệnh này in ra một bản tóm tắt và ghi một file JSON. Hãy mở file đó bằng công cụ app size trong DevTools — nó cho bạn một treemap với các ô tỉ lệ theo s...

Sinh mã trong Dart: build_runner mà không bực mình

Bạn thêm json_serializable , chạy dart run build_runner build , và nhận được: Conflicting outputs were detected and the build will be terminated. Bạn chạy lại với --delete-conflicting-outputs , nó chạy được, và từ đó bạn gõ cờ này mãi mãi mà không biết nó đã xoá gì. Đó là mối quan hệ điển hình giữa lập trình viên và build_runner, và nó đáng được sửa, vì công cụ này dễ đoán hơn vẻ ngoài của nó. Mô hình: một asset vào, một asset ra build_runner không phải bộ chạy script. Nó là một hệ thống build trên asset — những file được định danh theo dạng package:name|path . Mỗi builder khai báo nó tiêu thụ phần mở rộng nào và sinh ra phần mở rộng nào, và build_runner dựng một đồ thị từ đó. json_serializable nói: với mỗi .dart , có thể sinh ra một .g.dart . freezed nói: với mỗi .dart , có thể sinh ra một .freezed.dart . Vì đầu ra được đánh khoá theo đường dẫn, hai builder cùng nhận một đường dẫn đầu ra sẽ xung đột — và một builder cũng xung đột với chính đầu ra cũ của nó còn nằm trên đĩa từ...

Flavor trong Flutter: một codebase, ba ứng dụng, không copy-paste cấu hình

Phiên bản tệ của việc xử lý môi trường trông như thế này: const bool isProd = false ; final apiBase = isProd ? 'https://api.example.com' : 'https://staging.api.example.com' ; Nó chạy được cho tới khi ai đó phát hành với cờ bật sai chiều, hoặc tới khi QA cần cài song song staging và production rồi phát hiện cả hai có cùng bundle id. Flavor giải quyết cả hai vấn đề ở tầng build: ba ứng dụng cài được riêng biệt, mỗi cái được biên dịch kèm cấu hình của chính nó. Phía Dart trước đã Bắt đầu từ đây vì đây là phần quyết định mọi thứ còn lại. // lib/config/app_config.dart enum Flavor { dev, staging, prod } final class AppConfig { const AppConfig ._({ required this .flavor, required this .apiBase, required this .appName, }); final Flavor flavor; final String apiBase; final String appName; static const _flavorName = String . fromEnvironment ( 'FLAVOR' , defaultValue : 'dev' , ...

Flutter flavors: one codebase, three apps, zero copy-pasted config

The bad version of environment handling looks like this: const bool isProd = false ; final apiBase = isProd ? 'https://api.example.com' : 'https://staging.api.example.com' ; It works until someone ships with the flag flipped the wrong way, or until QA needs staging and production installed side by side and discovers both have the same bundle id. Flavors fix both problems at the build layer: three separate installable apps, each compiled with its own configuration baked in. The Dart side, first Start here because it is the part that determines everything else. // lib/config/app_config.dart enum Flavor { dev, staging, prod } final class AppConfig { const AppConfig ._({ required this .flavor, required this .apiBase, required this .appName, }); final Flavor flavor; final String apiBase; final String appName; static const _flavorName = String . fromEnvironment ( 'FLAVOR' , defaul...