少点废话
1.了解Fair
Fair,由58同城开源提供,目的是flutter项目上架后动态更新代码,
首先了解一个概念,热更新是flutter打包APK后会讲所有的dart代码生成一个so文件,手机通过读取并执行so文件;基于此,我们可以替换iso文件达到代码的更新,这种方式称之为热更新;但是这种方式被google给限制了,上架后会立即闪退,当然国内的平台是可以通过这种方式进行热更新。
不同与热更新,fair是将代码生成配置文件,然后将配置文件托管到服务器,flutter通过加载服务区的配置文件,动态的生成界面,这种方式简单但是很繁琐,如果Flutter版本更替出现差异,就很麻烦而且容易出bug。
2.前期准备
首先我们到fair的代码库下载最新代码,传送门:https://github.com/wuba/Fair
3.环境搭建
(1)AS安装插件
在setting-plugin,搜索并安装FairTemplate

(2)Fair本地化修改
下载后,我们把一下几个模块给提出来出来,目的是因为这些项目可能会导致包的版本冲突,如果不冲突可以不用管这些,直接引入显示的版本 ,传送门:fair | Flutter package

提出来后,我们用AS打开以下项目
1)annotation模块
打开项目后,在pubspec.yaml中,put get一下,
没报错 ,下一项
2)compiler模块
这个模块会导致 intl 冲突,因此我们要自己处理下,如果自己的项目没有使用intl,可以忽略
在pubspec.yaml中再将此项修改

put get一下,项目不报错,下一项
3)flutter_verion模块
在里面找到自己Flutter版本试用的,使用AS打开项目
打开后,put get一下发现项目报错,找到报错项注释掉,
这里是因为Flutter版本差异造成的,里面的注释掉可能会导致我们打包的样式出现问题,目前是入门阶段,遇到问题的时候再解决吧
注释完成后,项目不报错,下一项
4)fair模块
打开后,直接把Example目录删掉,里面没啥用;
然后在pubspec.yaml中再将此项修改

fair_version改成你所使用的版本
put get一下,项目不报错,完成
4.开发
(1)引包
在项目pubspec.yaml 配置
dependencies:
flutter_localizations:
sdk: flutter
intl: any
...
#fair: ^4.0.0 #热更新
fair:
path: ../plugin/fair
dev_dependencies:
...
build_runner: ^2.0.0
fair_compiler:
path: ../plugin/fair_compiler
flutter:
uses-material-design: true
# generate: true
assets:
- assets/
- assets/bundle/
flutter_intl:
enabled: true
(2)服务端代码
完成后,以下直接贴代码,不解释
在Main.dart里面
void main() {
//如果size是0,则设置回调,在回调中runApp
if (window.physicalSize.isEmpty) {
window.onMetricsChanged = () {
//在回调中,size仍然有可能是0
if (!window.physicalSize.isEmpty) {
window.onMetricsChanged = null;
runMyApp();
}
};
} else {
//如果size非0,则直接runApp
runMyApp();
}
}
void runMyApp() async {
WidgetsFlutterBinding.ensureInitialized();
LogUtil.init(isDebug: false);
await LanManage.si.initialize();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]);
Utils.setStatusLight(); //设置状态栏颜色
// runApp();
FairApp.runApplication(_getApp(), plugins: {});
}
dynamic _getApp() => FairApp(modules: {}, delegate: {}, child: Phoenix(child: TestMyApp()));
class TestMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget widget1 = const DynamicWidget("TT");
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(centerTitle: true, title: const Text("APP")),
body: Column(children: [
Image.asset("assets/img.png", width: 200, height: 200),
widget1,
])));
}
}
@FairPatch()
class DynamicWidget extends StatelessWidget {
@FairWell('content')
final String content;
const DynamicWidget(this.content, {super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.only(top: 30, bottom: 30),
color: Colors.redAccent,
width: 300,
height: 300,
child: Text(content, style: const TextStyle(fontSize: 30, color: Colors.yellow))));
}
}
以上完成后,在AS的工具栏将代码生成以下

在Terminal视图中,可以看到执行结果

在项目界面中,找到这两个文件,然后放到服务器即可

(3)APP代码
直接贴代码
class TestMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget widget2 = FairWidget(
//这个地方如果是本地测试,直接用绝对路径即可
//如果是服务器,直接指向json文件即可
path: "http://xx.xx.xx.xx/app/bundle/lib_main_test.fair.json",
data: {"content": "VV"},
);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(centerTitle: true, title: const Text("APP")),
body: Column(children: [
Image.asset("assets/img.png", width: 200, height: 200),
widget2,
])));
}
}
至此,接入完成,收工!
5.参考资料