2015年,是移动领域新技术取得极大丰收的一年。
(一)Android篇
这里我不谈Google IO大会的各种新概念新思想,不谈Android 5.0和高逼格的Material Design,那些都是浮云,热闹过后,能沉淀下来用于App应用的干货并不多。我只谈这一年来,我认为Android技术界最激动人心的三件事。最后再聊一聊八卦。
首先是插件化技术的百家争鸣。在此之前,关于Android插件化的介绍凤毛麟角,Android程序员即使想去研究也无从下手。2015年,几家大的互联网公司陆续开放了自己的插件化编程的项目源码,值得注意的是,各家的实现思想还都不同,各有特色。
1)DL插件化体系
第一个要介绍的是DL插件化框架,GitHub地址为:https://github.com/singwhatiwanna/dynamic-load-apk。
这个框架早在2014年3月就在Github上了,直到2015年才基本稳定下来,开始有越来越多的Android开发人员关注这个项目。它是由“民间”三位Android开发者共同研发出来的,分别是任玉刚、田啸、宋思宇。
这个项目的特色是,通过宿主程序中一个叫做proxy的Activity,去调用插件中的Activity。
以下图片摘取自任玉刚的博客,形象的表达了DL的核心思想:
图片描述
DL框架面临两个棘手的问题:
首先是通过proxy调用插件中的Activity,那么插件中的Activity就是一个普通的类了,不再具有原有的生命周期,为此需要重写插件中的Activity的所有生命周期方法,proxy手动去管理插件中每个Activity的onCreate、onResume这样的方法。
其次是插件中的资源,不能再通过R来访问,为此要重写Context中的getAssets方法和getResources方法。
DL框架最有名的发明创造。莫过于that语法了。在插件中,我们将尽量使用that关键字来替代this。
DL目前还有很多不完善的地方。但据我所知,已经有大型移动互联网公司的Android插件化体系就是基于DL的。
2)Fragment系
https://github.com/mmin18/AndroidDynamicLoader
早在2012年7月,就有大众点评的屠毅敏在Github上发布了一个名为AndroidDynamicLoader的开源项目,这应该是第一个Android插件化的项目,它的亮点在于大规模的使用Fragment来代替Activity。所有的Fragment都运行在一个Activity上,从而在Manifest文件中只事先声明这个Activity就够了,这样就避免了每次新增一个Activity都要修改Manifest文件的尴尬。
2015年也有类似的一款基于Fragment的插件化框架问世,详情请参见以下地址:
博文介绍:http://blog.csdn.net/sbsujjbcy/article/details/47060211
Github下载:https://github.com/lizhangqu/CorePage
3)阿里系插件化体系
阿里其实几年前就在搞插件化编程了,代号为Atlas,只是2015年才把这套技术公布于众。先是命名为OpenAtlas,然后改名为ACDD,最后不知道为什么又把GitHub的地址改为ACDDExtension——其实这3个项目是一回事,相关地址请参见:
OpenAtlas:http://blog.csdn.net/column/details/openatlas.html
ACDD:https://github.com/bunnyblue/ACDD
ACDDExtension:https://github.com/bunnyblue/ACDDExtension
Atlas的亮点在于对R进行分区,从而确保资源相互独立互不冲突。为此,把功夫做足在aapt这个命令层面,需要额外修改aapt中的逻辑,以确保资源分区没有问题。
4)携程
https://github.com/CtripMobile/DynamicAPK
携程的插件化思想和阿里的Atlas有很多相同的地方,由此可见这是一套通用的技术解决方案,所谓的“正统思想”,主要包括以下几点:
1.aapt上的改造
2.gradle上的改造
3.资源ID分区
4.修改Context的getAssets方法和getResources方法,解决R文件的读取问题。
5)对插件本身没有限制的新思路
https://github.com/houkx/android-pluginmgr
看惯了前面的各种插件化技术,细心的朋友是否发现,我们对插件做的太重了,比如说要遵守各种人为的规定,重写aapt指令,资源分区,that语法等等。
这个世界总是太浮躁,让我们静下心来做减法,闭上眼睛思考我们究竟想要什么,而不是各种跟风。是否可以搭建这样的一个Android宿主程序,它可以把任何未经安装、默默躺在SD卡上的apk程序都作为插件加载进来。这样就降低了插件编写的难度。
本篇要介绍的pluginmgr就是这样的思想,作者在试图搭建这样的一个万能的Android宿主程序。
pluginmgrd的核心思想有2点:
一是把插件中所有的Activity都动态生成一个相对应的PluginActivity。启动插件的某个Activity时,先找PluginActivity,再找对应的Activity——所谓的依赖反转的思想。这就不需要把插件中的Activity还要在宿主中的Manifest文件中注册。
二是在启动插件的Activity时,不是通过自己写程序手动去new一个Activity,而是由Android系统来new这个Activity。我们将宿主的ClassLoader替换为FrameworkClassLoader。
注意,所有的插件apk都是不需要安装的,只需要静静的躺在SD卡上即可。由万能的pluginmgrd在运行时将这些apk加载进来。
6)更优雅的修bug:AndFix
https://github.com/alibaba/AndFix
Android插件化是为了解决什么问题?
65536方法数爆棚。
减少apk体积。
不通过发版就能发布新功能
不通过发版就能修复线上bug和崩溃。
但我们经过实践发现,插件化更多的运用于修复线上bug和崩溃。这是一个很轻量的需求,却为此花费了大量的人力和财力去运行这样一套庞大的架构体系,是相当不划算的。为此,2015年github上出现了AndFix,这款Android轻量级线上bug修复工具。
AndFix的核心思想是,把app中的方法B替换为新的方法B ‘,为此,我们把新方法B’所在的代码进行重新打包,并和就的apk包进行差分比较,得到一个差分包,放到服务器提供旧版apk下载,那么apk在接收到差分包后,就会执行新的方法B’了,如下图所示:
图片描述
这类似于iOS的JSPatch实现。只不过Objective-C是一门动态语言,天生就支持这样的特性。而在Android中,则需要修改Native底层了。
在Native底层,有一个dalvik_dispatcher方法负责最终执行哪个方法。就是在这里做一些手脚,把旧方法替换为新方法。
对于功能不是很多的App而言,AndFix是首选,可以快速修复线上bug而不用发新版,而实现成本也很低。对于规模不大的团队而言,相当划算。
这里不得不说到dexposed。dexposed和AndFix都是阿里推出的开源框架,用以解决Android热修复的两种实现,原理两者类似,都是在在Native底层的dalvik_dispatcher方法做文章。但是dexposed有一个硬伤,就是不支持art,这使得很多粉丝转而去投标AndFix阵营。dexposed的github地址为:
https://github.com/alibaba/dexposed
8)360系插件化
https://github.com/Qihoo360/DroidPlugin
纵览了前面的所有插件化技术,你会发现,它们都是基于单进程的。这就是说,插件更新只能等到App重新启动才能生效。
但是我们的用户大都是不懂得如何重启App的。这就导致了插件升级后的更新率并不高,两周时间也就50%的升级率,然后App就又发大版本了。
对于这个问题,360推出了DroidPlugin的插件化技术,它是基于多进程的思想。比如说一个App中有吃喝玩乐4个插件,如果“吃”这个插件有升级,DroidPlugin就可以把正在运行的“吃”的旧版本的这个进程杀掉,然后运行新的插件版本。
目前看起来,对于电商、O2O、OTA这样多业务线、并偏重于闭环的App而言,DroidPlugin是一个终极解决方案。
第二个激动人心的是Facebook开源的Fresco,这是一款强大的图片加载组件,github地址:https://github.com/facebook/fresco。
Android领域最让程序员苦恼的莫过于内存不足够导致的OOM异常了,这大都是由于加载大量图片而没有及时回收导致的。为了解决这个问题,Android有很多专门用于加载图片的组件,比较著名的有ImageLoader、Picaso等,它们只能在Android层面通过及时回收图片资源来缓解Android的内存使用,来减缓OOM的发生频率。
接下来我们说Fresco,它引进了三级缓存的概念(Bitmap缓存、内存缓存和硬盘缓存),它比其他图片下载组件消耗的内存小,就在于这个全新的缓存设计。三级缓存中,尤以Bitmap缓存最亮眼。在Android 4.x和更低的系统,Bitmap缓存位于ashmem中,而不是位于Java的堆(heap)中。这意味着图片的创建和回收不会引发过多的GC。
关于Fresco的更多介绍,请参见Fresco的官方文档:http://fresco-cn.org/docs/index.html
最后,是针对于Android的线上崩溃的收集整理和分析修复。其实收集整理这件事,要么是使用第三方平台的系统,要么是自己做,但是收集到数据并去重后,如果分析这些崩溃信息并修复,是件很棘手的事情。要针对于机型、使用场景,具体问题具体分析,社区上(比如CSDN或Stackflow)针对于每个崩溃信息的分析和修复方案,鱼目混杂,或只言片语,或空穴来风,要逐一订正是件很费神的事情。
我曾经试图来整理这些崩溃的原因和修复方案,耗费半年时间,也才完成84个(可以参见《App研发录》第6章)。就在我干这件事的同时,腾讯有一个团队Bugly也在做类似的事情,他们在11月搞了这样的一个活动“腾讯 Bugly Android 异常案例解决方案征集”(活动的详细地址参加http://www.oschina.net/news/67914/tencent-bugly-projects),试图通过社区的力量来建立一个Android的崩溃仓库。天地万物皆有时,崩溃仓库在2015年只是一个萌芽,能否做大做全,我们期待2016年。
前面说了Android太多普大喜奔的事情,接下来说一说Android在2015年遇到的一个安全问题。
我敢打赌说,大部分公司的Android项目,会为了方便,而把签名密钥放在了项目中,所有开发人员都可以看到。随着这几年开发人员的流动,密钥已不再是密钥了。
把密钥从项目中移除,保存在1-2个人手中,是个不错的办法。但是仍不能避免之前的同事手中握有这份密钥。密钥一旦被流传到市场上,就会有不怀好意的人在原先的App加一些恶意的功能,然后重新签名。
更换密钥吗?这是个馊主意,这会导致生成一个新的App,而不再是原先的那个App了。
其实这个问题早就存在,只是现在才摆上台面而已。目前还没有更好的解决办法,也只能缩小直到密钥的人员。
末了插播一条新闻。2015年6月,Google宣布将在年底前停止对Eclipse Android开发工具的一切支持,从此我们只能使用Android Studio开发Android。对于一个使用Eclipse3年的开发者而言,我感到非常不适应。相信和我有相同感受的朋友不在少数。从此,Gradle成为标配。
ADT的没落完全是咎由自取,自身的不努力,导致Google不再花费时间和精力去支持。这样也好,集中精力先把一个IDE做好,目前看起来,Android Studio比微软的Visual Studio还差很多很多。
热门评论
不久前看过一篇跟这一样的
实用的文章,赞一个
hao