Flutter 多端应用开发

1,176 阅读3分钟

背景

在使用 Flutter 开发跨平台应用时,我们发现现有应用的逻辑代码和视图代码没有充分解耦。这在开发多端(如iOS、Android、Mac、Windows、Web)场景下,不利于复用已编写的逻辑,从而影响开发效率。我们可以利用 Mixin 的能力解决这个问题

目标

在不影响现有功能的基础上,重构应用的业务代码。通过复用重构后的逻辑代码,快速完成 APP 端的功能迁移到桌面端,提高代码的一致性、扩展性,并适配多端场景。

解决方案

移动端应用(APP)

对现有代码进行改造:

  • 将APP页面中的 State 抽离,封装成 StateMixin(StateMixin:继承于 State 的 mixin);
  • 保留APP页面的UI代码,将封装好的StateMixin进行混入,以还原业务实现;

其他平台

通过复用封装的 StateMixin,采用 View+StateMixin 的方式实现业务,从而实现逻辑层的跨平台复用:

  • 将多端共用的属性和方法提取并封装成基类(BaseState),统一处理可复用的业务逻辑;
  • 将各端差异化的属性和方法提取并封装成子类(如AppState、DesktopState、WebState),以个性化处理各端差异化的业务。

StateMixin

classDiagram
BaseState <|-- AppState
BaseState <|-- DesktopState
BaseState <|-- WebState
BaseState : String name
BaseState : int age
BaseState: initState()
BaseState: eat()

class AppState{
	String height
  @override initState()
  run()
}
class DesktopState{
	String width
  @override initState()
  jump()
}
class WebState{
	@override
	String name
  @override initState()
  dance()
}
mixin BaseState<T extends BaseView> on State<T> {}
mixin AppState<T extends AppView> on BaseState<T> {}
mixin DesktopState<T extends DesktopView> on BaseState<T> {}
mixin WebState<T extends WebView> on BaseState<T> {}

Widget

classDiagram
BaseView <|-- AppView
BaseView <|-- DesktopView
BaseView <|-- WebView
BaseView : String viewName

class AppView{ }
class DesktopView{ }
class WebView{ }
class BaseView extends StatefulWidget {}
class AppView extends BaseView {}
class _AppViewState extends State<AppView> with BaseState, AppState {}
class DesktopView extends BaseView {}
class _DesktopViewState extends State<DesktopView> with BaseState, DesktopState {}
class WebView extends WebView {}
class _WebViewState extends State<WebView> with BaseState, WebState {}

优势

  • 最小化对现有代码的修改;
  • 充分解耦各平台代码;
  • 通过子类覆盖父类方法,灵活应对各种业务场景;

对现有 APP 代码的改动较小,只需将 State 中的属性和方法迁移至 mixin 文件,保留 widget 视图代码。然后将 mixin 文件重新混入视图代码中,即可完成 APP 代码的重构。其他平台可直接复用 mixin。对于 APP 中原有的方法名、属性名和逻辑,基本无需调整。

注意事项

  1. 抽离至mixin中的属性或方法不能设为私有(正确示例:name;错误示例:_name)
  2. 混入mixin时,基类必须放在子类前面(示例:State<AppView> with BaseState, AppState
  3. 可以通过基础视图类BaseView处理页面间传参

具体实施

view 实现

  • 通过适配层动态渲染 APP 和 桌面端 UI视图
  • 通过 mixin 实现逻辑复用
// index.dart
Widget build(BuildContext context) {
  // 通过视图适配层,收敛多端视图的适配
  return AdapterLayout(
    mobile: AppGroupShareView(todoLabel: widget.todoLabel,),
    desktop: DesktopGroupShareView(todoLabel: widget.todoLabel),
  );
}
// base_group_share_view.dart
abstract class BaseGroupShareView extends StatefulWidget {
  const BaseGroupShareView({Key? key, required this.todoLabel})
      : super(key: key);

  final TodoLabel todoLabel;
}

	
// app_group_share_view.dart
class AppGroupShareView extends BaseGroupShareView {
  AppGroupShareView({Key? key, required todoLabel})
      : super(todoLabel: todoLabel);

  @override
  _AppGroupShareViewState createState() => _AppGroupShareViewState();
}
class _AppGroupShareViewState extends State<AppGroupShareView>
    with BaseGroupShareMethod, AppGroupShareMethod {}
	
	
// desktop_group_share_view.dart
class DesktopGroupShareView extends BaseGroupShareView {
  const DesktopGroupShareView({Key? key, required todoLabel})
      : super(todoLabel: todoLabel);

  @override
  _DesktopGroupShareViewState createState() => _DesktopGroupShareViewState();
}
class _DesktopGroupShareViewState extends State<DesktopGroupShareView>
    with BaseGroupShareMethod, DesktopGroupShareMethod {}

mixin 实现

// base_group_share_method.dart
mixin BaseGroupShareMethod<T extends BaseGroupShareView> on State<T> {
  get isCreate {
    // 业务逻辑
    reture 1
  }

  void initState() {
    super.initState();
    // 业务逻辑
    // ...
  }


  // 可直接使用
  void backGroupShare() {
      resetLabel();
  }

  // 需子类实现
  void jumpToContactView() {}

  // 需子类实现
  void refreshUI() {}
}
	
	
// app_group_share_method.dart
mixin AppGroupShareMethod<T extends AppGroupShareView>
    on BaseGroupShareMethod<T> {
  void backGroupShare() {
    // 调用父类方法
    super.backGroupShare();
    Get.back();
  }

  // 重新方法,各端差异实现
  void jumpToContactView() {
    Get.to(() => Contact());
  }

  // 刷新UI
  refreshUI() {
    TDStore().todoLabelsStore.fetchServerData().then((value) {
      // ...
    });
  }
}
	

// desktop_group_share.method
mixin DesktopGroupShareMethod<T extends DesktopGroupShareView>
    on BaseGroupShareMethod<T> {
  // 重新方法,各端差异实现
  void jumpToContactView() {
    print('跳转桌面端');
  }
}

总结

在本文中,我们提供了一种 Flutter 实现多端应用开发中逻辑层的复用与解耦的方案。通过对现有代码的改造和封装,我们能够在最小化对现有代码的修改的同时,充分解耦各平台代码,并灵活应对各种业务场景。希望对大家有所帮助!