一、背景及目标
1、背景
在使用 Flutter 开发跨平台应用时,我们发现现有应用的逻辑代码和视图代码没有充分解耦。这在开发多端(如iOS、Android、Mac、Windows、Web)场景下,不利于复用已编写的逻辑,从而影响开发效率。我们可以利用 Mixin 的能力解决这个问题
2、目标
在不影响现有功能的基础上,重构应用的业务代码。通过复用重构后的逻辑代码,快速完成 APP 端的功能迁移到桌面端,提高代码的一致性、扩展性,并适配多端场景。
二、解决方案
1、移动端应用(APP)
对现有代码进行改造:
(1)将APP页面中的 State 抽离,封装成 StateMixin(StateMixin:继承于 State 的 mixin)。
(2)保留APP页面的UI代码,将封装好的StateMixin进行混入,以还原业务实现。
2、其他平台
通过复用封装的 StateMixin,采用 View+StateMixin 的方式实现业务,从而实现逻辑层的跨平台复用:
(1)将多端共用的属性和方法提取并封装成基类(BaseState),统一处理可复用的业务逻辑。
(2)将各端差异化的属性和方法提取并封装成子类(如AppState、DesktopState、WebState),以个性化处理各端差异化的业务。
3、StateMixin
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> {}
4、Widget
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 {}
三、优势
(1)最小化对现有代码的修改。
(2)充分解耦各平台代码。
(3)通过子类覆盖父类方法,灵活应对各种业务场景。
对现有 APP 代码的改动较小,只需将 State 中的属性和方法迁移至 mixin 文件,保留 widget 视图代码。然后将 mixin 文件重新混入视图代码中,即可完成 APP 代码的重构。其他平台可直接复用 mixin。对于 APP 中原有的方法名、属性名和逻辑,基本无需调整。
注意事项
(1)抽离至mixin中的属性或方法不能设为私有(正确示例:name;错误示例:_name)
(2)混入mixin时,基类必须放在子类前面(示例:State<AppView> with BaseState, AppState)
(3)可以通过基础视图类BaseView处理页面间传参。
四、具体实施
1、view 实现
(1)通过适配层动态渲染 APP 和 桌面端 UI视图。
(2)通过 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 {}
2、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 实现多端应用开发中逻辑层的复用与解耦的方案。通过对现有代码的改造和封装,我们能够在最小化对现有代码的修改的同时,充分解耦各平台代码,并灵活应对各种业务场景。