混合开发App架构
目前博主所做负责的App是一个高度混合的App,混合了Web(cordova)、Weex和Native。产生这样的杂交方案有一定历史原因,最早它只是一个单纯的Cordova混合App,但随着项目的迭代,web页面的加载和用户体验不能满足产品的需要,所有引入了Weex。在开发的过程中,已有架构有很多问题,导致各端开发效率和体验都不太好,经过思考,有了此文,以便解决多端开发协作遇到的问题。
App架构概述
为了讲清楚为何要做技术优化,我先从几个不同的角度来讲讲App整体的状况和开发中的痛点。
App启动流程
- App启动,拉取配置中心配置
// 省略了配置中心的模块概念
{
host: 'http://75-up.domain-test.cn',
loginApi: '/api/m/user/login',
homePage: '/api/m/user/getHomePage',
...
sidebarWeex: {
'账户中心': 'http://static.domain-test.cn/sy/project/up-mobile-weex/accountCenter.js?weex=1'
},
sidebar: {
'使用反馈': 'http://73-up.domain-test.cn/vip/m/user/getHomePage#/feedback',
'更多设置': 'http://73-up.domain-test.cn/vip/m/user/getHomePage#/setting'
}
}
- 加载首页,也就是配置中心
host + homePage字段拼接后的地址,并将侧边栏的item显示出来,设置上跳转地址。
痛点
在开发上线的过程中,配置中心给我们带来了无尽的痛
- 不同版本App,配置无法按版本兼容
- 测试环境配置中心只能配到一台测试服务器,无法做到多人协同测试不同版本
- 测试环境配置易出错,导致各种问题,比如:首页是sunyun75,侧边栏是sunyun73,导致token错误,被踢出登录
- 主host只能通过配置中心写入,前端无法连到自己的开发电脑开发,降低了开发效率
- 配置中心只能配置一个host,无法做到多名前端同时真机调试
- 客户端因配置中心导致不必要的复杂度上升
Web(cordova)页面
细心的你可能已经发现了,我们的所有web页面是一个单页应用(single page application),后端吐出的HTML始终是同一个,我们通过前端路由(vue-router)来做的多个页面,也就是利用URL中#后的hash。FE还通过异步路由,解决了首屏JS包过大的问题。
每次提测上线,我们通过脚本,将Web页面引用的静态资源,js、css等发布到公司统一的静态资源服务器。
公司提供了两套静态资源服务,一个带缓存,用于线上,一个不带缓存,用于测试。
// 线上
https://static.domain.com
// 测试
https://static.test-domain.cn
痛点
- 多套测试环境共用测试静态资源服务器,无法同时测试不同版本的web页面。
Weex页面
weex页面打包后实际上也是一个js文件,目前这个js文件也是放在公司统一的静态资源服务器的,和web页面的静态资源一致。
痛点
- 多套测试环境共用测试静态资源服务器,无法同时测试不同版本的weex页面
- weex页面因无法知道当前host,所以无法判断请求哪个环境的后端API
可以说配置中心带来了一系列的问题,从开发体验,到测试流程。而且产品同学还在不断的往配置中心中增加配置,比如加个首页banner图的配置之类的,有配置爆炸的趋势,每次上线弄配置也是如履薄冰。
我理想中的Hybrid App架构
我理想中的Hybrid App,应该是只改写Host就能在一个新环境跑起来的。就像我们在web开发中,服务跑在a.com上和跑在b.com上除了域名以外并没有区别。如果混合开发的App也将配置收敛到只有一个域名(Host),那岂不完美。这样做以后,我们可以在App中留一个配置Host的口,以便测试同学和前端同学修改App当前环境,以便开发和测试。多个人测试不同版本,完全通过域名隔离,互不影响。
结合我们目前的项目状况和可以利用的资源,我提供的方案是这样的
开发阶段,前端将App的Host配置为自己开发电脑的局域网IP,这样所有的静态资源、web页面和API均走前端同学的开发电脑(webpack-dev-server)。
测试阶段,前端通过npm run build:37 && npm run deploy:37将源码打包连同index.html发布到测试静态资源服务器的名为/37目录下,如果并行开发几个版本,测试同学可提供新的测试服务器,例如38,前端只需要npm run build:38 && npm run deploy:38即可。
上线,前端通过npm run build:prod && npm run deploy:prod,打包后的JS、CSS发布到带缓存的静态资源服务器的,将index.html发布到不带缓存的静态资源服务器。
后端需要做的改动
根据当前服务所在的域名抓取对应的index.html并缓存在内存中。简易流程如下
var HtmlPath
if (host为测试环境) {
var 静态资源服务地址 = 'http://static.domain-test.cn/'
var 当前测试环境编号 = 取得当前测试服务器编号,例如37号
HtmlPath = 静态资源服务地址 + 项目资源目录 + 当前测试环境编号 + 'index.html'
} else if (host为正式环境) {
var 线上不带缓存的静态资源服务地址 = 'http://static.domain.com/'
HtmlPath = 线上不带缓存的静态资源服务地址 + 项目资源目录 + 'index.html'
}
客户端需要的改动
移除配置中心,将侧边栏跳转地址等写在App内或由前端控制。Host配置本地化,测试包留口可切换Host。这样Web页面的部分就解决了多人同时开发和测试的问题。
再说Weex页面,Weex页面的地址也要遵循只依赖Host,大致逻辑如下
if (host为IP) {
weexBundleUrl = '从当前IP的9082端口获取'
} else if (host为测试域名) {
var 当前测试环境编号 = 取得当前测试服务器编号,例如37号
weexBundleUrl = 静态资源服务地址 + weex项目资源目录 + 当前测试环境编号 + 'index.html'
} else if (host为正式域名) {
weexBundleUrl = 静态资源服务地址 + weex项目资源目录 + 'index.html'
}
通过这样一个方法,就可以做到通过Host,算出对应Weex页面的地址。
写下这篇文章主要是阐述我对整体架构的理解和针对目前团队结构提出的改进方案
推进整套方案是个漫长的过程,,keep going!!!
现在我遇到的问题大概是这样的,之前公司前端有自己的dev server,所以你怎么去改这个server都无所谓;但是现在node中间层代码取代了dev server,即把两者混在一起。虽然本地的node代码也会去区分环境打到不同服务上,但毕竟是业务代码,所以决定不对这里作任何更改,使用纯mock工具又希望一些接口使用相应环境的服务。所以选择了一种非常笨重的方式---Proxy。基于anyproxy开发的一款强侵入式mock服务,原理也很简单,拦截response,返回mock数据。可以说是为了抓包,顺带加一个mock功能