介绍
native-adapter是一套开箱即用,易于拓展,无需引入多余代码的多环境适配框架 。目前涵盖转转app、找靓机app、m站、微信浏览器、微信小程序、qq、qq小程序、百度小程序、快手小程序、头条小程序、采货侠app等多种环境。
旧的方案
主要是以适配器模式的设计架构,前期平台较少的情况下,扩展和兼容比较灵活。随着适配平台的增多,不断地增加平台代码,没办法按需引入,最后导致包体积会越来越大。
面临的问题
native-adapter作为团队基础库中最重要的一个,在近几次的基建问题收集时,反馈native-adapter问题的不在少数。经过业务反馈和调研,主要问题如下:
-
包体积大,无法按需引用
-
缺少demo,不方便测试
-
文档不友好,使用成本过高
-
代码没有采用ts,不支持API调用提示
针对以上问题,经过梳理和评估,确立以下目标:
- 新增测试demo,独立测试每个方法
- 重构文档,提供完善的API说明与测试二维码等
- 多端方法一致性兼容,产出多端兼容参考文档
- 升级代码为插件架构、支持TS
- 优化代码,精简逻辑
架构升级
对社区一些开源包的调研,发现针对包体积大,无法按需引用 这个痛点,基本上采用的是插件化架构。在此借鉴了一下BetterScroll插件体系以支持按需引用。
新的架构特点
- 架构更加清晰、分为核心层和插件层。
- 插件继承关系更加简洁
- 扩展灵活,升级为插件化,支持按需加载和全量加载
目录
├── src
│ ├── all.ts // 全量包入口
│ ├── core // 核心
│ │ ├── conf.ts // 暴露的api方法
│ │ ├── index.ts
│ │ ├── native.ts // 核心插件化实现
│ │ └── utils // 工具方法
│ │ ├── ajax.ts
│ │ ├── compareVersion.ts
│ │ ├── cookies.ts
│ │ ├── events.ts
│ │ ├── index.ts
│ │ ├── urls.ts
│ │ ├── util.ts
│ │ ├── waitJsLoaded.ts // 进行异步加载初始化sdk和调用队列
│ │ └── wxAuth.ts
│ ├── index.ts // 核心包, 包括m站,转转app、找靓机app、微信浏览器、微信小程序、qq等
│ └── plugins
│ ├── base // 基础adapter
│ │ ├── BaseAdapter.ts
│ │ └── LoginAdapter.ts
│ ├── buildIn // 内置核心adapter
│ │ ├── QQAdapter.ts
│ │ ├── WechatAdapter.ts
│ │ ├── WechatMPAdapter.ts
│ │ ├── ZLJAdapter.ts
│ │ └── ZZAdapter.ts
│ ├── external // 扩展adapter
│ │ ├── BaiduMPAdapter.ts
│ │ ├── GAdapter.ts
│ │ ├── KrakenAdapter.ts
│ │ ├── KuaishouAdapter.ts
│ │ ├── QQMPAdapter.ts
│ │ ├── ToutiaoAdapter.ts
│ │ ├── WubaAdapter.ts
│ │ ├── ZZHunterAdapter.ts
│ │ ├── ZZSELLERAdapter.ts
│ │ └── ZZYigeAdapter.ts
│ └── index.ts
实现过程
-
逻辑解耦,把每个适配平台的代码整合到插件文件中去,不和核心逻辑耦合,增加可维护性。
-
baseAdapter作为最小的adapter,其余的平台都基于baseAdapter来扩展
-
充分利⽤了 TypeScript 接⼝⾃动合并的功能,让开发者在使⽤某个插件时,能够有对应的 native能够有对应的⽅法提示
// ZZAdapter platform static platform = [ { rule: /58ZhuanZhuan/g, name: 'zz', scheme: 'zhuanzhuan://' }, { // 找靓机新webview rule: () => /zhaoliangji-v2/g.test(navigator.userAgent) && (getUrlParams().needNewWebview == '1' || getUrlParams().needNewWebView == '1' || compareVersion(getCookie('v'), '9.1.10') >= 0), name: 'zlj', isNewWebview: true, }, // 转转门店 { rule: /zzstore|offlinestorecomplex/g, name: 'zzstore', }, // 上门超人 { rule: /zzupdoor/g, name: 'zzupdoor', }, ]static use(ctor: PluginCtor) { const name = ctor.pluginName const installed = NativeConstructor.plugins.some((plugin) => ctor === plugin.ctor) if (installed) return NativeConstructor if (isUndef(name)) { console.warn(`插件必须有一个静态pluginName字段`) return NativeConstructor } NativeConstructor.plugins.push({ name, ctor, }) return NativeConstructor }NativeConstructor.plugins.forEach( (item: PluginItem) => (this.pluginsMap[item.name] = item.ctor) ) Object.keys(this.pluginsMap).forEach((key) => { const Ctor: PluginCtor = this.pluginsMap[key] let currentPlatform = this.getCurrentPlatform(Ctor.platform) if (currentPlatform) { // 实例化plugin时会注入当前this,即native实例 this.plugin = new Ctor(this as unknown as Native) this.currentPlatform = currentPlatform } }) // plugins没有匹配到平台、默认匹配baseAdapter if (!this.plugin) { let currentPlatform = this.getCurrentPlatform(MAdapter.platform) if (currentPlatform) { this.currentPlatform = currentPlatform } this.plugin = new MAdapter(this) } -
利用静态方法use进行注册 Native.use(ZLJAdapter).use(ZZAdapter) , 每个插件内部含有一个或者多个匹配规则不如上面匹配ZZAdapter, Native在内部通过Platform判断匹配到的规则执行相应的组件实例
灵活的包使用方式
// 核心包:包括m站,转转app、找靓机app、微信浏览器、微信小程序、qq
import native from '@zz-common/native-adapter'
// 全量包:包含插件中所有平台
import native from '@zz-common/native-adapter/es/all'
// 按需加载, 已经默认包含核心包,可以扩展qq小程序、百度小程序、快手小程序、头条小程序、采货侠app、Kraken等
import { Native } from '@zz-common/native-adapter'
import QQAdapter from '@zz-common/native-adapter/plugins/external/QQAdapter'
Native.use(QQAdapter)
let native = new Native(options)
API方法提示
参数提示
完善demo
完善文档
总结
本次代码升级和优化一方面使得代码维护更加简单清晰,趋于稳定。另一方面对代码进行的瘦身和优化使得核心包代码体积减少了40%左右。同时文档和demo对使用人员来说,更加方便快捷,提高了集团内开发人员的效率。