你知道途牛 Android 客户端架构是怎么优化的吗?

xrjk5290 8年前
   <h3>途牛APP的故事</h3>    <h3>成长</h3>    <p>途牛APP经历了诞生、发展、升级和优化的阶段,系统越来越稳定,功能越来越丰富,技术架构越来越完善。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/9088b62df624a982be17ae3c1c401fc3.jpg"></p>    <h3>团队</h3>    <p>团队的规模从最开始的2个人扩张到100人左右,APP的功能也是越来越丰富。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/2e8e18f0cb95a7897d180e78b532cd8e.png"></p>    <h3>行业表现</h3>    <p>当前途牛app的行业表现如下:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/0ebde8408cf2ac9e07b76ee96b80b15a.jpg"></p>    <h3>产品演进</h3>    <p>产品界面原型从 2013年(左图)的简单,到2016年(右图)的复杂。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/af953c233a827aa03eeb86b9ec7b542f.jpg"></p>    <h3>架构演化</h3>    <p>想象一下:“在你的面前有一堆代码,耦合很严重,堆在一个仓库里,质量很难控制,然后团队规模迅速增大,功能越来越多,代码堆砌速度很快。”</p>    <p>是不是有种快要失控的感觉?</p>    <h3>架构的背景</h3>    <p>最早无线中心包含自助、门票、跟团、酒店等业务,随着公司规模增大,按照垂直业务划分了机票、酒店、交通等事业部。同时也带来了一个问题, <strong>什么样的架构才能比较好的支持不同团队的协同开发?</strong></p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/7f5883385baa83b20ccc38fef4a7ad52.jpg"></p>    <h3>机遇和挑战</h3>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/062c1174753d7aaa24cc302171d573b8.jpg"></p>    <p>随着团队人数增多,团队的拆分,给途牛APP架构带来了一些机遇和挑战。</p>    <p>我们的 <strong>机遇</strong> 包括:</p>    <p>第一,各个业务线可独立开发,从提高开发的效率;</p>    <p>第二,可总结沉淀一些公共组件,为不同的业务团队提供服务;</p>    <p>第三,搭建业务公共平台,例如打点、性能监控。</p>    <p>我们的 <strong>挑战</strong> 包括:</p>    <p>第一,项目之间的业务存在横向和纵向的耦合,业务之间存在相互调用,业务和底层library也存在相互调用,成网状的调用方式;</p>    <p>第二,项目中存在部分重复的代码,例如,不同的业务相同的功能,城市选择,存在两份代码;</p>    <p>第三,项目未沉淀一些平台化的产品,需要抽象独立出来,以SDK的形势提供给各个产品或业务线使用。</p>    <h3>解决问题</h3>    <p>解决问题的思路是拆分,重构项目。 <strong>那如何拆分是比较好的拆分方式呢?</strong></p>    <p>我们可以把 独立性强的业务抽离出来 ,从而独立开发、优化以及维护,公共的部分可由架构团队统一管理和维护。</p>    <p>抽象、隔离、解耦各个业务线,以什么方式进行?</p>    <p>我们采取了 插件方式 把各条业务线独立开来。</p>    <h3>什么是插件?</h3>    <p>插件是一个apk或者dex文件,无需安装就可运行,插件好处有动态加载,增量更新,业务隔离。</p>    <p>插件拥有 两种 思路:</p>    <p>一种是静态代理的方式,通过主app的组件代理插件中的组件;</p>    <p>另外一种是360公司研发的动态hook的方式,主要原理是hook系统的API从而实现插件的运行。</p>    <p>经过团队的调研和分析,我们的项目比较适合 静态代理的插件 思路。</p>    <h3>下面简单演示一下静态代理的方式:</h3>    <p>主APP中有个ProxyActivity的模块,这个Activity具有基本的生命周期,插件的PluginActivity不具有生命周期的概念, 通过ProxyActivity中插件PluginActivity的引用来实现 ProxyActivity的生命周期对插件的PluginActivity的代理。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/9ee86279cfeb66a4e9b9528feaf38030.jpg"></p>    <h3>插件要解决的几个重要问题:</h3>    <p>一个是资源加载的问题,另外一个是dex代码加载的问题。</p>    <p>通过分析系统加载apk的源码,发现 资源加载的核心方法 是addAssetPath,由于此方法没有公开,通过反射的机制可以获取方法并且调用,解决插件资源加载的问题。</p>    <p>AssetManager <strong> instance = AssetManager.class.newInstance(); </strong></p>    <p>Method addAssetPathMethod=</p>    <p>AssetManager.class.getDeclaredMethod(</p>    <p>" addAssetPath <strong> ", String.class); </strong></p>    <p>addAssetPathMethod.invoke(instance, apkPath);</p>    <p>由于插件代码都打在dex文件中,代码的加载可以通过系统提供的DexClassLoader来完成。如下所示的核心代码, 解决插件的calss加载问题 。</p>    <p>DexClassLoader   pluginClassLoader = new DexClassLoader(dexPath, optimizedDirectory,libraryPath, parentClassLoader);</p>    <p>选定插件的静态代理的基本设计思想后,可实现 插件的底层框架 。</p>    <p>途牛app的插件框架包括:</p>    <p>调度引擎,bridge模块,性能监控,日志系统,增量更新和安全校验。</p>    <p>调用引擎 负责插件的拷贝,加载策略等核心问题;</p>    <p>Bridge 负责插件之间、以及插件和主app之间的沟通;</p>    <p>性能监控 主要是监控插件的加载和运行时的加载时间、页面耗时、接口耗时等性能数据;</p>    <p>日志统计 负责纪录插件系统内的用户行为,以便产品策略的优化;</p>    <p>增量更新 负责插件的动态加载更新,包括下载、合并等环节;</p>    <p>安全校验模块 负责插件 的安全,主要职责是插件的本地校验。</p>    <h3>插件系统的编译要采取provided的形式。</h3>    <p>由于插件是动态加载到主app中的,对于library的引用,采取provided方式,即不用把library代码打进插件包中。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/2f600dd6175306c25d39d9e0a8951adb.jpg"></p>    <h3>插件的采取分级调度策略,分为1,2,3优先级。</h3>    <p>优先级为1 的插件在应用启动时,就开始加载;</p>    <p>优先级2 的插件在首页 渲染完成后,开始加载;</p>    <p>优先级3的插件,在首页加载完成后,延迟加载。</p>    <p>插件的加载要收口,所有的插件加载 都是异步的方式,加载成功或失败通过回调来通知调用者。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/2910919359ac7e46a9850d2170eb010f.jpg"></p>    <p>想知道我们在实践中遇到问题是怎么解决的吗?</p>    <p> </p>    <p> </p>    <p>来自:http://mp.weixin.qq.com/s/CfPlVKElv2SshAbfzHfRhg</p>    <p> </p>