Flutter未定义功能插件nadarchitecture的潜在用途探索

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter未定义功能插件nadarchitecture的潜在用途探索

插件简介

nadarchitecture 是一个Flutter包,由Yusuf Nadaroglu开发,旨在为Flutter项目实现Clean Architecture(整洁架构)。该插件可以帮助开发者快速搭建符合Clean Architecture设计模式的项目结构,提高代码的可维护性和扩展性。

主要功能

  • 创建通用文件夹:处理常见的ViewModel、Model和Widget。
  • 创建核心文件夹:处理基础类、常量、帮助函数和服务。
  • 创建特性文件夹:处理所有页面和功能模块。

使用方法

  1. 添加依赖: 在 pubspec.yaml 文件中添加 nadarchitecture 作为开发依赖:

    dev_dependencies:
      nadarchitecture: ^1.0.17
    
  2. 更新依赖: 运行以下命令以更新依赖项:

    flutter pub get
    
  3. 生成项目结构: 运行以下命令以创建项目文件夹结构:

    flutter pub run nadarchitecture:main
    

实现的第三方库

nadarchitecture 集成了多个常用的Flutter和Dart库,包括但不限于:

  • get_storage:用于快速、轻量级的键值存储。
  • get_it:用于服务定位器模式,简化依赖注入。
  • flutter_native_splash:自定义Flutter应用的启动页。
  • dartz:提供函数式编程工具,如不可变数据结构、单子等。
  • flutter_svg:用于渲染SVG图像。
  • flutter_screenutil:适配不同屏幕尺寸和字体大小。
  • logger:提供美观的日志输出。
  • dio:强大的HTTP请求库。
  • provider:简化状态管理。
  • json_annotationjson_serializable:用于JSON序列化。
  • freezedfreezed_annotation:用于生成不可变类。
  • build_runner:用于代码生成和模块化编译。
  • flutter_gen_runner:用于生成资产、字体、颜色等代码。

项目文件夹结构

以下是使用 nadarchitecture 生成的典型项目结构:

├── common
│ ├── models
│ │ ├── token_model.dart
│ │ └── user_model.dart
│ ├── view_model
│ │ └── user_view_model.dart
│ └── widget
│     ├── app_logo.dart
│     ├── custom_button.dart
│     └── custom_input.dart
├── core
│ ├── base
│ │ ├── model
│ │ │ ├── base_error_model.dart
│ │ │ └── base_pagination_model.dart
│ │ ├── view
│ │ │ └── base_view.dart
│ │ └── viewModel
│ │     └── base_view_model.dart
│ ├── constants
│ │ ├── app
│ │ │ └── app_constants.dart
│ │ ├── color
│ │ │ └── app_colors.dart
│ │ ├── end_point
│ │ │ └── app_end_points.dart
│ │ ├── enum
│ │ │ └── http_types_enums.dart
│ │ ├── local
│ │ │ └── app_locals.dart
│ │ ├── notification
│ │ │ └── notification_constants.dart
│ │ ├── route
│ │ │ └── app_routes.dart
│ │ ├── text_style
│ │ │ └── app_text_styles.dart
│ │ └── theme
│ │     └── app_themes.dart
│ ├── helper
│ │ ├── extension
│ │ │ ├── color.dart
│ │ │ ├── context.dart
│ │ │ └── string.dart
│ │ └── init
│ │     └── helper_init.dart
│ └── services
│     ├── get_it
│     │ └── get_it_service.dart
│     ├── local
│     │ └── local_service.dart
│     ├── logger
│     │ └── logger_service.dart
│     ├── network
│     │ ├── helper
│     │ │ └── network_helper.dart
│     │ ├── mapper
│     │ │ └── api_model_mapper.dart
│     │ └── network_service.dart
│     ├── route
│     │ ├── app_router.dart
│     │ └── route_service.dart
│     └── theme
│         └── theme_service.dart
├── features
│ ├── home
│ │ └── presentation
│ │     ├── mixin
│ │     │ └── home_mixin.dart
│ │     └── view
│ │         └── home_view.dart
│ ├── login
│ │ ├── data
│ │ │ ├── data_sources
│ │ │ │ └── login_data_source.dart
│ │ │ ├── models
│ │ │ │ ├── login_request
│ │ │ │ │ └── login_request_model.dart
│ │ │ │ └── login_response
│ │ │ │     └── login_response_model.dart
│ │ │ └── repositories
│ │ │     └── login_repository_impl.dart
│ │ ├── domain
│ │ │ ├── entities
│ │ │ │ └── login_response
│ │ │ │     └── login_response_entity.dart
│ │ │ └── repositories
│ │ │     └── login_repository.dart
│ │ └── presentation
│ │     ├── mixin
│ │     │ └── login_mixin.dart
│ │     ├── view
│ │     │ └── login_view.dart
│ │     └── view_model
│ │         └── login_view_model.dart
│ └── test
│     ├── data
│     │ ├── data_sources
│     │ │ └── test_data_source.dart
│     │ ├── models
│     │ │ └── test_model.dart
│     │ └── repositories
│     │     └── test_repository_impl.dart
│     ├── domain
│     │ ├── entities
│     │ │ └── test_entity.dart
│     │ └── repositories
│     │     └── test_repository.dart
│     └── presentation
│         ├── mixin
│         │ └── test_mixin.dart
│         ├── view
│         │ └── test_view.dart
│         └── view_model
│             └── test_view_model.dart
└── main.dart

完整示例Demo

以下是一个完整的示例项目,展示了如何使用 nadarchitecture 创建一个简单的Flutter应用。这个应用包含登录功能,并使用了 provider 进行状态管理。

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'core/consts/app/app_constants.dart';
import 'core/consts/theme/app_themes.dart';
import 'core/helper/init/helper_init.dart';
import 'core/services/get_it/get_it_service.dart';
import 'core/services/route/app_router.dart';
import 'core/services/route/route_service.dart';
import 'core/services/theme/theme_service.dart';

Future<void> main() async {
  // 初始化HelperInit
  await HelperInit.init();
  // 启动应用
  HelperInit.startApp();
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(375, 882), // 设计稿尺寸
      child: MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => ThemeService()), // 提供主题服务
        ],
        child: MaterialApp(
          debugShowCheckedModeBanner: false, // 关闭调试模式横幅
          title: AppConstants.appName, // 应用名称
          themeMode: context.watch<ThemeService>().themeMode, // 监听主题模式
          theme: AppThemes.lightTheme, // 光明主题
          darkTheme: AppThemes.darkTheme, // 深色主题
          navigatorKey: getIt<RouteService>().navigatorKey, // 导航键
          onGenerateRoute: AppRouter.generateRoute, // 路由生成器
        ),
      ),
    );
  }
}
login_view.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'login_view_model.dart'; // 导入登录ViewModel

class LoginView extends StatelessWidget {
  const LoginView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('登录'),
      ),
      body: ChangeNotifierProvider(
        create: (_) => LoginViewModel(), // 创建LoginViewModel实例
        child: Consumer<LoginViewModel>(
          builder: (context, viewModel, _) {
            return Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  TextField(
                    controller: viewModel.emailController, // 绑定邮箱输入框
                    decoration: const InputDecoration(labelText: '邮箱'),
                  ),
                  const SizedBox(height: 16),
                  TextField(
                    controller: viewModel.passwordController, // 绑定密码输入框
                    obscureText: true,
                    decoration: const InputDecoration(labelText: '密码'),
                  ),
                  const SizedBox(height: 16),
                  ElevatedButton(
                    onPressed: () {
                      viewModel.login(); // 触发登录操作
                    },
                    child: const Text('登录'),
                  ),
                  if (viewModel.isLoading) // 显示加载指示器
                    const CircularProgressIndicator(),
                  if (viewModel.error.isNotEmpty) // 显示错误信息
                    Text(
                      viewModel.error,
                      style: const TextStyle(color: Colors.red),
                    ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}
login_view_model.dart
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:get_it/get_it.dart';
import 'package:nadarchitecture/core/services/network/network_service.dart';
import 'package:nadarchitecture/features/login/data/models/login_request_model.dart';
import 'package:nadarchitecture/features/login/data/models/login_response_model.dart';

class LoginViewModel with ChangeNotifier {
  final TextEditingController emailController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();
  final NetworkService _networkService = getIt<NetworkService>();
  bool _isLoading = false;
  String _error = '';

  bool get isLoading => _isLoading;
  String get error => _error;

  Future<void> login() async {
    try {
      _isLoading = true;
      notifyListeners();

      final request = LoginRequestModel(
        email: emailController.text,
        password: passwordController.text,
      );

      final response = await _networkService.post(
        endpoint: '/api/login',
        data: request.toJson(),
      );

      final loginResponse = LoginResponseModel.fromJson(response.data);
      // 处理登录成功后的逻辑,例如导航到主页
      print('登录成功: ${loginResponse.token}');
    } catch (e) {
      if (e is DioError) {
        _error = e.response?.data['message'] ?? '网络请求失败';
      } else {
        _error = '未知错误';
      }
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  @override
  void dispose() {
    emailController.dispose();
    passwordController.dispose();
    super.dispose();
  }
}
app_router.dart
import 'package:flutter/material.dart';
import 'package:nadarchitecture/features/home/presentation/view/home_view.dart';
import 'package:nadarchitecture/features/login/presentation/view/login_view.dart';

class AppRouter {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(builder: (_) => const LoginView());
      case '/home':
        return MaterialPageRoute(builder: (_) => const HomeView());
      default:
        return MaterialPageRoute(builder: (_) => const Scaffold(body: Center(child: Text('404'))));
    }
  }
}
helper_init.dart
import 'package:get_it/get_it.dart';
import 'package:nadarchitecture/core/services/get_it/get_it_service.dart';
import 'package:nadarchitecture/core/services/local/local_service.dart';
import 'package:nadarchitecture/core/services/logger/logger_service.dart';
import 'package:nadarchitecture/core/services/network/network_service.dart';
import 'package:nadarchitecture/core/services/route/route_service.dart';
import 'package:nadarchitecture/core/services/theme/theme_service.dart';

class HelperInit {
  static Future<void> init() async {
    // 初始化GetIt
    GetItService.init();
    // 初始化本地存储服务
    await LocalService.init();
    // 初始化日志服务
    LoggerService.init();
    // 初始化网络服务
    await NetworkService.init();
    // 初始化路由服务
    RouteService.init();
    // 初始化主题服务
    await ThemeService.init();
  }

  static void startApp() {
    // 启动应用逻辑
  }
}
get_it_service.dart
import 'package:get_it/get_it.dart';
import 'package:nadarchitecture/core/services/local/local_service.dart';
import 'package:nadarchitecture/core/services/logger/logger_service.dart';
import 'package:nadarchitecture/core/services/network/network_service.dart';
import 'package:nadarchitecture/core/services/route/route_service.dart';
import 'package:nadarchitecture/core/services/theme/theme_service.dart';

final getIt = GetIt.instance;

class GetItService {
  static void init() {
    // 注册LocalService
    getIt.registerSingleton<LocalService>(LocalService());
    // 注册LoggerService
    getIt.registerSingleton<LoggerService>(LoggerService());
    // 注册NetworkService
    getIt.registerSingleton<NetworkService>(NetworkService());
    // 注册RouteService
    getIt.registerSingleton<RouteService>(RouteService());
    // 注册ThemeService
    getIt.registerSingleton<ThemeService>(ThemeService());
  }
}
network_service.dart
import 'package:dio/dio.dart';
import 'package:nadarchitecture/core/constants/end_point/app_end_points.dart';

class NetworkService {
  final Dio _dio = Dio();

  static Future<void> init() async {
    // 初始化Dio配置
    final instance = NetworkService();
    instance._dio.options.baseUrl = AppEndPoints.baseUrl;
    instance._dio.interceptors.add(LogInterceptor()); // 添加日志拦截器
  }

  Future<Response<T>> get<T>(String endpoint) async {
    try {
      final response = await _dio.get(endpoint);
      return response;
    } catch (e) {
      rethrow;
    }
  }

  Future<Response<T>> post<T>(String endpoint, {Map<String, dynamic>? data}) async {
    try {
      final response = await _dio.post(endpoint, data: data);
      return response;
    } catch (e) {
      rethrow;
    }
  }
}
theme_service.dart
import 'package:flutter/material.dart';
import 'package:nadarchitecture/core/consts/theme/app_themes.dart';

class ThemeService with ChangeNotifier {
  ThemeMode _themeMode = ThemeMode.system;

  ThemeMode get themeMode => _themeMode;

  void toggleTheme() {
    _themeMode = _themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }

  static Future<void> init() async {
    // 从本地存储中读取用户选择的主题模式
  }
}

更多关于Flutter未定义功能插件nadarchitecture的潜在用途探索的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter未定义功能插件nadarchitecture的潜在用途探索的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,当你遇到“未定义功能插件”(比如你提到的nadarchitecture)时,通常意味着这个插件不存在于Flutter的官方包中,或者它可能是一个自定义的、非公开的插件。由于nadarchitecture不是一个广为人知的Flutter插件,我无法提供关于它的具体文档或预构建功能。不过,我可以向你展示如何探索和定义一个自定义Flutter插件的基本结构,这可能帮助你理解如何开发和使用类似功能的插件。

创建一个自定义Flutter插件

  1. 创建Flutter插件项目

    使用Flutter命令行工具创建一个新的插件项目:

    flutter create --template=plugin my_custom_plugin
    cd my_custom_plugin
    
  2. 插件结构

    插件项目将包含两个主要部分:Dart代码(用于Flutter前端)和原生代码(用于Android和iOS后端)。

    • lib/my_custom_plugin.dart:这是Dart端的接口。
    • android/:包含Android端的实现。
    • ios/:包含iOS端的实现。
  3. 实现一个简单功能

    例如,我们实现一个简单的功能,从原生端返回一个字符串。

    lib/my_custom_plugin.dart

    import 'dart:async';
    
    typedef NativeFunctionResultHandler = Function(String result);
    typedef NativeFunctionHandler = Future<void> Function(NativeFunctionResultHandler result);
    
    class MyCustomPlugin {
      static const MethodChannel _channel = const MethodChannel('my_custom_plugin');
    
      static Future<String?> get platformVersion async {
        final String? version = await _channel.invokeMethod('getPlatformVersion');
        return version;
      }
    
      static NativeFunctionHandler get nativeFunction => _channel.invokeMethod<void>('nativeFunction');
    }
    

    android/src/main/kotlin/com/example/my_custom_plugin/MyCustomPlugin.kt

    package com.example.my_custom_plugin
    
    import io.flutter.embedding.engine.plugins.FlutterPlugin
    import io.flutter.embedding.engine.plugins.activity.ActivityAware
    import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
    import io.flutter.plugin.common.MethodCall
    import io.flutter.plugin.common.MethodChannel
    import io.flutter.plugin.common.MethodChannel.MethodCallHandler
    import io.flutter.plugin.common.MethodChannel.Result
    import android.app.Activity
    
    class MyCustomPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
      private lateinit var channel : MethodChannel
    
      override fun onAttachedToEngine(binding: FlutterPluginBinding) {
        channel = MethodChannel(binding.binaryMessenger, "my_custom_plugin")
        channel.setMethodCallHandler(this)
      }
    
      override fun onMethodCall(call: MethodCall, result: Result) {
        if (call.method == "getPlatformVersion") {
          result.success("Android ${android.os.Build.VERSION.RELEASE}")
        } else if (call.method == "nativeFunction") {
          val handler = { resultStr: String -> result.success(resultStr) } as NativeFunctionResultHandler
          handler("Hello from native Android!")
        } else {
          result.notImplemented()
        }
      }
    
      override fun onDetachedFromEngine(binding: FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
      }
    
      override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        // No-op
      }
    
      override fun onDetachedFromActivityForConfigChanges() {
        // No-op
      }
    
      override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        // No-op
      }
    
      override fun onDetachedFromActivity() {
        // No-op
      }
    }
    

    ios/Classes/MyCustomPlugin.swift

    import Flutter
    
    public class MyCustomPlugin: NSObject, FlutterPlugin {
      public static func register(with registrar: FlutterRegistrar) {
        let channel = FlutterMethodChannel(name: "my_custom_plugin", binaryMessenger: registrar.messenger())
        let instance = MyCustomPlugin()
        registrar.addMethodCallDelegate(instance, channel: channel)
      }
    
      public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        if call.method == "getPlatformVersion" {
          let version = UIDevice.current.systemVersion
          result(version)
        } else if call.method == "nativeFunction" {
          let handler: @escaping (String) -> Void = { resultStr in
            result(resultStr)
          }
          handler("Hello from native iOS!")
        } else {
          result(FlutterMethodNotImplementedError(methodName: call.method))
        }
      }
    }
    
  4. 在Flutter应用中使用插件

    在你的Flutter应用的pubspec.yaml中添加对本地插件的依赖:

    dependencies:
      flutter:
        sdk: flutter
      my_custom_plugin:
        path: ../path/to/my_custom_plugin
    

    然后在你的Dart代码中调用插件:

    import 'package:flutter/material.dart';
    import 'package:my_custom_plugin/my_custom_plugin.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Plugin example app'),
            ),
            body: Center(
              child: FutureBuilder<String?>(
                future: MyCustomPlugin.platformVersion,
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    if (snapshot.hasError) {
                      return Text('Error: ${snapshot.error}');
                    }
                    return Text('Platform version: ${snapshot.data ?? 'Unknown'}');
                  } else if (snapshot.connectionState == ConnectionState.active) {
                    return CircularProgressIndicator();
                  } else {
                    return Text('Loading...');
                  }
                },
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () async {
                MyCustomPlugin.nativeFunction.then((_) {});
              },
              tooltip: 'Invoke native function',
              child: Icon(Icons.add),
            ),
          ),
        );
      }
    }
    

这段代码展示了如何创建一个简单的Flutter插件,它可以在原生端(Android和iOS)执行一些操作,并将结果返回给Flutter前端。虽然nadarchitecture这个具体插件的详细实现可能不同,但上述步骤提供了一个模板,帮助你理解如何定义和使用自定义Flutter插件。如果你确实在寻找一个名为nadarchitecture的插件,建议检查是否有拼写错误,或者询问提供这个名称的源头是否有相关的资源或文档。

回到顶部