简介
MIST 是口碑团队研发的一套高性能的 iOS 动态化解决方案,2016年最初被用于开发支付宝 App 的 O2O 业务,因其开发速度快,无需发版的特性迅速得到了众多业务团队的青睐。MIST 经历了日常百万 UV 的考验,在双 12 等大型活动中经历了千万 UV 的洗礼,目前已经足够稳定,部分代码已经开源。本人(kyson.cn)在蜂鸟配送个人中心页面使用了 MIST 技术。
需要注意的是,饿了么内部使用的 MIST 和对外开源的版本差别比较大,后者目前处于几乎无人维护的阶段。如果贵公司没有足够的人手,不建议大家贸贸然上 MIST。
尽管如此,也不建议大家立刻停止阅读接下来的内容,MIST 的代码还是有一定的研究价值的————他的可以实现 H5 来编写 iOS 界面,这点类似 Android 的 XML。相信很多 iOS 开发人员都很羡慕 Android 的 XML,他的效率比 iOS 的 Hard Code 高多了。
MIST 的另外一个特性是支持动态下发。他只需要一个 json 文件就可以渲染整个页面,我们只需要把 json 放在服务器,在合适的时间下发到本地即可。
废话不多说,我们现在就开始研究一下他!
集成
MIST 的 github 地址在这里:https://github.com/Vizzle/MIST,我们注意一下这个 Vizzle 用户,他下面还有几个仓库分别是:
- VZFlexLayout : MIST 的底层实现
- Vizzle : iOS MVC Framework
- mistcmistc: MIST 组件编译工具
编译运行
git clone 到本地后,目录如下:
双击 MIST-Demo.xcworkspace
打开工程,编译运行,我们可以在模拟器或者真机上看到主页面:
代码分析
我们先看一下仿微博 timeline 这个 demo:
然后看代码实现(WBTimelineListViewController 中的 load 方法):
- (void)load
{
[[MistDemoTemplateManager defaultManager] downloadTemplates:@[@"WeiBo"] completion:^(NSDictionary<NSString *,NSString *> *templates) {
NSString *path = [NSString stringWithFormat:@"%@/mist.bundle/WeiBo.json", [NSBundle bundleForClass:self.class].bundlePath];
NSData *rawData = [NSData dataWithContentsOfFile:path];
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:rawData options:NSJSONReadingAllowFragments error:nil];
self.data = [data[@"statuses"] copy];
self.items = [self itemsWithData:self.data templates:templates];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
} options:nil];
}
可以看到其主要是加载了本地的 WeiBo.json
文件,为了验证UI数据是否来自该文件,我们把 “新浪科技” 改成 “kyson.cn”, 重新编译看一下效果:
果不其然,用户名改了,这验证了我们的第一个假设: UI的数据来自 json 文件
接下来,我们进入MistDemoTemplateManager
的 downloadTemplates
方法内部,一探究竟:
//@Important! If using the local templates, this method will be hooked by MistDebugger
- (void)downloadTemplates:(NSArray *)tplIds completion:(void (^)(NSDictionary<NSString *, NSString *> *templates))completion options:(NSDictionary *)opt
{
__block NSMutableDictionary<NSString *, NSString *> *results = [NSMutableDictionary dictionary];
__block NSInteger count = 0;
for (NSString *tplId in tplIds) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *tplPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"mist.bundle/%@", tplId] ofType:@"mist"];
NSString *result = [[NSString alloc] initWithContentsOfFile:tplPath
encoding:NSUTF8StringEncoding
error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
++count;
[results setObject:result forKey:tplId];
if (count == tplIds.count) {
if (completion) {
completion(results);
}
}
});
});
}
}
不难发现,他加载了 WeiBo.mist
文件。同样的,我们改一下 WeiBo.mist
文件的内容,也不难发现, UI 的布局来自 mist 文件
总结
FlexBox布局算法:MIST内部实现了CSS3 FlexBox的标准布局算法,作为模板布局的核心能力;对比现有的FlexBox算法(RN, Weex), MIST支持的属性更完整,灵活性更高 ;算法采用C语言实现,无运行时的性能损耗
高效的语法解释器:MIST内部实现了一套功能完备的语法解释器,支持基本的数学运算、逻辑运算、比较运算、条件表达式等;此外,MIST还支持OC类方法的调用作为对Native通信能力的补充
UI异步绘制:MIST对UI底层渲染做了深度优化,对模板内的UI元素支持整体的异步光栅化绘制,可以极大的提升FPS,使页面具有更流畅的滑动体验
React:MIST将React.js的思想移植到了客户端,使用Objective-C++实现了一套Native版本的React。因此MIST底层也具备和React相似的运作机制,包括Virtual Dom结构,使用Immutable数据和One-Way data flow等。MIST模板在此之上进行了一层抽象,使开发者不需要理解上述概念,也不需要关心具体的实现细节,降低上手门槛