Luis von Ahn这个神人

p19930693

前面的话

上次看了Fenng的一篇文章,大意说的是拥有较好的写作能力能够帮助自己更好的去思考,看了之后自己挺认同的。

我对自己的写作能力还是相当悲观的,你要知道我是那种高中写作文第一件事是找到800百字的位置,做个标记,然后开始了挤牙膏似的向那个『800百字』标记进军的人;大学每年的学年总结我都是照着标准格式来填的。本身就烂的底子再大学这七年的荒废,可想而知现在我的写作水平到了哪个境界了?所以我写这个博客有一部分原因也是想借此提高自己的写作能力。现在我决定用“随想”这个类别来写一些我觉得有趣、好玩的事情、东西或者人,涉及的领域可能五花八门。

恰好之前我在北京实习的时候,公司要求每个人每周都要进行一次分享,内容不限,当时轮到我的时候,我就向大家分享了一下Luis von Ahn这个人以及他所做的事情。那我今天就把之前的那个分享在充实一下,遂作此文。

验证码

看到CAPTCHA这个单词你熟悉么?嘿嘿,估计我们在编程的时候见过。其实它不是一个单词,它是一个缩略词,它是取 Completely Automated Public Turing Test To Tell Computers and Humans Apart 这几个单词的首写字母组成的(其实我也是刚刚搜出来的)。它翻译出来其实还挺拗口的,叫做全自动区分计算机和人类的图灵测试。

CAPTCHA其实在我们的网络生活中是随处可见,几乎每天都会碰到它。基本上我们所有的网站登录界面都会用到它。没错!它就是『验证码』。所以,验证码还有这个洋气的名字,叫做『全自动区分计算机和人类的图灵测试』。说到这个验证码,我们不得不来了解一下这个验证码背后的男人——Luis von Ahn。

验证码背后的男人

Luis von Ahn是一位卡内基梅隆大学的副教授,他其实最开始是研究加密的,后来开始研究如何区分在网络中人和计算机。

你可以想象一下在Luis von Ahn之前没有验证码的日子吗?买票的网站因为没有验证码几万张票被黄牛通过刷票程序全部买走?网站被人一次性注册几百万个垃圾帐号,然后产生各种垃圾信息,还可以操纵投票,使网站失去了公正性。

这还只是举了简单的几个例子。没有验证码的日子网络世界一片狼藉。Luis von Ahn觉得自己应该可以做点什么,要知道他是研究如何区分在网络中人和计算机的。上面两个例子就是因为有人使用计算机非法的对网站进行操作。

于是Luis von Ahn就想如果我能把人和计算机分开就好了,刚好他的研究里面就有一个方法可以区分计算机和人,那就是人可以用肉眼很容易的识别出图片里面的东西,但是计算机不能。Luis von Ahn就利用这个特性发明了CAPTCHA,也就是『全自动区分计算机和人类的图灵测试』,也就是『验证码』。

那么验证码是怎么让杜绝那些计算机对网站进行非法操作呢?很简单,首先计算机是可以像人一样去模拟登录的,但是当它碰到验证码的时候,计算机就傻眼了,它不认得这个验证码里面是什么东西,但是人的话就一眼认出来,然后输入验证码,就通过啦。就这么简单。人和计算机就被区分开来了。这个小小的发明为世界上的所有网站拦截了大部分的恶意注册和垃圾信息。

游戏还可以这样玩

其实在这之前 Luis von Ahn还有一个研究领域就是如果利用人在上网过程的中作用,说简单点就是如何让人在上网的同时不知不觉的还完成了一些不可思议的事情。于是他基于这个研究开发了一个图片游戏,这个游戏的玩法就是给任意随机的玩家A和B发送同一张图片,然后要A和B在有限的时间内对这个图片进行描述,当这个两个人的描述接近的时候就算这两个人匹配成功,然后获胜得分。

你能想到人在玩这个游戏的时候不知不觉的完成那些任务了么?就像上面说的那样,计算机是很难识别图片,但是人就可以很简单的识别图片,并对图片进行描述,于是乎,人们在玩这个游戏的时候不知不觉的就对这些图片进行了相当精确(因为是两个人同时在想,而且限时,而且必须描述相近)的标记。哈哈哈,想法是不是相当高明。认为这个想法高明的不止有你,还有当时的搜索巨头Google(谷歌)。Google当时就收购了这个游戏,并把这个想法应用到了Google的图片搜索。

验证码的升级版

Luis von Ahn在发明验证码之后,有一段时间变得很郁闷。为啥呢?因为他得到了一些数据——全世界的网民每天数据验证码将近2亿次,而每次验证码的输入时间将近10秒,这样算下来,每天网民要在验证码上面话费50万个小时。Luis von Ahn看着这些数字陷入了沉思,因为自己的发明,网民每天要多花这么多时间,有没有什么办法利用这些时间呢?

『有了!』Luis von Ahn突然在办公室跳起来,他想起之前被Google收购的那个游戏了,他知道该怎么做了。于是Luis von Ahn在CAPTCHA的基础上进一步改进,并把新的验证码叫做『reCAPTCHA』。『re』就是重新的意思嘛。

那么这次他是怎么改的呢?在我看来,Luis von Ahn的这次改进简直就是天才的想法。他的想法就是既然人们在输入验证码的时候有10秒钟的时间,那何不利用这10秒来讲那些古老的书籍或者图片的门牌号给识别出来。

这里需要说一下为什么要进行书籍的电子化。信息时代的一个特点就是要把我们生活的世界进行信息化,尽可能地把一切都可以索引。那么我们把书籍电子化就可以让人们更方便的去查找某一本书的某一句话,而不需要你翻烂一本书都找不到出处。

但是古老的书籍实在信息时代之前出现的,因此需要人为的进行电子化。但是电脑在扫描这些古老的书籍的时候总是错误率很高,根本不能用,这也是图书领域的一个大难题。不过,有了Luis von Ahn的天才想法,这些都不是问题。让我们来看看他是怎么解决这个问题的:

验证码升级版的验证过程

  1. 将古老书籍进行扫描(比如我们扫描《西游记》)
  2. 将扫描得到的图片分成单个词的片段 (将《西游记》扫描的图片按照单个字进行截取)
  3. 系统随机生成一个词A和扫描图片得到的词B组成一个验证码(假如随机生成的词A为『我』,扫描图片的词B为『俺老孙』,当然了用户是不知道『我』还是『俺老孙』哪一个是系统产生的)
  4. 当用户正确输入A之后就会被认为这是人在操作,那么B也就会被认为是人在认这个词(于是只要用户输入正确的A的答案为『我』,那么系统也会人会后面输入词就是扫描图片上面的词了)
  5. 然后B这个词就被人认出来了,以此类推,书就可以被全部认出来了。(以此类推,《西游记》就会被人在输入验证码的时候就被电子化了。)

说了这么多,咱们还是来看看真图(其中『morning』这个词是书里扫描出来的,后面这个『upon』是系统随机产生的,伪装的很像哈):
psb

升级版的验证码效果

那么这个升级版的验证码效果如何呢?当时是有35万个网站使用这个验证码,一天可以数字化1亿个单词,一年可以将250万本古老书籍电子化。这真的是一个功德无量的时候,它可以让老一辈的智慧通过电子化继续流传下去(用书的话说不定哪天就被烧了呢)。

这个天才的想法再次Google收购。唉,Luis von Ahn是名副其实的人生赢家了。

Luis von Ahn在我看来是一个闲不下来的人。按理来说,这个家伙的做的东西两次被Google收购,还是国际顶级名校的副教授,吃穿都应该不愁了吧。可是人家的境界还是比我不知道高到哪里去了,他貌似又看到了一些新的东西。

再次出发,Duolingo教你学外语

Luis von Ahn有一次给他带的研究生出了一个问题——如何让一亿网民免费来将互联网的主要内容翻译成各个主要语种。后来Luis von Ahn带着他的研究生开启一个全新的项目,叫做『Duolingo』,中文名叫做『多邻国』。

这是一个什么样的项目呢? 在Luis von Ahn看来,现在的互联网的优质内容还主要集中在英语,如果想让全球人民来无障碍来享用这些优质内容,这些优质内容必须被翻译成他们相应的语言版本。同时其中一大部分还是很有热情去学习一门外语,甚至花钱都可以。

于是Luis von Ahn又想到一个两全其美的办法让人们即可以免费学习最正宗的外语,还能提供专业级的翻译。他是这样想的:

  1. 首先那些提供优质内容的网站(比如纽约时报,英国广播电台BBC,美国有线电视CNN)会付费把他们要翻译的内容提供给『Duolingo』。
  2. 有了语料之后,『Duolingo』会在相关语种的语法专家的帮助下将这些内容分解成『Duolingo』的学习材料。这些内容会被分成简单的小句子,而且句子中的每个单词的意思都会给出。
  3. 有了这些单词的意思,『Duolingo』的用户就可以使用这些单词的意思翻译自己的语言版本,在这个过程中你的翻译还会被系统进行评价,通过即可获得积分和等级。

『Duolingo』里面的积分和等级代表了你的外语能力,你的积分和等级越高,你要翻译的东西越复杂。于是在整个过程中,你通过翻译学习了英语,同时你还帮助『Duolingo』完成了企业客户提供的语料翻译。

那『Duolingo』的效率如何呢?还是来看数据吧——将维基百科翻译成西班牙语:在十万用户的前提下,5周可以翻译完成;在100万用户的前提下,80个小时就可以了。多么神奇的一个工具呀。

如果你想体验『Duolingo』学英语(还可以学西班牙语、日语、韩语)的感觉,直接去豌豆荚下载吧 :http://www.wandoujia.com/apps/com.duolingo

总算结束了

不容易,总算接近尾声了。Luis von Ahn在我看来完全是一个优质偶像啊,你看发明了验证码,又改进验证码,让人们在输验证码的时候顺便帮忙把那些古老的书籍电子化,让人类的文明得到更好的传承。后来看到大家很多人都在学外语,他通过『Duolingo』为人们免费提供高效的外语学习平台,同时还帮助把互联网的优质内容翻译成其他语言版本,让更多的人享受更优质的内容。在我看来牛逼的地方在于他的两次创业成果都被Google收购,而且他还不满足,继续着自己的奋斗!

最后我想给大家推荐一下Luis von Ahn在TED的这个经典演讲,内容基本概况的他的主要工作内容,更重要的是他的演讲能力也很好,很会与听众互动,知道如何幽默地演讲。演讲链接地址

参考链接:

  1. Luis von Ahn 个人主页
  2. Luis von Ahn wikipedia
  3. TED 演讲

如何给你的Android 安装文件(APK)瘦身

本文翻译自:Putting Your APKs on Diet           原作者:Cyril Mottier

Android的apk文件越来越大了这已经是一个不争的事实。在Android 还是最初版本的时候,一个app的apk文件大小也还只有2 MB左右,到了现在,一个app的apk文件大小已经升级到10MB到20MB这个范围了。apk文件大小的爆炸式增长主要是因为用户对app质量的期待越来越高以及开发者的开发经验增长,具体体现在以下几个方面:

  • Android设备 dpi 的多样化 ([l|m|tv|h|x|xx|xxx]dpi)
  • Android平台的进化,开发工具的改进以及开源类库生态系统的丰富
  • 用户对高质量UI的期待
  • 其他原因

Android开发者在设计一个app的时候应该将最终发布一个轻量级app作为一个最佳实践来考虑。为什么?首先这就意味着你拥有了一个简洁,易维护代码基础。其次,官方应用商店对超过50MB的apk设置了拓展包文件下载选项,apk文件在50MB以下更容易让用户下载。最后,我们的应用程序环境是一个带宽有限,存储空间有限的环境,apk安装文件越小,下载就会越快,安装也会更快,良性循环,最后说不定用户因为这个给好评。

在大部分情况下,apk大小的增长是为了满足消费者的需要和期待。然而,我认为apk大小的增速已经超过了用户对app期待的增速。所以,很大程度上,官方应用商店里面的那些程序可以瘦身至它们现在大小的一半甚至更多。在这篇文章里面,我将写下一些关于如何给apk文件瘦身的招式,希望你们能够喜欢。

reducing_apk_file_size

 

APK 文件格式

在说如何给apk瘦身之前,让我们先来看看apk文件内部的结构到底是怎么一回事。说简单点,一个apk文件就是包含一些文件的压缩包。作为开发者,我们通过使用 unzip 命令解压这个apk文件一探apk的内部结构。下面的文件结构就是我们使用 unzip <your_apk_name>.apk1这个命令所获得的:

/assets
/lib
  /armeabi
  /armeabi-v7a
  /x86
  /mips
/META-INF
  MANIFEST.MF
  CERT.RSA
  CERT.SF
/res
AndroidManifest.xml
classes.dex
resources.arsc

我们可能对上面大部分的文件和目录都很熟悉。它们和我们在实际开发app的时候所看到得项目结构一样,包含了: /assets, /lib, /res, AndroidManifest.xml. 还有一些文件可能是我们第一次看到。一般说来,classes.dex, 它包含了我们所写的Java代码经过编译后class文件;resources.arsc 包含了预编译之后的资源文件(比如values文件,XML drawables 文件等。)。

由于apk文件只是一个简单地压缩文件,这就意味着它有两种大小:即压缩前的大小和压缩后的大小。这篇文章我将主要关注压缩后的大小。

如何减少apk文件大小

减少apk文件大小可以从几个方面入手。由于每个app都是不同的,所以没有什么绝对规则来给apk文件瘦身。作为apk文件的三个重要组成部分,我们可以考虑从它们开始入手:

  • Java 源代码
  • 资源文件(resources/assets)
  • native code

所以接下来的招式都是由减少这些组件的大小出发,进而减少整个app的大小。

掌握良好的编码习惯

这是减少apk文件至关重要的第一步。你要对自己的代码了如子掌。你要移除掉所有无用处的dependency libraries,让你的代码一天比一天优秀,持续地优化你的代码。总而言之,保持一个简洁,最新的代码基础是减少apk文件至关重要的一环。

当然,从零开始一个项目并为这个项目保持一份简洁的代码基础很容易。项目越老,这个工作就越困难。事实上,拥有一大段历史背景的项目必须要去处理各种死代码和无用代码。还好有许多的开发工具可以帮我们来做这些事情……

使用 Proguard

Proguard 是一个很强悍的工具,它可以帮你在代码编译时对代码进行混淆,优化和压缩。它有一个专门用来减少apk文件大小的功能叫做 tree-shaking。Proguard 会遍历你的所有代码然后找出无用处的代码。所有这些不可达(或者不需要)的代码都会在生成最终的apk文件之前被清除掉。Proguard 也会重命名你的类属性,类和接口,然整个代码尽可能地保持轻量级水平。

也许现在你会认为 Proguard 是一个相当有效地工具。但是能力越大,责任也就越大。现在许多开发这认为Proguard有点让人不省心,因为它会重度依赖反射。哪些类或者属性需要被处理或者不能处理都要开发者对 Proguard 进行配置。

广泛使用 Lint

Proguard 只会对 Java 代码起作用,那么对哪些资源文件呢?比如一张图片 my_image 在 res/drawable 文件夹中,没有被使用,Proguard 只会移除掉 R 类中的引用,但是图片依然还在文件夹中。

Lint 一个静态的代码分析器,你只需通过调用 ./gradlew lint这个简单地命令它就能帮你检查所有无用的资源文件。它在检测完之后会提供一份详细的资源文件清单,并将无用的资源列在“UnusedResources: Unused resources” 区域之下。只要你不通过反射来反问这些无用资源,你就可以放心地移除这些文件了。

Lint 会分析资源文件(比如 /res 文件夹下面的文件) ,但是会跳过 assets 文件 ( /assets 文件夹下面的文件)。事实上assets 文件是可以通过它们的文件名直接访问的,而不需要通过Java引用或者XML引用。因此,Lint 也不能判定某个 asset 文件在项目中是否有用。这全取决于开发者对这个文件夹的维护了。如果你没有使用某个asset 文件,那么你就可以直接清除这个文件。

对资源文件进行取舍

Android 支持多种设备。Android的系统设计让它可以支持设备的多样性:屏幕密度,屏幕形状,屏幕大小等等。到了Android 4.4,它支持的屏幕密度包括: ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi and xxxhdpi。但是你要知道的一点是,Android 支持这么多的屏幕密度并不意味着你需要为每一个屏幕密度提供相应的资源文件。

如果你知道某些屏幕密度的设备只有很少部分用户在使用,那么你就可以直接不需要使用相应屏幕密度的资源文件。就我个人而言,我只会为我的应用提供 hdpi, xhdpi and xxhdpi2 这几个屏幕密度的支持。如果某些设备不是这几个屏幕密度的,不用担心,Android 系统会自动使用存在的资源为设备计算然后提供资源文件。

我这么做得原因很简单。首先,这些设备屏幕密度就能覆盖我 80% 的用户。其次,xxxhdpi 这个屏幕密度只是在为未来的设备做准备,但是未来还未到来。最后,我真的不怎么关心低屏幕密度(比如mdpi 和 ldpi),无论我为这几个屏幕密度努力,结果都是令人伤心地,还不如直接让Android系统对 hdpi 资源文件进行适当地缩放来匹配相应地低端机型。

同样地,在 drawable-nodpi 文件夹里面维持一个文件也能节省空间。当然前提是你觉得对这个文件进行相应地缩放之后呈现的效果你能接受或者这个文件出现的几率很少。

资源文件最少化配置

Android 开发经常会依赖各种外部开源代码库,比如Android Support Library, Google Play Services, Facebook SDK 等等。但是这些库里面并不是所有的资源文件你都会用到。比如, Google Play Services 里面会有一些为其他语种提供翻译,而你的app又不需要这个语种的翻译,而且这个库里面还包含了我的app中不支持的 mdpi 资源文件

还好从Android Gradle Plugin 0.7 开始,你可以配置你的app的build系统。这主要是通过配置 resConfig 和 resConfigs 以及默认的配置选项。下面的 DSL (Domain Specific Language)就会阻止 aapt(Android Asset Packaging Tool)打包app中不需要的资源文件。

defaultConfig {
    // ...

    resConfigs "en", "de", "fr", "it"
    resConfigs "nodpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
}

 

 

 

 

压缩图片

Aapt(Android Asset Packaging Tool)就内置了 保真图像压缩算法。例如,一个只需 256 色的真彩PNG图片会被aapt 通过一个颜色调色板转化成一个 8-bit PNG 文件。这可以帮助你减少图片文件的大小。当然你还可以通过Google查找相应的优化工具,比如 pngquant, ImageAlpha 和 ImageOptim 等。你可以从中选择一个适合你的工具。

还有一种只在Android平台上存在的图片文件也可以优化,它就是 9-patches。就我目前所知道,我还没发现有这个文件的优化工具。然而你只需要求你的设计师将它的可扩展区域和内容区域尽可能地减少即可。这不但可以减少资源文件的大小,还能使得以后资源文件的维护变得更加简单。

限制app支持的cpu 架构的数目

一般说来Android 使用Java 代码即可以满足大部分需求,不过还是有一小部分案例需要使用一些 native code。就像之前对资源文件那样opinionated,你可以这些 native code opinionated。 在当前的Android 生态系统中,让你的app支持 armabi 和 x86 架构就够了。这里有一篇相当不错的关于如何瘦身native 代码库的文章,你可以参考参考。

尽可能地重用

重用资源可能是你在进行移动开发时需要了解的最重要的优化技巧之一。比如在一个 ListView 或者 RecyclerView,重用可以帮助你在列表滚动时保持界面流畅。重用还可以帮你减少apk文件的大小。例如,Android 提供了几个工具为一个asset文件重新着色,在Android L中你可以使用 android:tintandroid:tintMode 来达到效果,在老版本中则可以使用 ColorFilter 。

如果系统中有两种图片,一种图片是另一种图片翻转180°得到的,那么你就可以移除一种图片,通过代码实现。比如你现在有两种图片分别命名为 ic_arrow_expandic_arrow_collapse :

expand_collapse

 

你可以直接移除掉 ic_arrow_collapse 文件,然后在ic_arrow_expand 的基础上创建一个 RotateDrawable 。这个方法也可以让你减少设计人员的工作:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_arrow_expand"
    android:fromDegrees="180"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="180" />

 

在合适的时候使用代码渲染图像

在某些情况下,直接使用Java 代码渲染图像也能获得不错的效果。比如逐帧动画就是一个很好的例子。最近我都在尝试一些Android Wear 的开发,了解了一下Android wearable support library。就像其他的Android support library 一样,这个库里面也有一些工具来处理穿戴设备的。

不过让我吃惊的是,当我简单地构建了一个 “Hello World”示例,最后得到的apk文件竟然有1.5MB。于是我快速地研究了一下 wearable-support.aar 文件,发现这个库有两个逐帧动画,并分别支持了3种不同的屏幕密度:一个 “success” 动画 (31 frames) 和一个 “open on phone” 动画 (54 frames)。

wearable_support

 

这个逐帧success动画是被一个叫做 AnimationDrawable 所定义的:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true">
    <item android:drawable="@drawable/generic_confirmation_00163" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00164" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00165" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00166" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00167" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00168" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00169" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00170" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00171" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00172" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00173" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00174" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00175" android:duration="333"/>
    <item android:drawable="@drawable/generic_confirmation_00185" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00186" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00187" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00188" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00189" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00190" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00191" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00192" android:duration="33"/>
    <item android:drawable="@drawable/generic_confirmation_00193" android:duration="33"/>
</animation-list>

 

这样做得好处就是 (我当然在讽刺) 每帧显示33ms,这使得整个动画保持在30fps的频率。如果每帧16ms这将会导致整个库是之前的两倍大。如果你去看源码你会发现很有趣。在 generic_confirmation_00175 这一帧 (15 行) 将持续显示 333ms。 generic_confirmation_00185 紧跟着它。这个优化节省了9个类似的帧 (包含了从176 帧到 184 帧) 。不过最后神奇的是 wearable-support.aar 竟然神奇的包含了这个9个完全无用的帧,而且还以3中屏幕密度展示。3

在代码中来渲染这样的动画明显会很花时间。然而当你维持动画运行在60fps这样的频率可以大幅度的减少apk的大小。在写这篇博文的时候,Android还没提供工具来渲染这样的动画。但是我希望Google正在开发新一代的轻量级实时渲染系统来保证material design的细节呈现。当然“Adobe After Effect to VectorDrawable” 之类的设计工具也能提供很多方便。

如何更进一步?

上面所有的招式都集中在app或者library 开发者。也许我们还可以在app分发渠道方面为apk大小做出一些改变?我想可以在app 分发服务器端做一些改进,或者在官方应用商店。例如,我们可以期待官方应用商店在用户安装app的时候为设备绑定相应的native 库而摒弃那些无用的。

同样地,我们还可以想象只根据目标设备的配置来打包应用。不幸的是,这可能破坏Android 生态一个重要的功能特性:配置热置换。事实上,Android一开始就是位处理各种实时的配置更改(语言,屏幕转向)而设计的。如果我们移除掉与目标屏幕不兼容的资源文件,这可以极大的减少文件大小。不过Android需要处理实时的屏幕密度更改。即便我们假设废除这种功能,我们仍然需要处理为不同的屏幕密度设计的图片以及其他配置(比如屏幕朝向,最小宽度等)。

服务器端的apk打包看起来很强大。但这样会冒很大得风险,因为最终传送给用户的apk会于开发者发给的服务器的完全不同。分发一些缺失资源文件的apk可能会导致app崩溃。

总结

设计就是在一个约束集里面找出最好的方案。显然apk文件的大小就是一个约束。不要害怕为了让多个方面变得更好而放松一个方面的约束。例如,当你要降低UI的渲染效果时,不要犹豫,因为这可以让apk的大小减小,同时使得app的运行也更加流畅。你99%的用户是感受不到UI质量变低的,但是他们会注意到apk文件变小了,运行也更加流畅了。总之,你需要将app各方面进行整体考虑,而不是仅仅几个方面的斟酌。