大主线
细说移动开发历程
大技术
组件化开发
组件配置动态加载
组件骨架架构
插件化开发
静态插件化
动态插件化
细节雕琢
网络层的优化和架构
动态埋点的实现
技术层架构(MVP,MVVM等模式)
大天地
后续按照大技术块各个技术点深入浅出的分享出来,请订阅关注。
后续文章列表:
前言
本文阅读需要8分钟。
你可能的收获:
理解整个公司移动开发的基线和主线
学会移动开发组开发过程碰到问题和解决方案
学会移动开发过程各个技术的细枝末叶
希望能给读者开发项目有点启发和思索
正文
我理解的技术开发人员,除了业务和技术的热爱,其同时也需具备独立思考的能力。
在这个高速变换的二次元移动开发时代,很多产品和公司应付追赶日新月异之变化都是争分夺秒攻城略地,伴随而来的移动研发也是进随着'敲锣打鼓开天辟地'。
所以我们有必要分析和思索当下移动开发的周期,就个人理解则把移动开发生命周期分四大周期,这个四个周期同步伴随着公司发展整个过程。
这个四个生命周期分别命名为:
1.成长期
2.混沌期
3.统一期
4.分化期
成长期一般在公司的第1~2年;
混沌期一般在公司的第2~3年;
统一和分化期在公司第3年以后;其中统一和分化期有可能多次迭代进行。
所谓的成长期,也就是传说中的野蛮发展,此时公司主导方向快速迭代跟进市场,作为研发里程以及人员数目这块都是从无到有的过程,其宗旨也是开发追赶产品实现快速上线过程。
此时开发技术选型都是以个人因素为走向,因此前期项目选型和架构都是个人技术喜爱占主导,自己熟悉的技术和框架才是最快最有效的,可以快速追赶上线进度。
譬如喜欢rxjava,喜欢mvp模式很快就会在这个项目就起主导方案和技术架构.甚至有些开发同仁直接从网上所谓架构好的现成项目开干怼。
此时段公司的唯一宗旨就是首战市场产出产品,快速迭代占据每个开发人员的脑海中,细节等一切可以忽略,要啥自行车。
接下来,随着公司业绩第一枪打响,同时融资也下来了,开始招兵买马大干一场,人员补给上来,开始出现混乱和磨合期,新来人员觉得老代码就是一坨翔,各种心底鄙视和不爽;
老员工觉得新员工桀骜不驯啥都不懂喜欢装逼。但是公司补给人员的目的是更加快速迭代项目,公司还动不动搞个什么敏捷开发鬼模式实现1~2周迭代一个版本(就喜欢搞事)。
需求继续开展代码还得迭代而新老开发人员依葫芦画瓢编写代码,慢慢的(可以N个),慢慢的过段时间发现代码充斥各种耦合,不规范代码,文件包混乱,业务各种穿插,
一句话混乱的一锅粥,各种线上bug突突的冒出来;线上bug一统计,fuck指标超过5-10%,开始全组上下静心反思,产生出版本重构迭代统一思想。
项目重构功能改善等统一口号就出现了,此时一般分两波人马,一拨人马继续业务迭代而另外一波人马进行项目重构;此事的核心就是减少线上bug数的量级,
完成公司要求线上bug不能超过3%的指标,这个时候重构重点基于线上bug进行维度分析,通过问题按多少进行划分,差不多这个时候的问题如下:
1、Bug的可视化实时监控和统计;
2、引用内存未释放导致crash的bug;
3、内存泄漏导致crash的bug;
4、进入市场机型问题引起的bug;
5、网络访问慢的反馈;
6、奇葩未知的bug;
7、。。。
问题1的思考,引入第三方系统,例如bugly等
问题2的思考,引入Eventbus解决回调地狱问题和回调引起泄漏未释放问题;
问题3的思考,引进LeakCanary内存泄漏检测,和prof分析大法根据各个问题进行突破;
问题4的思考,无解,能解决一个是一个,主要公司机型跟不上,可以通过网上机型提供商进行问题测试,贵不说而且感觉没啥用;
问题5的思考,略;
关于公司指定的线上bug指标,是否完成也是需要多版本迭代现网运行后才能统计;既然是现网bug就有轻重之分,如果重大bug一般立即发布新版本更新,轻微的bug放到下一个版本迭代修复,那有没有现网bug热修复方案,肯定有的,成熟的有tinker等第三方库;
虽然以上问题加班加点的搞完后,但是随着公司业务的发展和市场的强大推广,多个业务线如雨后春笋一般立项开干,看着当前项目架构模式(如图一)
图(一)
长叹一声,埋在心头的那个一个极大隐患和不安慢慢露出来,项目中依旧充斥代码各种耦合和混乱,加上‘混乱代码加上新代码依旧还是混乱代码’定理一直压着头顶上,这项目框架肯定无法跟上公司新业务线的发展和规划;有压力就有动力,深思熟虑后不知觉分层分模块架构慢慢浮现出来,每个业务线都是一个Module模块,接下来每来一个业务线就按照这模块模样复制粘贴一份接着开怼业务。一般这种情况需要持续到三个业务线后基本就会出现模块间混乱调用,资源文件各种重复且代码到处飞,加上权限控制不到从而每个人都有权限编写基础库从而使各个业务公共代码下沉到基础库导致庞大臃肿,多模块混合编译速度极度慢等不良问题一大堆冒出来,回过头看看项目现状,我去,又来了,忙不完的事。看看图二(偷图,侵图删)如果你把自己当处女座,你肯定会发狂,要么炒老板鱿鱼要么静下心思考分析。
图(二)
分析后得出以下几个急需解决的问题,
1. 模块间的调用进行解耦合实现模块热拔式方案
2. 是时候加上代码权限管理
3. 模块打包AAR实现模块间引入
4. 解决编译速度慢问题
5. 自动化打包问题
6. 。。。。
问题1的思考,既然实现解耦合同时实现热拔式方案,说白点就是当前模块开关关闭,被其他引用的模块无法感知到这个模块被关闭,即其他模块引用的代码必须不能硬编码此模块的方法和引用类等等,方案就是组件路由,调用方通过字符串path查询模块的服务和功能。
问题2的思考,代码权限管理一般通过git或者svn去实现。
问题3的思考,可以通过gradle脚本实现模块打包上传私服。
问题4的思考,gradle本身问题加上模块多导致编译速度慢,根据业务线的独立性那我们可以通过编写业务模块时给此模块实现App模式,减少其他不必要的代码编译和运行。实现方案大体如下:
在模块gradle编译脚本通过标识符来区分是模块还是可独立运行的App
sourceSets {
main {
jniLibs.srcDirs = ['libs']
if ("true".equals(FINANCE_IS_APPLICATION)) {
manifest.srcFile 'src/main/diff/appmodule/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/diff/appmodule/java']
res.srcDirs = ['src/main/res', 'src/main/diff/appmodule/res']
assets.srcDirs = ['src/main/assets', 'src/main/diff/appmodule/assets']
} else {
manifest.srcFile 'src/main/diff/libmodule/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/diff/libmodule/java']
res.srcDirs = ['src/main/res', 'src/main/diff/libmodule/res']
assets.srcDirs = ['src/main/assets', 'src/main/diff/libmodule/assets']
}
}
}
这样我们需要单独运行此模块,在gradle.properies把FINANCE_IS_APPLICATION为true然后编译就可以实现业务代码编写和运行。有人问,如果我需要实现主App里面的新业务,那你可以关闭其他无关的模块实现快速编译提高开发效率。
问题5的思考,随着项目的增大和多渠道的打包,此时需要进行考虑项目周边的业务服务,例如提供给测试人员的打包测试,正式版的发布等等自动化产出问题。
一般自动化服务可以通过搭建jenkins服务,或者配合python脚本实现自动化打包功能,其
脚本的功能因公司而异。
图(三)
所以此时迫切需要一个熟悉gradle,python等脚本的同志(gradle本身是grovvy语言)。保证新业务的开发的情况下整个过程的重构和完善至少需要半年时间(大公司除外)。
慢慢发现,组件化架构无声无息的出现了,是不是很神奇。
回过头发现组件化架构已经进行了一小部分,信心十足,继续干,此时必须祭出毛爷爷的红本子,大声的朗读出来,我爱编程,皮肤好好!!
我们发现已经做了业务模块化代码分离和模块间路由互调通信以及gradle组件化脚本;
你的成长是建立在公司的成长上,随着公司业务发展庞大,种种缘由业务伴随着也会出现分支独立,需要某些子业务线独立出App提供专业的服务和体验;需要撒播种子开花结果,原先的子模块可能变成独立App,所以发现目前的架构是没法实现,对,走过来,请在菩提树下思考;其根本缘由就是组件化不完全导致的。其中最大问题就是主项目模块涉及到大量的以前最早的业务代码和功能,现在最迫切问题是需要把主项目的业务剥离变成一个业务子模块加一个纯粹的项目骨架,其中项目骨架必须上升一级变成新的主项目模块,此主项目模块包含项目公共业务。说白点,把项目骨架套在其他子模块就是一个独立的App可以运行;
作为对比,图四为原架构图,图五为主项目模块上升一级为项目骨架的架构图
其中主项目骨架必须包含的功能有:
1、项目升级降级功能;
2、第三方库的引用和初始化工作;
3、实现子模块加载和引入以及初始化工作;
4、周边服务或插件的引入和初始化工作;例如Tinker和bugly等
5、。。。
图(四)
图(五)
这个时候组件化大体已经完整成型,现在唯一需要做的就是通过gradle脚本去做粘合器,脚本配合jenkins动态实现模块间和主项目骨架的组合;
上面说的组件化成型是主体骨架完整了,但是需要根据自己的公司业务继续进一步解耦和分离,一般如:
1. 全局配置文件的分离,实现配置文件根据子模块业务走,例如网络地址的配置和网络请求地址的分离;
2. 业务配置文件的分离,配合服务端一起实现模块化分离;
3. 各个子模块的公共业务动态加载块;
4. 耦合代码的分离和重构;
5. 。。。
此过程应该做到了项目模块以及代码的各种解耦和分离,看起来非常清爽和干净。不知觉又开始唱起了:我爱编程,皮肤好好!!
突然有一天你听到有人说插件化,你心里暗暗一笑,我们项目早就实现了热拔式插件化;
一讨论发现原来不是你想的插件化,他们说的插件化是把业务模块动态存放到网上,需要的时候加载进来;
哇咔咔,原来插件化分两种,一直静态插件化和动态插件化;
不知觉的发现我们已经实现了静态插件化功能,细水长流说的就是这个,哦,应该是水到渠成;
动态插件化的前提必须是项目已经具备成型的组件化后才能实现动态插件化功能。
目前已经可以独立出各个子模块打包成AAR、JAR、APK;接下来就是需要在主项目骨架上添加一项动态插件化功能;完美
现在动态插件化市面上有很多成熟的方案,因为这个不像组件化过程,组件化其实本身和业务和项目有很大关联,需要根据自己的业务以及已有的业务框架进行加工和架构实现;而
动态插件化实现机制和业务体系和自身架构无关系,可以大胆的引入第三方成熟的插件;例如美团公司,阿里公司的动态插件化。
其实,回味下整个过程,发现这些都是一步步的走下去的,不可能一步到位,这才人生;
有人问是不是接下来高枕无忧,哈哈,too x too native, 这才是万里长征前几步而已,接下来需要细节上和技术上进一步雕琢,周边服务的完善和安全等配套实施都需要等你去实现;路遥茫茫。。。
细节上雕琢随便列举几个:
1、例如上面提到的bug中出现网络性能慢,这个就可以深入挖掘各个实现,例如腾讯就这个小点实现了Mars开源框架;
2、业务UI框架的封装(减少重复开发以及性能问题);
3、性能监控;
4、配置管理中心;
5、动态埋点;
6、各个业务核心点的优化;
7、编写的组件化的重构和优化;
8、技术层架构(MVP,MVVM等模式)
9、分布式架构;
10、。。。。
最终你会发现,很多功能只有在你组件化结束后或者插件化结束后再去实施会达到事半功倍效果,实现集中优化改动分布最小化,极大减少改动的风险和bug风险;
以上过程其实是一个分久必合合久必分的过程。当项目走向做到极致的时候还是没法应付庞大用户群和业务群,请转行养猪。。。
网络层架构实现,源码详见,觉得好请点击star:我的网络层
路由组件化框架实现,源码详见,觉得好请点击star:我的路由
最近有很多同仁@我后续更新 情况, 真心谢谢大家的关注,最近家里我爸脑出血目前没时间更新后续文章,等一段时间后慢慢把整个涉及到的方方面面的技术点和经验分享补上来,再次谢谢大家关注!