FlutterKit Ships a GetX Scaffold With 98% Test Coverage and AI-Ready Structure
Out-of-the-box Flutter Universal Scaffold — FlutterKit
In an era where AI-assisted development is becoming routine, a scaffold must not only reduce repetitive work but also allow AI to understand the project structure, follow development conventions, and complete development within clear architectural boundaries.
Previously, I shared rapid development frameworks for HarmonyOS and Android. This time, I'm bringing the Flutter version. FlutterKit is based on Flutter + Dart + GetX + TDesign Flutter, with built-in capabilities for networking, pagination, database, state management, navigation, screen adaptation, and more. It supports dark mode, internationalization, and multi-device adaptation. Welcome to learn and exchange ideas together.
The project also provides a project-level AGENTS.md and specialized Skills covering UI, data, navigation, theming, previews, and other scenarios, helping AI participate in feature development, code refactoring, unit testing, and documentation maintenance.
Project Highlights
- Out-of-the-box: Built-in networking, pagination, database, state management, and other basic capabilities, eliminating the need for repeated setup.
- Complete Examples: Every functional module provides runnable Demo pages, making it easy to directly view effects and code.
- Quality Assurance: Both Core and Demo modules come with unit tests, with line coverage no less than 98% and branch coverage no less than 95%.
- Modular Architecture: Responsibilities are divided using bootstrap, core, routes, and feature, keeping business modules isolated from each other.
- Modern Tech Stack: Flutter + Dart + GetX + TDesign Flutter, supporting Android, iOS, Web, and desktop.
- Screen Adaptation: Supports phones, foldables, tablets, and landscape/portrait layout switching.
- Dark Mode: Supports light, dark, and follow-system themes, with persistent user selection.
- Internationalization Support: Built-in Chinese/English language switching, with Core and Feature strings maintained per module.
- Online Documentation: Framework documentation is maintained in sync with the code, facilitating learning, reference, and secondary development.
- AI-Assisted Development: Provides a project-level
AGENTS.mdand specialized Skills to help AI tools understand framework boundaries.
If this project helps you, please give a Star to support it ⭐ It's very important to me and provides the motivation for long-term updates and maintenance!
Project Address: GitHub | Gitee
Online Documentation: https://flutter.dusksnow.top
Demo Download: https://www.pgyer.com/FlutterKit
Project Preview
💡 Note: The framework provides various example pages demonstrating networking, pagination, database, theming, navigation, state management, and other capabilities, supporting device forms such as phones, foldables, and tablets.
📱 Phone
📱 Tablet
Architecture Design
FlutterKit adopts a modular layered architecture, divided from top to bottom into the business layer, core layer, and entry layer:
Business Layer (Feature)
- Functional Modules: Split by business domain, currently including authentication, user, home, and demo modules.
- Page Layering: Page code is organized using View + Logic + State + Binding.
- Module Components: Widgets, data, and services reused within a single module remain inside the Feature.
- Internationalization Resources: Each Feature independently maintains text keys and Chinese/English translations.
Core Layer (Core)
- base: Base parent classes and page state encapsulation (BaseLogic, BaseNetworkLogic, BaseListLogic, BaseRefreshLogic, BaseTabLogic).
- data: Unified data entry point, holding Repository and static Preview Data.
- database: Local database capabilities based on sqflite.
- datastore: Lightweight local storage based on shared_preferences.
- design_system: Theme, colors, spacing, fonts, shapes, shadows, and Widget chain extensions.
- localization: Core public strings and translation aggregation.
- model: Request models, response models, pagination models, and business entities.
- network: Dio, Retrofit, interceptors, DataSource, and Debug network panel.
- result: RequestHelper, unified error formatting, and request result handling.
- service: User state, login state, and cross-page shared Services.
- ui: Common UI components, responsive breakpoints, and Widget Preview.
- util: Storage, Route, Toast, Alert, Size, Common, and other utilities.
Entry Layer (Application)
- Application Entry: Responsible for Flutter application startup and
GetMaterialAppconstruction. - Startup Initialization: Unified initialization of storage, theme, language, Services, and network debugging tools.
- Route Registration: Aggregates GetPage, Binding, parameters, results, and route guards for each module.
- Multi-platform Configuration: Maintains native projects for Android, iOS, Web, macOS, Linux, and Windows.
Dependency Rules
- feature depends on core: Business modules can use the public capabilities provided by Core.
- feature does not directly depend on network / database: Business modules access underlying data through Repository.
- routes handles module navigation: Features do not directly import each other's page implementations.
- core does not depend on feature: Public capabilities cannot reverse-reference specific business modules.
Tech Stack
| Category | Technology Selection | Description |
|---|---|---|
| Language | Dart | Flutter's official development language |
| UI Framework | Flutter + TDesign Flutter | Cross-platform UI and business components |
| Architecture | View + Logic + State + Binding | Page layering and dependency registration |
| State & Nav | GetX | Rx, Obx, GetPage, Binding, Service |
| Networking | Dio + Retrofit | HTTP client, interceptors, and interface declarations |
| Data Storage | sqflite + shared_preferences | Database and lightweight local storage |
| Screen Adapter | flutter_screenutil + BreakpointType | Size adaptation and responsive breakpoints |
Core Capabilities
1. Network Request Encapsulation
Network request encapsulation based on Dio + Retrofit, adopting a DataSource → Repository → Logic three-layer architecture. The framework uniformly handles errors, loading, toasts, dialogs, and page states.
Features:
- Unified management of Dio instances, baseUrl, timeout, and headers.
- Use Retrofit to declare type-safe network DataSources.
- Automatic handling of HTTP status codes and business error codes.
- Supports RequestHelper chain configuration for loading, toast, dialog, and error callbacks.
- Supports BaseNetwork automatic management of loading, error, empty data, and success states.
- Debug mode provides an Alice network request panel and PrettyDioLogger logs.
Usage Example:
/// Request product details.
Future<void> requestGoodsDetail() {
return RequestHelper.repository<Goods>(
GoodsRepository().getGoodsInfo(1),
)
.loading(true) // Show Loading during the request.
.toast(true) // Automatically show Toast on business failure.
.execute()
.then<void>((Goods? goods) {
LogUtil.d('Product details: ${goods?.title}');
})
.catchError((Object error) {
LogUtil.e(error.toString());
});
}
Single Request Scenario (automatically handles loading, error, empty data, and success states):
/// Network demo page State.
class NetworkDemoState extends BaseNetworkState {
/// Product details.
final Rx<Goods> goods = Goods().obs;
}
/// Network demo page Logic.
class NetworkDemoLogic extends BaseNetworkLogic<Goods> {
/// Page display state.
final NetworkDemoState networkDemoState = NetworkDemoState();
/// Product repository.
final GoodsRepository _goodsRepository = GoodsRepository();
/// Network parent class reuses the State declared by the page.
@override
NetworkDemoState get networkState => networkDemoState;
/// Product details request.
@override
Future<BaseResponse<Goods>> Function()? get apiRequest =>
() => _goodsRepository.getGoodsInfo(1);
/// Save product details.
@override
void requestOk(Goods data) => networkDemoState.goods.value = data;
}
/// Network demo page.
class NetworkDemoView extends BaseNetworkView<NetworkDemoLogic> {
/// Create network demo page.
NetworkDemoView({super.key, super.logic});
/// Build page content after a successful request.
@override
Widget bodyContent(NetworkDemoLogic logic) {
return Obx(
() => GoodsDetailContent(
goods: logic.networkDemoState.goods.value,
),
);
}
}
BaseNetworkLogic calls apiRequest, and executes requestOk() after a successful request; BaseNetworkView displays Loading, error page, empty page, or business content based on the current state.
For specific implementation code, please refer to: Network Request Documentation | Result Handling Documentation
2. Paginated List Encapsulation
Unified encapsulation of initial loading, pull-to-refresh, load-more, empty state, error handling, and no-more-data for paginated lists. Developers only need to care about request parameters and list item rendering.
Features:
- Automatically handles four states: loading, success, failure, and empty data.
- Automatically handles pull-to-refresh and load-more.
- Automatically manages
currentPage,pageSize, and pagination request parameters. - Automatically determines if there is more data.
- Automatically restores to the last successful page on load-more failure.
- When the next page returns an empty list, existing content is retained and marked as no more data.
- Supports custom loading, error, empty state, and list item Widgets.
Logic Implementation:
/// Network list demo page State.
class NetworkListDemoState extends BaseListState<Goods> {
/// Number of products per page.
@override
int get pageSize => 15;
}
/// Network list demo page Logic.
class NetworkListDemoLogic extends BaseListLogic<Goods> {
/// Create network list demo page Logic.
///
/// [goodsRepository] Optional product repository, can inject Fake implementation for testing and previews.
NetworkListDemoLogic({GoodsRepository? goodsRepository})
: _goodsRepository = goodsRepository ?? GoodsRepository();
/// Page pagination state.
final NetworkListDemoState networkListDemoState = NetworkListDemoState();
/// Pagination parent class reuses the State declared by the page.
@override
NetworkListDemoState get listState => networkListDemoState;
/// Product repository.
final GoodsRepository _goodsRepository;
/// Product pagination request.
@override
Future<BaseResponse<BaseListResponse<Goods>>> Function()? get apiRequest {
return () => _goodsRepository.getGoodsPage(
GoodsSearchRequest(
page: listState.currentPage,
size: listState.pageSize,
),
);
}
}
Page Usage:
/// Network list demo page.
class NetworkListDemoView
extends BaseListView<NetworkListDemoLogic, Goods> {
/// Create network list demo page.
NetworkListDemoView({super.key, super.logic});
/// Build product list item.
///
/// [item] Current product.
/// [index] Current index.
@override
Widget itemWidget(Goods item, int index) {
return GoodsListCard(goods: item);
}
}
Usage Steps:
- State inherits
BaseListState<T>, optionally overridepageSize. - Logic inherits
BaseListLogic<T>and implementsapiRequest. - View inherits
BaseListView<Logic, T>and implementsitemWidget. - Parent class uniformly manages EasyRefresh, page number, list state, and no-more-data.
For specific implementation code, please refer to: Paginated List Documentation
3. State Management
Implements page state and global state sharing based on GetX's Rx, Obx, and GetxService.
Features:
- Type-safe reactive state definition.
Obxautomatically listens to Rx changes and updates Widgets.- Page state is managed by Feature State.
- Cross-page state is managed using GetxService.
- Theme, language, and user state support persistent restoration.
- Binding uniformly registers page Logic, avoiding controller creation in Views.
State Definition:
/// Demo counter service.
class DemoCounterService extends GetxService {
/// Current count value.
final RxInt count = 0.obs;
/// Increment count by one.
void increase() {
count.value += 1;
}
}
Usage Example:
/// Build state management example.
Widget buildCounter() {
final DemoCounterService service = Get.find<DemoCounterService>();
return Obx(() {
return Column(
children: <Widget>[
TDText('Current count: ${service.count.value}'),
TDButton(text: 'Increase', onTap: service.increase),
],
);
});
}
Temporary page state goes in State, cross-page state goes in Service, and application-level state like theme and language goes in Application. It is not recommended to put all Rx into global Services.
For specific implementation code, please refer to: State Management Documentation
4. Navigation Management
Unified management of route registration, page navigation, parameter passing, result return, and login interception.
Features:
- Type-safe route parameters and return results.
- Modular route registration (Routes + Pages).
- Unified module Navigator.
- Supports navigation with arguments and result return.
- Supports login interception and GetMiddleware route guards.
- Android uses platform-native transitions and supports predictive back.
Route Definition:
/// Demo module routes.
abstract final class DemoRoutes {
static const String navigationWithArgs = '/demo/navigation-with-args';
static const String navigationResult = '/demo/navigation-result';
}
/// Demo module navigation parameters.
class DemoParams {
const DemoParams({required this.goodsId});
final int goodsId;
}
/// Demo module navigation results.
class DemoResult {
const DemoResult({required this.id, required this.message});
final int id;
final String message;
}
Navigator Encapsulation (Recommended):
/// Demo module navigator.
abstract final class DemoNavigator {
/// Navigate to the navigation-with-args demo page.
static Future<T?>? toNavigationWithArgs<T>(int goodsId) {
return toPage<T>(
DemoRoutes.navigationWithArgs,
arguments: DemoParams(goodsId: goodsId),
);
}
/// Navigate to the result-return demo page.
static Future<DemoResult?>? toNavigationResult() {
return toPage<DemoResult>(DemoRoutes.navigationResult);
}
}
Usage Example:
/// Open page with arguments.
Future<void> openGoodsPage() async {
await DemoNavigator.toNavigationWithArgs<void>(10086);
}
/// Open result-return page.
Future<void> openResultPage() async {
final DemoResult? result = await DemoNavigator.toNavigationResult();
if (result != null) {
ToastUtil.success(result.message);
}
}
/// Read current page parameters.
class NavigationWithArgsLogic extends BaseLogic {
late final DemoParams params = args as DemoParams;
}
/// Return page result.
void submitResult() {
back<DemoResult>(const DemoResult(id: 1, message: 'Operation successful'));
}
The application root node uses Transition.native, and Android Manifest explicitly enables android:enableOnBackInvokedCallback="true", allowing Android 14+ pages to access predictive back.
For specific implementation code, please refer to: Navigation Management Documentation
5. Screen Adaptation
A complete screen adaptation solution supporting phones, foldables, tablets, and landscape/portrait layouts.
Features:
- XS / SM / MD / LG four responsive breakpoints.
BuildContext.bp()responsive value retrieval.BreakpointType.bp()supports LayoutBuilder local constraints.- flutter_screenutil provides basic size adaptation.
- SafeArea and MediaQuery handle notches, punch-holes, and gesture areas.
- Main page switches between bottom navigation and side navigation based on landscape/portrait orientation.
- Widget Preview checks multiple device sizes simultaneously.
Breakpoint Rules:
| Breakpoint | Description | Width Range (dp) |
|---|---|---|
XS |
Extra Small | < 320 |
SM |
Small | 320 - 599 |
MD |
Medium | 600 - 839 |
LG |
Large | >= 840 |
Grid Layout Adaptation:
/// Build responsive product grid.
Widget buildGoodsGrid(BuildContext context, List<Goods> goods) {
final int columns = context.bp<int>(xs: 2, sm: 2, md: 3, lg: 4);
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: goods.length,
itemBuilder: (BuildContext context, int index) {
return GoodsListCard(goods: goods[index]);
},
);
}
Text Adaptation:
/// Build responsive text.
Widget buildAdaptiveText(BuildContext context) {
final double fontSize = context.bp<double>(
xs: 14,
sm: 14,
md: 16,
lg: 22,
);
return Text(
'Large screen adaptive sample text',
style: TextStyle(fontSize: fontSize),
);
}
Navigation Bar Position Adjustment:
/// Switch navigation position based on screen orientation.
Widget buildMainLayout(
BuildContext context,
Widget page,
Widget sideNavigation,
) {
final bool isLandscape =
MediaQuery.orientationOf(context) == Orientation.landscape;
if (isLandscape) {
return Row(
children: <Widget>[
sideNavigation,
Expanded(child: page),
],
);
}
return page;
}
Safe Area Adaptation:
Normal pages avoid the status bar via BaseView.head()'s AppBar; bottom action areas use SafeArea(top: false) to avoid system gesture areas.
/// Build page bottom action button.
///
/// [onSubmit] Submit callback.
Widget buildBottomAction(VoidCallback onSubmit) {
return SafeArea(
top: false,
child: TDButton(text: 'Submit', onTap: onSubmit),
);
}
For specific implementation code, please refer to: Screen Adaptation Documentation | Safe Area Documentation
6. Database Encapsulation
Local database capabilities based on sqflite, adopting a DataSource → Repository architecture. The business layer accesses the database through Repository.
Entity Definition (Simplified Example):
/// Demo table entity.
class DemoEntity {
const DemoEntity({
this.id,
this.title = '',
this.description,
});
final int? id;
final String title;
final String? description;
/// Convert to database field Map.
Map<String, dynamic> toMap({bool includeId = true}) {
return <String, dynamic>{
if (includeId) 'id': id,
'title': title,
'description': description,
};
}
}
Usage Example:
/// Database demo page Logic.
class DatabaseDemoLogic extends BaseLogic {
/// Demo data repository.
final DemoRepository _demoRepository = DemoRepository();
/// Demo record list.
final RxList<DemoEntity> items = <DemoEntity>[].obs;
/// Save record.
Future<void> save() async {
await _demoRepository.createDemo('Sample Title', description: 'Sample Description');
items.value = await _demoRepository.getAll();
}
}
DatabaseProvider uniformly manages database connections, concurrent first-open, table creation, and closing. DataSource is responsible for SQL, table names, and field mapping. Features do not directly hold Database.
For specific implementation code, please refer to: Database Documentation
7. Local Storage
Lightweight local storage based on shared_preferences, adopting a DataSource → Repository architecture. The business layer accesses tokens, themes, languages, and user caches through Repository.
Usage Example:
/// Local storage demo page Logic.
class LocalStorageDemoLogic extends BaseLogic {
/// User info storage repository.
final UserInfoStoreRepository _userInfoStoreRepository =
UserInfoStoreRepository();
/// Current user info.
final Rxn<User> user = Rxn<User>();
/// Save user info.
Future<void> saveUser() async {
const User demoUser = User(
id: 10086,
nickName: 'Demo User',
phone: '18800000000',
);
await _userInfoStoreRepository.saveUserInfo(demoUser);
user.value = await _userInfoStoreRepository.getUserInfo();
}
/// Clear user info.
Future<void> clearUser() async {
await _userInfoStoreRepository.clearUserInfo();
user.value = null;
}
}
Storage keys, default values, and JSON conversion are all kept within the DataSource implementation. Corrupted user JSON is treated as no cache, preventing parse exceptions from being thrown directly to the page.
For specific implementation code, please refer to: Local Storage Documentation
Utility Classes
The framework includes common utilities to avoid repetitive implementation in the business layer:
- ToastUtil: Normal, success, warning, and error Toasts.
- AlertUtil: Confirmation, feedback, and business prompt dialogs.
- RouteUtil: Page navigation, return, parameter reading, and navigation stack handling.
- StorageUtil: Basic SharedPreferences read/write.
- CommonUtil: Copy, vibration, platform detection, and general checks.
For specific usage methods, please refer to: Utility Class Documentation
Project Structure
FlutterKit/
├── android / ios / web / ... # Six-platform native projects
├── assets/ # Images, icons, theme JSON, and generated source images
├── docs/ # FlutterKit and TDesign local documentation
├── lib/
│ ├── bootstrap/ # Startup initializer
│ ├── core/ # Core module
│ │ ├── base/ # Base parent classes
│ │ ├── data/ # Repository and Preview Data
│ │ ├── database/ # Database
│ │ ├── datastore/ # Local storage
│ │ ├── design_system/ # Design system and chain extensions
│ │ ├── model/ # Data models
│ │ ├── network/ # Network layer
│ │ ├── result/ # Result handling
│ │ ├── service/ # Global Services
│ │ └── ui / util / ... # UI, responsive, and utility classes
│ ├── feature/ # Functional modules
│ │ ├── auth/ # Authentication module
│ │ ├── demo/ # Demo module
│ │ ├── main/ # Main module
│ │ └── user/ # User module
│ ├── routes/ # Routes, parameters, results, and guards
│ ├── application.dart # Initialization orchestration and app-level state
│ └── main.dart # Flutter application entry point
├── test/ # Unit tests and Widget tests
└── tool/ # Scripts like coverage checks
Related Resources:
- Online Documentation: https://flutter.dusksnow.top
- TDesign Flutter: https://tdesign.tencent.com/flutter/getting-started
- Demo Download: https://www.pgyer.com/FlutterKit
- DeepWiki: https://deepwiki.com/Joker-x-dev/FlutterKit
If this project helps you, please give a ⭐ Star to support it!
Top 3 of 4 from juejin.cn, machine-translated. The original thread is authoritative.
Bookmarking this.
[heart]
Impressive, big shot. It'd be even better if you swapped out GetX.
Not bad, pretty good.