1
+ [ English Version] ( ) : is working in progress...
2
+
3
+ # Unify:Flutter-原生混合通信
4
+
1
5
## 介绍
2
- Unify 旨在为Flutter和其宿主平台之间的交互提供类型安全的代码生成解决方案。
3
6
4
- ## 特性
5
- * ** 多端接口统一** :借助代码自动生成技术和通用接口模板,实现多端接口的标准化和统一化。
6
- * ** 语言易扩展** :内置了独特的AST协议和通用的代码模板,利用编程式思想进行多语言扩展。
7
- * ** 代码模块化** :按照模板目录结构生成和存储代码,模型与接口完全分离解耦。
8
- * ** 简单易上手** :一条命令实现跨端语言调用,开发者无需手动编写繁琐的通信代码,只需专注于接口的定义。
7
+ Unify 是一个 Flutter 代码生成器,解决 Flutter 混合开发场景下,原生模块与 Flutter 模块间的大规模通信问题。
8
+
9
+ Unify 允许开发者声明平台无关的模块抽象,灵活注入实现,并生成 Flutter、Android、iOS 多平台下统一调用 SDK。
10
+
11
+ 基于 Unify 的代码生成技术,允许开发者使用 Dart 语言声明模块接口与实体。对于实现注入方式,开发者可选择注入原生实现(Android、iOS)或 Flutter 实现。
12
+
13
+ 整体原理如下:
14
+
15
+ ![ ] ( docs/public/unify-arch.png )
16
+
17
+ Unify 擅长解决:
18
+
19
+ - 大量原生模块高效导入 Flutter
20
+ - 大量 Flutter 模块高效导入原生
21
+ - 解决大量 Channel 难以维护的问题
22
+ - 原生与 Flutter 并存下的** 混合架构分层**
23
+
24
+ Unify 由滴滴出行国际化外卖团队自研,广泛应用于滴滴国际化外卖及国际化出行业务。有效支撑业务 Flutter 大规模落地。
25
+
26
+ ## Installation
27
+
28
+ Unify 是一个使用 Dart 开发的命令。
29
+
30
+ 在 Flutter 工程的 ` pubspec.yaml ` 中添加 ` dev_dependencies ` :
31
+
32
+ ``` yaml
33
+ dev_dependencies :
34
+ unify : latest_version
35
+ ` ` `
36
+
37
+ > 注:目前 Unify 尚未发布 pub.dev,可先通过 git 依赖方式体验。后续会正式发布 pub.dev,敬请期待。
38
+
39
+ git 依赖:
40
+
41
+ ` ` ` yaml
42
+ dev_dependencies :
43
+ unify :
44
+ git : git@github.com:maxiee/Unify.git
45
+ ` ` `
46
+
47
+ 执行 ` flutter pub get` 拉取依赖。之后即可运行 Unify:
48
+
49
+ ` ` ` sh
50
+ flutter pub run unify api
51
+ ` ` `
52
+
53
+ > 注:执行 Unify 命令通常需伴随一系列参数,具体可使用方式可参见 Getting Started。
54
+
55
+
56
+ # # Getting Started
57
+
58
+ 以最基础的使用场景为例:有一个原生 SDK,同时包含 Android、iOS 版本,开发者需要对其进行统一封装,并导入到 Flutter 中。
59
+
60
+ > 本例实例代码位于 `examples/01_uninativemodule_demo` 下。
61
+
62
+ 运行 Demo:
63
+
64
+ 首先 clone 工程,并进入 `01_uninativemodule_demo` 目录:
65
+
66
+ ` ` ` sh
67
+ git clone git@github.com:didi/Unify.git
68
+ cd ./Unify/01_uninativemodule_demo
69
+ ` ` `
70
+
71
+ ` 01_uninativemodule_demo` 是一个普通的 Flutter App,其功能是:原生侧(Android/iOS)各实现一个系统信息模块,统一导入 Flutter,在 Flutter 中统一调用。
72
+
73
+ 不同之处在于,**项目下有一个 interface 目录,这是我们声明 Unify 模块的地方**。其中包含两个类:
74
+
75
+ 首先是一个模块声明,`@UniNativeModule` 表示该模块的实现由 Native 原生提供(NativeModule):
76
+
77
+ ` ` ` dart
78
+ // device_info_service.dart
79
+ @UniNativeModule()
80
+ abstract class DeviceInfoService {
81
+ /// 获取设备信息
82
+ Future<DeviceInfoModel> getDeviceInfo();
83
+ }
84
+ ` ` `
85
+
86
+ 同时可以看到,`getDeviceInfo` 返回一个 `DeviceInfoModel`,声明如下:
87
+
88
+ ` ` ` dart
89
+ // device_info_model.dart
90
+ @UniModel()
91
+ class DeviceInfoModel {
92
+ /// 系统版本
93
+ String? osVersion;
94
+
95
+ /// 内存信息
96
+ String? memory;
97
+
98
+ /// 手机型号
99
+ String? plaform;
100
+ }
101
+ ` ` `
102
+
103
+ 这是什么意思呢?**使用 Unify 之后,开发者只需关注跨端统一模块的声明**,如果由原生侧提供实现使用 `@UniNativeModule` 注解,如果由 Flutter 侧提供实现使用 `@UniFlutterModule` 注解,如果使用复杂实体使用 `@UniModel` 注解。
104
+
105
+ 接口声明好后,执行项目目录下的 `gen_uni_code.sh` 脚本:
106
+
107
+ ` ` ` sh
108
+ flutter pub run unify api\
109
+ --input=` pwd`/interface \
110
+ --dart_out=`pwd`/lib \
111
+ --java_out=`pwd`/android/src/main/java/com/example/uninativemodule_demo \
112
+ --java_package=com.example.uninativemodule_demo \
113
+ --oc_out=`pwd`/ios/Classes \
114
+ --dart_null_safety=true \
115
+ --uniapi_prefix=UD
116
+ ```
117
+
118
+ 这会调用 Unify 生成器。其中:
119
+
120
+ - ` input ` :指定接口输入目录
121
+ - ` dart_out ` :指定 Dart 部分输出目录
122
+ - ` java_out ` :指定 Java 部分输出目录
123
+ - ` java_package ` :指定对应的 Java 报名
124
+ - ` oc_out ` :iOS 的 Objective-C 输出目录
125
+ - ` dart_null_safety ` :是否启用空安全
126
+ - ` uniapi_prefix ` :(可选),生成器会生成一个 Unify 类,这里提供一个前缀,避免多个使用 Unify 的库间相互冲突。
127
+
128
+ 执行后,在工程内会生成以下文件:
129
+
130
+ 由于实现由原生侧注入,所以我们使用 ` @UniNativeModule ` ,在原生侧生成供注入的接口:
131
+
132
+ - Android:[ DeviceInfoService.java] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/android/src/main/java/com/example/uninativemodule_demo/DeviceInfoService.java )
133
+ - iOS:[ DeviceInfoService.h] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/ios/Classes/DeviceInfoService.h ) 、[ DeviceInfoService.m] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/ios/Classes/DeviceInfoService.m )
134
+
135
+ 有了这些接口,由开发者继承补充模块的原生代码实现:
136
+
137
+ - Android 实现类:[ DeviceInfoServiceImpl.java] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/example/android/app/src/main/java/com/example/uninativemodule_demo_example/DeviceInfoServiceImpl.java )
138
+ - Android 注册实现:[ MainActivity.java] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/example/android/app/src/main/java/com/example/uninativemodule_demo_example/MainActivity.java )
139
+
140
+ - iOS 实现类:[ DeviceInfoServiceVendor.h] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/example/ios/Runner/DeviceInfoServiceVendor.h ) 、[ DeviceInfoServiceVendor.m] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/example/ios/Runner/DeviceInfoServiceVendor.m )
141
+ - iOS 注册实现:[ AppDelegate.m] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/example/ios/Runner/AppDelegate.m )
142
+
143
+ 我们可以看到,同时生成了跨端 ` UniModel ` 实体,** 在各平台下都能直接使用 Model 类,由 Unify 抹平底层序列化传递** :
144
+
145
+ - Android:[ DeviceInfoModel.java] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/android/src/main/java/com/example/uninativemodule_demo/DeviceInfoModel.java )
146
+ - iOS:[ DeviceInfoModel.h] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/ios/Classes/DeviceInfoModel.h ) 、[ DeviceInfoModel.m] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/ios/Classes/DeviceInfoModel.m )
147
+ - Flutter:[ device_info_model.dart] ( https://github.com/didi/Unify/blob/master/examples/01_uninativemodule_demo/lib/device_info_model.dart )
148
+
149
+ 至此,便完成了** 将一个原生模块统一导入 Flutter** !
150
+
151
+ 在 Flutter 中,可以以统一方式调用:
152
+
153
+ ``` dart
154
+ OutlinedButton(
155
+ child: const Text("获取设备信息"),
156
+ onPressed: () {
157
+ DeviceInfoService.getDeviceInfo().then((deviceInfoModel) {
158
+ setState(() {
159
+ _platformVersion = "\n${deviceInfoModel.encode()}";
160
+ });
161
+ });
162
+ },
163
+ ),
164
+ ```
165
+
166
+ ![ ] ( ./docs/public/unify-demo.png )
167
+
168
+ Bingo!是不是像调用一个 Flutter 模块一样清晰、简单!
169
+
170
+ 乘热划一下重点,Unify 带来了哪些好处?
171
+
172
+ 1 . ` 统一模块声明 ` :在任何平台下,统一的模块,统一的接口,完全对其,避免实现不一致
173
+ 2 . ` UniModel ` :模块支持声明实体,跨平台生成实体类,无感透明跨端传输
174
+ 3 . 相较于 Flutter Channel,避免了:
175
+ 1 . 手动解析参数已出错
176
+ 2 . Android、iOS 双端难以对齐
177
+ 3 . 大量 Channel 下不易维护
178
+ 4 . 复杂实体序列化管理成本高
179
+
180
+ ## Decision Tree
181
+
182
+ 我们总结了如下决策流程:
183
+
184
+ ![ ] ( ./docs/public/unify-decision-tree.png )
185
+
186
+
187
+ ## More Examples
188
+
189
+ 在 Getting Started 中,给出了最基础、使用场景最多的【原生实现导入 Flutter】。Unify 的能力远不止这些。从简单的单一 SDK 封装,到复杂的企业级 App 大规模模块导出,Unify 都能够支持。
190
+
191
+ 我们通过实例应用的方式,对这些典型场景及业务模式进行介绍:
192
+
193
+ | 案例| 说明| 适用场景|
194
+ | ---| ---| ---|
195
+ | [ 01_uninativemodule_demo] ( https://github.com/didi/Unify/tree/master/examples/01_uninativemodule_demo ) | UniNativeModule 演示| 如何将一个原生模块(Android/iOS双端实现)高效导入Flutter、实现统一调用|
196
+ | [ 02_unifluttermodule_demo] ( https://github.com/didi/Unify/tree/master/examples/02_unifluttermodule_demo ) | UniFlutterModule 演示| 如何将一个 Flutter 模块,高效导入原生(Android/iOS),实现统一调用|
197
+
198
+ ## Documentation
199
+
200
+ 对于更多高级用法,请参见详细文档。
9
201
10
- ## 开始使用
11
202
* 查看文档请参考 [ Unify文档] ( docs/README.md ) 。
12
203
* 想快速体验如何使用,请参考 [ 快速开始] ( docs/02.快速开始/README.md ) 。
13
204
* 想了解 Unify 提供哪些能力,请参考 [ 基础能力] ( docs/06.基础能力/README.md ) 。
14
205
* 想了解 Unify 模块设计原理,请参考 [ 原理概述] ( docs/08.原理概述/README.md ) 。
15
206
* 想了解更多 Unify CLI 的使用说明,请参考 [ CLI 使用教程] (docs/04.CLI 使用教程.md)。
16
207
17
- ## 简单演示
18
- 简单感受一下使用 Unify 开发` UniModel ` 、` UniFlutterModule ` 、` UniNativeModule ` 类型模板。
19
-
20
- | 模板类型 | Unify 模板代码 |
21
- | ---- | ---- |
22
- | UniModel | ![ UniModel] ( https://img-hxy021.didistatic.com/static/starimg/img/pUTEtJURjh1696837559178.png ) |
23
- | UniFlutterModule | ![ UniFlutterModule] ( https://img-hxy021.didistatic.com/static/starimg/img/SSr324LZQ31696836327061.png ) |
24
- | UniNativeModule | ![ UniNativeModule] ( https://img-hxy021.didistatic.com/static/starimg/img/8EPR2HVl6J1696836327036.png ) |
25
-
26
- ## 关联用例
27
- | Demo | 说明 |
28
- | :-------- | :------ |
29
- | example | 项目中的 example 工程是 Unify 创建的完整示例工程,主要实现 ** 《Native 同步定位信息到 Flutter》** 和 ** 《Flutter 向 Native 获取设备信息》** 功能。 |
208
+ > 注:目前我们也在积极整理文档,如果在使用、理解上有任何问题,欢迎提交 Issue 反馈、交流!
30
209
31
210
## 协议
211
+
32
212
<img alt =" Apache-2.0 license " src =" https://www.apache.org/img/ASF20thAnniversary.jpg " width =" 128 " >
33
213
34
214
Unify 基于 Apache-2.0 协议进行分发和使用,更多信息参见 [ 协议文件] ( LICENSE ) 。
35
215
36
216
## 成员
217
+
218
+ 研发团队:
219
+
37
220
[ maxiee] ( https://github.com/maxiee ) ,
38
221
[ zhugeafanti] ( https://github.com/zhugeafanti ) ,
39
222
[ piglet696] ( https://github.com/piglet696 ) ,
@@ -48,4 +231,9 @@ Unify 基于 Apache-2.0 协议进行分发和使用,更多信息参见 [协议
48
231
[ jiawei1203] ( https://github.com/jiawei1203 ) ,
49
232
[ Whanter] ( https://github.com/Whanter )
50
233
234
+ ## Contribution
235
+
236
+ 如果在使用、理解上有任何问题,欢迎提交 Issue 反馈、交流!
237
+
238
+ 欢迎您的交流、贡献!
51
239
0 commit comments