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

Bài đăng

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

Privacy manifests and required reason APIs for Flutter plugins — hướng dẫn Flutter

Apple requires declared reasons for certain APIs. Plugins must ship manifests. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi What App Store privacy nutrition labels mean for plugin authors. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Audit transitive plugins before submission, not after rejection. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về ...

UIScene lifecycle: the iOS 27 launch gate for Flutter apps

Apple’s scene-based lifecycle is mandatory for apps built with the latest SDKs. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Xcode 27 fails launches without UIScene. What Flutter migrates automatically. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Flutter CLI migrates typical AppDelegate setups; custom hooks need a manual pass. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, ...

TestFlight internal vs external testing that finds real bugs

External testers find environment bugs internal teams never see. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Groups, feedback, and build expiry planning. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Keep a always-green internal build for demos. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent and calls the boun...

Swift Package Manager plugin migration checklist for Flutter

CocoaPods is maintenance mode. Flutter 3.44+ resolves iOS/macOS deps with SwiftPM by default. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence What iOS/macOS plugin authors must ship after SwiftPM became the default. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Unmigrated plugins score lower on pub.dev and will eventually stop resolving. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, su...

The April 2027 SDK deadline for App Store uploads — hướng dẫn Flutter

Stores will reject older SDK builds. Upgrade before the crunch. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Why you should upgrade Xcode and Flutter toolchains now. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Test UIScene, privacy manifests, and SwiftPM early. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, k...

The April 2027 SDK deadline for App Store uploads

Stores will reject older SDK builds. Upgrade before the crunch. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Why you should upgrade Xcode and Flutter toolchains now. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Test UIScene, privacy manifests, and SwiftPM early. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent a...

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' , ...

Privacy manifests and required reason APIs for Flutter plugins

Apple requires declared reasons for certain APIs. Plugins must ship manifests. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence What App Store privacy nutrition labels mean for plugin authors. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Audit transitive plugins before submission, not after rejection. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controlle...

Flutter and iOS app extensions without a second UI stack — hướng dẫn Flutter

Extensions must stay tiny. Share logic via app groups and files. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Share extensions, widgets, and shared app groups. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Do not embed a full Flutter engine in a Today widget. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không...

App Clips and Instant Apps with Flutter modules — hướng dẫn Flutter

Instant experiences convert. They also have brutal size budgets. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Size limits, invocation URLs, and handoff to full apps. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Design a one-URL task for the clip path. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không trả st...

Flutter and iOS app extensions without a second UI stack

Extensions must stay tiny. Share logic via app groups and files. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Share extensions, widgets, and shared app groups. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Do not embed a full Flutter engine in a Today widget. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent and c...

App Clips and Instant Apps with Flutter modules

Instant experiences convert. They also have brutal size budgets. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Size limits, invocation URLs, and handoff to full apps. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Design a one-URL task for the clip path. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent and calls th...

Chạy nền trong Flutter: hệ điều hành thật sự cho phép bạn chạy gì

“Đồng bộ dữ liệu người dùng mười lăm phút một lần” nghe như bài toán lập lịch. Thực ra đó là cuộc thương lượng với hai hệ điều hành đã dành cả thập kỷ để giỏi hơn trong việc nói không. Trước khi chọn gói, đáng để nói chính xác từng nền tảng thật sự cho gì, vì khoảng cách giữa chúng quyết định tính năng của bạn được phép hứa điều gì. Bạn thật sự được phép làm gì Khả năng Android iOS Chạy nền định kỳ Có, tối thiểu ~15 phút, còn tuỳ Doze BGAppRefreshTask — hệ thống quyết định khi nào, có thể là không bao giờ Việc hoãn lại chạy một lần Có, kèm ràng buộc BGProcessingTask , thường vào ban đêm khi đang sạc Bảo đảm chạy khi ứng dụng đã đóng Chỉ qua foreground service kèm thông báo nhìn thấy được Không Việc chạy dài (nhiều phút) Foreground service Không — tác vụ nền có vài giây rồi bị đình chỉ Kích hoạt từ máy chủ Có, FCM mức ưu tiên cao Hạn chế; push ngầm bị bóp Dòng làm thay đổi thiết kế là dòng thứ ba. Trên iOS không có cách nào bảo đảm mã của bạn chạy...

The April 2027 SDK deadline for App Store uploads — hướng dẫn Flutter

Stores will reject older SDK builds. Upgrade before the crunch. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Why you should upgrade Xcode and Flutter toolchains now. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Test UIScene, privacy manifests, and SwiftPM early. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, k...

Flutter and iOS app extensions without a second UI stack — hướng dẫn Flutter

Extensions must stay tiny. Share logic via app groups and files. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Share extensions, widgets, and shared app groups. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Do not embed a full Flutter engine in a Today widget. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không...

App Clips and Instant Apps with Flutter modules — hướng dẫn Flutter

Instant experiences convert. They also have brutal size budgets. Bài này chuyển quan sát đó thành một mô hình nhỏ để bạn có thể kiểm thử, đo lường và giữ cho code dễ bảo trì khi app lớn lên. Vấn đề cốt lõi Size limits, invocation URLs, and handoff to full apps. Câu hỏi hữu ích không phải API hay pattern có đẹp riêng lẻ hay không, mà là state nằm ở đâu, boundary nào chịu trách nhiệm khi lỗi xảy ra, và người dùng phục hồi thế nào khi happy path biến mất. Mô hình thực tế Design a one-URL task for the clip path. Hãy bắt đầu bằng một owner rõ ràng cho behavior. Widget chỉ nên render và phát intent; IO, persistence, permission và retry nên nằm sau một interface nhỏ. Nhờ vậy bạn có seam để fake trong test và một chỗ ghi lại các dữ kiện cần theo dõi ở production. Trong app Flutter, boundary thường có dạng: Widget phát intent như load, submit, refresh hoặc retry. Controller hoặc use case validate intent rồi gọi boundary. Boundary trả về data có kiểu hoặc failure có kiểu, không trả st...

The April 2027 SDK deadline for App Store uploads

Stores will reject older SDK builds. Upgrade before the crunch. This article turns that observation into a small implementation model you can test, measure, and keep boring when the app grows. The problem in one sentence Why you should upgrade Xcode and Flutter toolchains now. The useful question is not whether the API or pattern looks elegant in isolation. It is where state lives, which boundary owns failure, and how a user recovers when the happy path disappears. A practical model Test UIScene, privacy manifests, and SwiftPM early. Start with one explicit owner for the behavior. Keep widgets responsible for rendering and user intent; keep IO, persistence, permissions, and retries behind a small interface. That gives you a seam for a fake in tests and a place to record the facts that matter in production. For a Flutter app, the boundary usually looks like this: The widget emits an intent such as load, submit, refresh, or retry. A controller or use case validates the intent a...