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

Bài đăng

Pigeon: platform channel có kiểu sinh từ một schema

Pigeon: platform channel có kiểu sinh từ một schema pigeon đáng chú ý vì nó giải quyết codegen Dart/native, contract API, task queue và versioning. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu @HostApi () abstract class SecureBiometrics { bool isAvailable (); @async bool authenticate ( String reason); } // dart run pigeon --input pigeons/biometrics.dart Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về background. Kiểm tra Android, iOS, web hoặc desktop đúng platform mà app hỗ trợ. Ghi lại owner, upgrade...
Các bài đăng gần đây

permission_handler: luồng xin quyền runtime có thể giải thích

permission_handler: luồng xin quyền runtime có thể giải thích permission_handler đáng chú ý vì nó giải quyết status, rationale, mở settings fallback và khai báo platform. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu final status = await Permission .camera. request (); if (status.isGranted) { openCamera (); } else if (status.isPermanentlyDenied) { await openAppSettings (); } Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về background. Kiểm tra Android, iOS, web hoặc desktop đúng platform mà app hỗ trợ. Ghi ...

Patrol: integration test có thể đi ra ngoài sandbox Flutter

Patrol: integration test có thể đi ra ngoài sandbox Flutter patrol đáng chú ý vì nó giải quyết permission native, notification, deep link và tự động hóa thiết bị. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu patrolTest ( 'camera permission flow' , ($) async { await $. native . grantPermissionWhenInUse (); await $. pumpWidgetAndSettle ( const CameraApp ()); await $(#takePhoto). tap (); expect (find. byType ( PhotoPreview ), findsOneWidget); }); Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về backgr...

Pigeon: typed platform channels generated from one schema

Pigeon: typed platform channels generated from one schema pigeon is useful because it focuses on Dart/native codegen, API contracts, task queues, and versioning. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point @HostApi () abstract class SecureBiometrics { bool isAvailable (); @async bool authenticate ( String reason); } // dart run pigeon --input pigeons/biometrics.dart Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify every platform your product suppo...

permission_handler: runtime permission flows you can explain

permission_handler: runtime permission flows you can explain permission_handler is useful because it focuses on status, rationale, settings fallback, and platform declarations. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final status = await Permission .camera. request (); if (status.isGranted) { openCamera (); } else if (status.isPermanentlyDenied) { await openAppSettings (); } Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify every platform your pro...

Patrol: integration tests that can leave the Flutter sandbox

Patrol: integration tests that can leave the Flutter sandbox patrol is useful because it focuses on native permissions, notifications, deep links, and device automation. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point patrolTest ( 'camera permission flow' , ($) async { await $. native . grantPermissionWhenInUse (); await $. pumpWidgetAndSettle ( const CameraApp ()); await $(#takePhoto). tap (); expect (find. byType ( PhotoPreview ), findsOneWidget); }); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle...

Mocktail: mock Dart dễ đọc mà không cần file generated

Mocktail: mock Dart dễ đọc mà không cần file generated mocktail đáng chú ý vì nó giải quyết fake, stub, verify, fallback value và ranh giới test. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu class MockUserApi extends Mock implements UserApi {} final api = MockUserApi (); when (() => api. fetchUser ( '42' )). thenAnswer ((_) async => user); final result = await repository. load ( '42' ); verify (() => api. fetchUser ( '42' )). called ( 1 ); Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hà...

Melos: biến Flutter monorepo thành ranh giới sản phẩm

Melos: biến Flutter monorepo thành ranh giới sản phẩm melos đáng chú ý vì nó giải quyết script workspace, package graph, test chọn lọc và release. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu name : flutter_workspace packages : - apps /** - packages/** scripts: analyze: melos exec -- flutter analyze test: melos exec --fail-fast -- flutter test changed: melos exec --since=main -- flutter test Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về background. Kiểm tra Android, iOS, web hoặc desktop đúng platfor...

Lotti: journal với audio, habit và local DB nghiêm túc

Tutorial Flutter hay dừng ở CRUD. Lotti thú vị vì journaling buộc entry đa modal (text, audio, habit, đo lường) và lưu trữ local dài hạn. Bài học Kiểu entry phân cấp thắng một row nullable khổng lồ. Capture + playback audio là surface platform, không phải widget. Insight cần index — thiết kế query trước chart. Cạm bẫy Migration trên dữ liệu cá nhân là thiêng; viết cẩn thận. Quyền ghi âm nền khác nhau theo OS. Nhìn Lotti khi “app note đơn giản” của bạn hết đơn giản. Bài viết gốc đăng tại FlutterCook . Bản trên đó là bản được cập nhật mới nhất.

Mocktail: readable Dart mocks without generated files

Mocktail: readable Dart mocks without generated files mocktail is useful because it focuses on fakes, stubbing, verification, fallback values, and test boundaries. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point class MockUserApi extends Mock implements UserApi {} final api = MockUserApi (); when (() => api. fetchUser ( '42' )). thenAnswer ((_) async => user); final result = await repository. load ( '42' ); verify (() => api. fetchUser ( '42' )). called ( 1 ); Production checklist Read the README and changelog for the exact version yo...

Melos: make a Flutter monorepo a product boundary

Melos: make a Flutter monorepo a product boundary melos is useful because it focuses on workspace scripts, package graph, selective tests, and releases. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point name : flutter_workspace packages : - apps /** - packages/** scripts: analyze: melos exec -- flutter analyze test: melos exec --fail-fast -- flutter test changed: melos exec --since=main -- flutter test Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify e...

Lotti: journaling with audio, habits, and a serious local DB

Most Flutter tutorials stop at CRUD. Lotti is interesting because journaling forces multi-modal entries (text, audio, habits, measurements) and long-term local storage. Lessons Entry type hierarchies beat one giant nullable row. Audio capture + playback is a platform surface, not a widget. Insights need indexes — design queries before charts. Pitfalls Migrations on personal data are sacred; write them carefully. Background recording permissions vary by OS. Look at Lotti when your “simple notes app” is no longer simple. Originally published on FlutterCook . Read the latest version there — that copy is the one kept up to date.

LocalSend: truyền file kiểu AirDrop không cần cloud

LocalSend hỏi một câu sản phẩm sắc: hai thiết bị đổi file không cần tài khoản server được không? Có — nếu bạn thiết kế discovery LAN, HTTPS và consent rõ ràng. Điểm thiết kế Peer protocol trên HTTPS cục bộ (thường gắn với cổng 53317 ). UI Flutter với phần Rust/native cho đường nhạy hiệu năng. Không có control plane cloud — privacy là feature. Học theo Discovery + consent UX là nửa sản phẩm. Transfer phải resume được và hiện rõ; lỗi im lặng phá niềm tin. Giữ CLI headless cho power user và automation. Cạm bẫy Giới hạn background mobile giết transfer dài ngây thơ. Mạng hỗn hợp (AP isolation, VPN, captive portal) sinh support load — hãy tài liệu hóa. Học LocalSend khi cần pattern local-first , không chỉ một package để copy. Bài viết gốc đăng tại FlutterCook . Bản trên đó là bản được cập nhật mới nhất.

local_auth: biometric là step-up, không phải nơi lưu password

local_auth: biometric là step-up, không phải nơi lưu password local_auth đáng chú ý vì nó giải quyết hỗ trợ thiết bị, prompt biometric, credential fallback và UX lỗi. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu final auth = LocalAuthentication (); final supported = await auth. isDeviceSupported (); if (supported) { final ok = await auth. authenticate ( localizedReason : 'Unlock your saved account' , options : const AuthenticationOptions (biometricOnly : false ), ); if (ok) unlock (); } Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. ...

just_audio: audio có thể điều khiển bằng stream

just_audio: audio có thể điều khiển bằng stream just_audio đáng chú ý vì nó giải quyết queue, stream position, playlist, tốc độ và tích hợp background. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu final player = AudioPlayer (); await player. setAudioSource ( ConcatenatingAudioSource (children : [ AudioSource . uri ( Uri . parse (trackUrl)), ]), ); player. play (); player.positionStream. listen (updateProgress); Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về background. Kiểm tra Android, iOS, web hoặc d...

LocalSend: AirDrop-style transfer with zero cloud

LocalSend answers a sharp product question: can two devices exchange files without an account or a server? Yes — if you design for LAN discovery, HTTPS, and explicit consent. Design highlights Peer protocol over local HTTPS (commonly associated with port 53317 ). Flutter UI with Rust/native pieces for performance-critical paths. No cloud control plane — privacy is the feature. Steal this Discovery + consent UX is half the product. Make transfers resumable and visible; silent failures destroy trust. Keep a CLI headless mode for power users and automation. Pitfalls Mobile OS background limits kill naive long transfers. Mixed networks (AP isolation, VPN, captive portals) will generate support load — document them. Study LocalSend when you need local-first product patterns, not just a package to copy. Originally published on FlutterCook . Read the latest version there — that copy is the one kept up to date.

local_auth: biometrics as a step-up, not a password store

local_auth: biometrics as a step-up, not a password store local_auth is useful because it focuses on device support, biometric prompts, fallback credentials, and failure UX. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final auth = LocalAuthentication (); final supported = await auth. isDeviceSupported (); if (supported) { final ok = await auth. authenticate ( localizedReason : 'Unlock your saved account' , options : const AuthenticationOptions (biometricOnly : false ), ); if (ok) unlock (); } Production checklist Read the README and change...

just_audio: controllable audio with streams

just_audio: controllable audio with streams just_audio is useful because it focuses on queues, position streams, playlists, speed, and background integration. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final player = AudioPlayer (); await player. setAudioSource ( ConcatenatingAudioSource (children : [ AudioSource . uri ( Uri . parse (trackUrl)), ]), ); player. play (); player.positionStream. listen (updateProgress); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground...