2016年读书笔记

又到了一年的年末,翻开去年的记录,吃惊的发现去年竟然只看过16本。今年年初的时候,计划阅读100本书,也的的确确一直坚持了一年,中途可能因为工作耽误了一些进度,但也一直坚持到现在。然而遗憾的是到目前为止,距离2016年结束还有短短一个礼拜的时候,又发生了和去年一样的问题,欠下了10本左右的债。

耳边总有人说,“为什么总要在意那几个数字?”,而对我而言,那不仅仅是那几个数字,他是年初的一句承诺,对整个年度的一句承诺,如果不能达到这个承诺,那过去说过的话还有什么意义。

今年的书单印证了一句话“因为一本书,爱上一个人,迷上一个类型”,我也曾经在 G+ 上说过,多少年了,还是在三年级到初中的那段时间疯狂的迷过Verne,多少年的时间里因为学业,因为各种,再难爱上一位作家,再难爱上一段文字。而今年因为一本《解忧杂货铺》让我知道了东野圭吾,也打开了我认知的另一扇窗户。今年的近90本中有很大一部分都是东野的作品。而有趣的事,和东野的经历一样,让我们结识悬疑推理的经历竟然如此的相似,这一段经历可以参考《我的晃荡的青春》,东野的青春竟然也如此的淘气和真实。

而我从年初,从东野最著名的小说开始读《嫌疑人X的献身》、《白夜行》在到加贺恭一郎系列,再甚至到不怎么出名,甚至默默无闻的早期作品《以眨眼干杯》《沉睡森林》,再到毒舌三部曲《毒笑小说》《黑笑小说》《怪笑小说》,东野圭吾的书读不到尽头也几乎没有重复,这让我佩服的五体投地。

按时间排序读过

  • 解忧杂货铺 五星
  • 白夜行 五星
  • 空中杀人现场,短篇,四星
  • 嫌疑人X的献身,五星
  • 秘密 五星
  • 放学后 四星
  • 恶意 五星
  • 流星之绊 五星
  • 彷徨之刃 五星,强烈推荐
  • 幻夜 四星
  • 信 五星
  • 单恋 四星
  • 时生 四星
  • 名侦探的守则 四星
  • 圣女的救济 五星
  • 宿命 四星
  • 超杀人事件 五星,短篇可以看看
  • 名侦探的诅咒 四星
  • 浪花少年侦探团 四星
  • 再见了忍老师 四星
  • 十一字杀人 四星
  • 没有凶手的杀人夜 四星
  • 分身 四星
  • 同级生 四星
  • 只差一个谎言 四星
  • 祈祷落幕时 四星
  • 虚无的十字架 五星
  • 湖畔杀人事件 四星
  • 布鲁特斯的心脏 三星
  • 毒笑小说 五星
  • 从前我死去的家 四星
  • 新参者 五星
  • 黑笑小说 五星
  • 天空之蜂 四星
  • 美丽的凶器 四星
  • 濒死之眼 四星
  • 杀人之门 四星
  • 以眨眼干杯 四星
  • 毕业 四星
  • 学生街杀人 四星
  • 我的晃荡的青春 四星
  • 红手指 四星
  • 谁杀了她 四星
  • 怪人们 四星
  • 麒麟之翼 四星
  • 梦幻花 四星
  • 变身 五星
  • 假面饭店 四星
  • 天使之耳 五星
  • 沉睡的森林 四星

今年的书摘如果都放到这边可能有些多,甚至没有什么必要,有些内容经过整理和摘录,我都放到了 Evernote 。有些比较长的内容,也有格式化。

其他小说

  • 围城,毕竟有些年代,不过依然值得一读
  • 追风筝的人,带领我走进阿富汗
  • 灿烂千阳,追风筝同作者的书,依然讲述阿富汗的故事
  • 岛上书店,毕竟畅销书,明年可以按比例提高产销书比例

技术

但回头看自己今年的书单,深感技术类书籍占比略少,去年至少系统的看过 Bash,和基础 Linux,而今年除了看一些基础的 Java 知识,再没有系统地学习一项内容,除了年末恶补了一些 Spring MVC 和 Redis, HBase 的相关知识。因此在制定明年的计划时要讲技术书籍内容比例提高到10%左右,有些书值得反复阅读思考和实践,技术类的书既有消费品也有值得反复品味的内容。

今年读过的技术类书:

  • Effective Java 五星,所有Java编程者都应该读一读
  • Java 与 模式,稍显啰嗦,但是讲的非常细致
  • Maven 实战,熟悉 Maven 入门速成
  • Redis 入门指南,入门书籍,不讲求细节和实现原理
  • 其他的都没有完整的读完,明年一定要提高一定的比率。

摄影

而其他摄影的类:

  • 摄影师的视界,迈克尔弗里曼摄影构图与设计,讲构图的书,还是值得一看,只是还没有来得及实践
  • 穿透黑暗夜景和暗光摄影,匆匆读过,夜间摄影还是需要一些技巧
  • 昨天的中国,在学校法盟偶然遇见的一本纪实摄影,顶赞

设计

  • 设计准则,第一次参加读书会时借阅的书,讲到一些日常生活中的设计,当要装修的时候再参阅
  • 设计心理学

其他

  • 人在欧洲,真的是讲人在欧洲的一些见闻和思考感悟
  • 民主的细节,五星强烈推荐
  • One Billion Customers ,五星强烈推荐
  • 黑客与画家,其实早读过,今年又翻出来推荐给一些人
  • 乖,摸摸头,小故事,有人说的”鸡汤“
  • 秦始皇的秘密,也是听人推荐一口气读完的,当故事看吧
  • 断舍离,整理啊
  • 怦然心动的人生整理魔法 1,2 第一部比较笼统,第二部比较仔细,第二部中的衣服整理法则好好
  • 从你的全世界路过,畅销书,小故事看吧
  • TED 演讲的8个秘诀
  • 失控,大部头的书,好像就记得蜜蜂了。
  • 三人行,第一次见到那么排版的书籍, 针对同一个主题,两岸三地不同世界的人不同的故事。

还有一些就不列了。


2016-12-22 book , reading

更新隐私政策

今天突然收到 Google Play Store 发来的邮件通知,说违反社区准则,原因是没有隐私政策说明。全文如下:

Our records show that your app, {Application Name}, with package name {package name}, currently violates our User Data policy regarding Personal and Sensitive Information.

Policy issue: Google Play requires developers to provide a valid privacy policy when the app requests or handles sensitive user or device information. Your app requests sensitive permissions (e.g. camera, microphone, accounts, contacts, or phone) or user data, but does not include a valid privacy policy.

Action required: Include a link to a valid privacy policy on your app’s Store Listing page and within your app. You can find more information in our help center.

Alternatively, you may opt-out of this requirement by removing any requests for sensitive permissions or user data.

仔细研读几遍之后发现其实只要增加一条链接,说明一下隐私政策。其实主要的原因就是应用中使用到了 android.permission.GET_ACCOUNTS,android.permission.READ_CONTACTS 这俩权限,都是 Firebase SDK 里卖弄登陆要用到的。

仔细研究了一番 Google 的隐私政策Instagram 的隐私政策

然后随着大概意思拷贝了一份


2016-12-21 Privacy

pdnsd 使用

Pdnsd 是用来缓存本地DNS信息的 DNS 服务器。和 BIND 和 dnsmasq 相比,Pdnsd 在重启之后依然可以保存 DNS 缓存,名字中的 p 表示 persistent。

Installation

Ubuntu/Debian 系下使用如下命名安装:

sudo apt install pdnsd

Configuration

默认配置地址 /etc/pdnsd.conf

下面配置示例,后面的分号不可缺少。

配置示例:

global {                                                                        
        perm_cache=1024;        # 要缓存多少DNS信息                                                
        cache_dir="/var/pdnsd";                                                 
#       pid_file = /var/run/pdnsd.pid;                                          
        run_as="nobody";                                                        
        server_port = 1053;                                                      
        server_ip = 127.0.0.1;  # Use eth0 here if you want to allow other       
                                # machines on your network to query pdnsd.       
        status_ctl = on;                                                         
#       paranoid=on;       # This option reduces the chance of cache poisoning   
                           # but may make pdnsd less efficient, unfortunately.   
#       query_method=udp_tcp;                                                    
        query_method=tcp_only;  # 使用 TCP 方式去查询 DNS 服务器                                                 
        min_ttl=15m;       # Retain cached entries at least 15 minutes. 缓存 DNS 最短有效期         
        max_ttl=1w;        # One week. 缓存 DNS 信息最长有效期                                           
        timeout=10;        # Global timeout option (10 seconds).                 
        neg_domain_pol=on;                                                       
        udpbufsize=1024;   # Upper limit on the size of UDP messages.            
}                                                                                

server {                                                                         
    label= "googledns";                                                          
    ip = 8.8.8.8, 8.8.4.4;                                                       
    timeout=30;                                                                  
    interval=30;                                                                 
    root_server = on;                                                            
    uptest = ping;                                                               
    ping_timeout=50;                                                             
    purge_cache=off;                                                             
    exclude=.cn, .douban.com, .taobao.com                                         
}             

Pdnsd 读取配置时,优先级从上到下,上面的 DNS 服务器配置优先于下一层。

DNS servers

pdnsd 需要至少知道一个上游 DNS 服务器用来收集信息

  • label,用来标示服务器,随意,但最好写上服务器名字
  • ip,DNS 服务器地址,可以分多行,也可以使用逗号分割

/etc/resolve.conf 中指定了一些DNS服务器地址,在配置 pdnsd 的时候,修改为

nameserver 127.0.0.1

测试

启动 pdnsd 服务

/etc/init.d/pdnsd start 
nslookup www.douban.com 127.0.0.1

或者

dig @localhost -p port www.douban.com

如果返回正常,和 webdnstools 比照,则说明配置成功

清空本地缓存

sudo pdnsd-ctl dump   # Print information stored in the cache about name.
sudo pdnsd-ctl empty-cache

查看端口占用

sudo netstat -anp | more

pdnsd 只能优化 DNS 解析,并不能避免 DNS 污染

reference


2016-12-19 Linux , DNS , pdnsd

笔记整理法则

最近 Evernote, WizNote 纷纷宣布收费,一时间让我手足无措,原本按部就班的一些流程纷纷被打破。但是笔记和摘录总是那样的顺其自然,在翻看自己曾经摘录过得一些整理法则的时候,发现其中有些问题确实自己也已经犯下,在电脑玩物的《Evernote 超效率数位笔记术》书中,作者总结了“Evernote 用户最容易犯的10个错误[^1]”:

  1. 无目的的存储。收集资料的目的性是非常重要的,所谓的目的应该紧紧围绕自身的现实需要,如果漫无目的地搜集,将来使用到的几率是非常低的,对于你自身的提高和发展毫无裨益。
  2. 过度分散。这个可能在利用Evernote当做GTD执行系统中出现。
  3. 不愿意舍弃。参考“断舍离”整理法,需要放弃“把东西占为己有的观念”,现在能够收集到的有价值的资料一定会在网络上更新与流通保存,你一定能够在网络上再次找到需要用到的时候才去寻找,能够得到更新更准确的资料。不会过期的资料便是你自己的心得、感想、经验与故事。笔记本不是仓库,而是用于行动的工具,收纳的东西越少,你的人生就越轻松。
  4. 笔记之间不流动。可以参考建立笔记中枢的做法。
  5. 笔记方式太枯燥。有的时候拍照或者录音会更方便快捷。
  6. 没有在行动中使用
  7. 过度在意版面编排。需要专注于笔记内容,舍弃其他多余的东西。
  8. 停留在文档处理思维。放弃处理文档时候细琐、分散、独立的思维,需要更多的整理沟通。
  9. 没有把记忆交给Evernote。没有形成一有想法就记录下来的习惯,是没有办法真正释放记忆的压力,也就不用说用好Evernote了。
  10. 过度整理。笔记的整理时一个长期的过程,也需要根据自己的实际需要来增加或者删减内容,不需要苛求一开始就整理得漂亮详细,一切都需要根据实际需要来进行操作,目的是为了以后能够用到。如果不能用到,便是在做无用功。

对于这些错误,最严重的就是第一条,因为 Evernote 和 WizNote 的网摘插件实在太好用,在摘录了大片的内容之后,就忘记整理总结,躺在笔记本中就“死亡”了。幸而这些天这么折腾让我想起了那些笔记墓地,也正好抽出时间来整理一下。正像最后写的那样,”笔记是为了在以后用到,如果用不到,那便是在做无用功”。

建立合理的分类

早之前就总结过分类和标签,这两者在使用上还是有些区别的,最直观的区别就是一篇笔记只能属于一个分类,而可以归属于多个标签。分类是方便我们整理,而标签是便于我们检索和记忆,同样分类是给我们自己看的,而标签是给机器看的。因而建立一个合理的分类是非常必要的。之前看电脑玩物使用标签整理法,在我个人使用一段时间之后便放弃了,转而使用分类管理,而在过程中打上标签。

根据自己的使用,可以将笔记划分为不同的分类:

  • Notes 通用的未处理笔记,包括大部分文摘,网摘
  • Archive,归档,当笔记无法分类时,归到此类,处理完之后归档
  • 读书笔记,看书时做的记录,通常一本书一篇
  • 豆瓣影评,电影观后感,或者电影相关资料
  • 蜂窝游记,平时有些游玩准备,或者游记,图片之类
  • 微信收藏,微信公众号中值得看第二遍的内容
  • 我的邮件,通过邮件收藏的内容,通常由 InoReader 中内容发送过来
  • 购物清单,又包括许多子分类

等等分类,每篇文章,在未处理之前都在未分类中,在处理完之后都有自己的归属。

标签管理

这里使用购物清单来作比喻,对于使用记事本来做类似 TODO list 这样的事情来说,没有比使用标签来得更加方便的事情。大部分人可能已经习惯了 List 这样的 Todo 清单,但是对于一件需要长期进行的计划来说,单一的清单可能已经完全不能满足需求。因此才出现了 Trello 这样的多Board 的清单列表。而对于记事软件比如 Evernote 或者 Wiznote 来说,没有了 Trello 这样的多列待办清单,使用 Tag 来模拟也是可以轻易的实现的。

我的标签命名方式从电脑玩物学来,使用如下:

  • !01.GTD
  • !01.重要
  • !02.今日事
  • $02.Shopping
  • $01.想要
  • $02.调查
  • $03.不需要
  • $04.满足

对于这样的分类能够一目了然并且能轻松快速的找到想要的内容。而使用“!”这样的方式不仅增加了趣味,也让标签更加形象,”$” 就表示和购物相关。

而对于购物清单的子标签中分成想要,调查,不需要,满足四个标签,对于我自己,当在平时浏览网页,阅读RSS,或者好友推荐,甚至广告中获取某一个产品时,优先添加到想要的标签中。而第二个调查标签为自己在调查想要的产品时可能主动浏览或者搜索的重要内容。而调查的内容可能有两种归宿,一种是在调查过程中发现确实不需要,最后将内容添加到不需要中,另外一种就是为最后列出了需要购买的几点理由,而不得不买时,将内容拖到满足中,并完成购物。当且仅当物品出现在调查中,并且有几点强烈需求时才能将其拖入到满足中。

对于文档标题,使用物品内容+型号+价格来标识。对于同一件物品使用尽量同一个文档来保存。比如文档” Dji Marvic Pro 6999“ 在想要中记录。然后可能会调查他的摄像分辨率,飞行高度等等参数然后记录。当然最重要的是列出需要购买的理由,不单纯仅限于玩一玩啊。

reference

[^1]: http://www.haiyue.info/pc-player-evernote-taking-notes.html


2016-12-18 Evernote , WizNote

ads 相关术语

前段时间处理和广告相关的业务,接触到一些名词,网上也有一些解释,归纳下也好。

CPM (Cost Per Mille)

Mille is Latin for “thousand” ,千人浏览计费(impressions), 1000人观看价值。 1元/CPM 表示,每千人次观看 banner 广告,则收费1元。每CPM 收费标准不一,国际每 CPM 收费 5美元到200美元不等。一般网络中热门位置广告横幅,视频插播广告,移动端 banner 广告等等通常使用 CPM 收费模式。

对于广告载体,如果有大流量并且广告投放商更加关注品牌曝光率而不是直接进行交易,CPM比较合适。

CPC (Cost Per Click)

点击一次计费,对于大品牌广告投放商来说,这明显是不划算的方式,不可预估广告花费。CPC 是购买广告低风险的一种方式,只需要为有效点击付费。 Google 的 AdSense 就是最大的 CPC 市场。

CPA (Cost Per Action)

按广告投放实际效果,按有效订单或者有效回访问卷或者有效注册会员等等而定,不限制广告投放的数量。CPA 方式下会计算 effective CPA,简称 eCPA,用来计算投资回报。也就是说,如果通过广告卖出了 5 份产品,那么 eCPA 是 $50 / 5 sales = $10 per sales. 如果能够从每笔交易中获取超过 $10 的利润那将是一份成功的广告投放,而如果没有,那么则需要重新思考市场策略。

CPI (Cost Per Install)

每次安装成本计费,常见于手机App 安装。

三方广告监测公司

秒针,admaster, Double Click 等。

reference


2016-12-14 Ads

Tampermonkey Chrome下超神的插件

根据Tampermonkey在Google Code页面的介绍,Tampermonkey是一款在Google Chrome和Chromuim浏览器中提供“油猴子脚本”支持的工具。Tampermonkey是Google Chrome中最流行的一款脚本管理插件。它的API完全兼容“油猴子脚本”,它还加入更多的 Chrome 本身不支持的用户脚本功能,比如 GM_registerMenuCommand 和 GM_xmlhttpRequest这两个函数。

安装地址: Chrome Web Store

Tampermonkey is a tool that provides Greasemonkey script support for Google Chrome and Chromium Browser. It's API is fully compatible to Greasemonkey, including GM_registerMenuCommand, GM_xmlhttpRequest with cross domain support and access to the unsafeWindow object.

什么是浏览器用户脚本(Userscript)?

当用户浏览网页时,会从服务器上下载脚本,并在本地运行,这种脚本我们会称之为网页脚本。与网页脚本不同的,用户脚本本身就在客户机上,不需要下载,而且如果不对其做限制,可用在所有网页上。浏览器用户脚本通常使用Javascript语言编写。

通过编写用户脚本,可以很大程度上提高上网体验。譬如使用 Userscript可以实现网页自动翻页、文字翻译、页面预读、看图增强等等有用、有趣的功能。

Userscript虽然很自由很强大,但出于安全性原因,使用的时候会有些限制,如 Userscript不能操作文件、不能操作剪贴板等。
参考

Tampermonkey功能

  1. 管理和编辑所有的用户脚本
  2. 点击启动和禁用脚本
  3. 在不同Chrome中同步所有的脚本
  4. 通过URL搜索用户脚本(确保启用TamperFire)


Features:
 - manage and edit all your userscripts
 - enable and disable your scripts with 2 clicks
 - easily sync you scripts between different Chrome instances
 - search scripts from userscripts.org by URL (with TamperFire enabled)

使用Tampermonkey同步脚本

  1. 将"Config mode"切换到"Advanced"
  2. 找到"TESLA BETA"启动"Enable TESLA","type"选用“Chrome sync(Beta)”,save
  3. 这样所有的脚本都不会丢失了,不会发生我重装系统丢失所有脚本的情况了。


Tampermonkey何时同步:
1) before every TM update check
2) whan a script is changed locally
3) when TM starts
4) every 5h (will become configurable)
参考

安装脚本过程

找到你想要安装的用户脚本,例子中使用“Download YouTube Videos as MP4”脚本,更多推荐脚本可以看我这篇文章,一下在Chrome中执行。

Tampermonkey install

到了这个界面可以点击右上角的“Install”,然后会自动调用Tampermonkey

Tampermonkey install

点击“OK”

Tampermonkey install

这个界面可以看到脚本要求的权限和版本信息等等信息。点击“OK”整个安装过程就结束了。
最后晒晒我的脚本

Tampermonkey


如果想要深入了解一下油猴子用户脚本,可以参考一下这本书《深入浅出Greasemonkey

参考以下文章


2016-12-13 Chrome , Tampermonkey , Google

iPhone 设置及Review

作为一个坚定的 Android 使用者,最近想要尝试一下 iOS,只有尝试过之后才有对比,有对比才能比较出好坏。于是乎记录下从一个 Android 重度使用者,转用 iOS 遇到的一些问题和解决方案。以下行文的结构按照提出问题,寻求解决的过程及最后的解决方案来规划。

从Android手机恢复通讯录,短信,通话记录

通过设置 Google 账号同步联系人,但是短信和通话记录暂时无法找到方法备份恢复。幸而我的所有通讯录都有云备份,轻松的通过账号登陆就可以完成通讯录的迁移,但是因为短信和通话记录相对不是太重要,所以暂时还不需要迁移过去。并且 Android 端的短信和通话记录通过 SMS Backup+ 备份到了 Gmail 和 Google Calendar,所以也不存在丢失问题。

Apple ID 不同国家切换

直接使用苹果AppleId官网,可以轻松注册美区账号。在手机首次登陆时,选择 none,不使用信用卡登陆即可。原本有一个美区的账号的,但是手贱转回了国内,无奈只能再注册一个了。

而苹果 iTunes 账号分区和 Google Play Store 分区的困难程度也还是差不多的,但是明显 iOS 上切换账号起来比较麻烦。

App 迁移

最重要的部分都在于此,但是因为平时使用的应用,基本都是跨平台的,因此也没有遇上什么比较困难的问题,登陆应用内的账号,云同步一下数据基本就完事了。这里要分享一些 must have app,基本都是跨平台的

  • LastPass ,所有的密码
  • Google Photos,所有的 Photos
  • Dropbox,所有的文档
  • 网易云音乐,所有的音乐
  • WizNote,所有的笔记

所有的这些,我登陆一下账号,我想要的数据都来了。而剩下的其他社交类,工具类,修图类基本都能找到。

更改 Home 键功能

对于iPhone 的Home 键,我实在是无法习惯,可能是我被 Android 的 back 键和多任务切换的 recent 键惯坏了。但在 iOS 上返回操作和多任务切换在我看来是非常费劲的一件事情。iOS 的返回操作在我努力使用一天之后,大部分的情况下可以使用“从屏幕左边缘向右滑动“来进行返回操作,但对于我这样一个右手使用者来说,单手操作非常非常吃力,并且有的时候,比如在照片浏览的时候这样的操作却又是无用的。而对于弹出窗口,完成返回的操作按钮可能出现在左边,也可能出现在右边,这让返回操作异常困难,经常需要双手或者异常困难的手势去完成一个返回或者完成的操作。

比如下面的几张截图,需要完成一个返回或者完成的操作,左边,右边,滑动都出现了。并且当从一个应用跳转到另外一个应用的时候,你会注意到状态栏多出一个返回来,而那个返回”竟然是可点击“的,可以用来返回上一个应用。这对于我这个 Android 重度使用者来说完全无法适应,原本使用 Back 键能够完成的事情,现在需要我选择三四种方式,还需要分不同场合选择使用。

iphone

iphone

iphone

iphone

再说回到 Home 键本身, Home 键有如下的操作方式:

  • Tap,轻触不按下,识别指纹,或者解锁手机
  • Double Tap,连触,将屏幕拉下,适用于单手操作
  • Press,按下,返回主界面,类似于 Android Home 键
  • Double Press,双击,切换多任务,类似于Android 多任务键
  • Long Press,开启 Siri
  • Triple Press 可以在 accessibility 中开启。

这些操作在 Android 系统上分别为四个按键,而在 iOS 端全部糅合到一个按键中,难怪我实在无法适应 Home 键。当然 Android 的 Back 键在推出的时候,也有很多人,甚至开发者也会产生疑惑,甚至开发文档有整整一页说明返回按键的流程,但是依然不妨碍用户使用它。甚至在很早的时候我在看到 Android 和 Chrome 中按钮设置的时候,就感觉到 Android 和 Chrome 的按钮设置太像了。Chrome 很简洁,保留的按钮并不多,但是返回按钮,主页按钮,以及标签页都在非常重要的位置,而这三个按钮也正是 Android 得以保留的三个按钮。

而 Android 的这个按钮让用户得以在应用中跳转而不会迷失,我甚至给举例,比如我在 Google+ 中看到有一个 YouTube 视频,我点开会自动跳转到 YouTube App 播放该视频,然后我看到说明区域有链接,我点击查看详情,跳转到 Chrome App,在查看文章的时候,我看到有活动申请,于是点击邮箱地址跳转到 Gmail App,写完邮件,我甚至可以使用 back -> Chrome -> back -> YouTube -> back -> Google+,来返回到原来浏览的地方。而这一点我是无法在 iOS 上完成的,也不敢想象,我要多累才能回去。当然那个例子是一个极端的情况,但是日常中我会经常需要跳转。

总结

总之在最后,iOS 和 Android 各有各的优劣,而最近几年的更新也是相互借鉴,Android 借鉴 iOS 的权限管理, iOS 借鉴 Android 的通知系统,而对于我们消费者来说,两者只要适合我们,为我们所用,都是很好的 Smart Phone。

而下面是几点 iOS 让我刚到非常惊喜的

Smooth and faster

界面和整体非常流畅,动画几乎没有卡顿,但也有遇到在 Setting 界面卡住不动,在 App Store 列表卡住的情况。但是总体来说较 Android 而言,确实非常顺滑。并且一直被提及的跟手程度,其实也是稍微有优势的,只是近年来差距越来越小了。

通知接受很快

这也是非常赞的一点,这当然和 Apple 收紧通知发送有关,PC,iOS,Android 三端相同网络环境,经常是 iOS PC 受到消息很久之后 Android 才能受到消息。

Siri VS Google Now

这一点确实令人比较惊喜, Siri 在中文支持上竟然还可以,可能 Apple 给中文适配的比较多吧,同时功能也很稳定,不像 Google Now,有的时候就不理我了。


2016-12-11 iPhone , review , Google

Android GPS 反作弊

在移动设备上有很多方式来追踪用户的地理位置信息,下文会展开。然而并没有一种方式能够很容易作弊,对于日常普通用户而言模拟地理位置可以实现但是相对成本较高。因而综合使用以下的定位方法,可以让模拟地理位置信息变得非常困难。

有以下技术可以用来实现GPS定位:

  • GPS Reporting ,这是相对来说成本较“昂贵”的定位方法,一般来说 GPS 需要消耗更多的电量来提供GPS芯片读取卫星信号。GPS 信号可以编程通过修改GPS芯片驱动来改变获取到的位置,这种方式甚至不需要修改设备

  • GSM Reporting 通常是最常见的定位方法,通过距离最近的三个信号塔,三角定位。在这种方式下,模拟位置相对较难。或许可以通过修改设备硬件,或者通过伪造基站来达到伪造定位,当成本也相对较高。并且,一般来说通信是加密的,也会造成不少困扰。

  • LAN Reporting 这种方式通常能够提供高精度的室内定位。

  • WAN Reporting 这种方式就是简单的 IP 定位,这种方式也是最容易破解的。这种方式也是通常移动设备上网页常见的定位用户方法。

  • Others 除了以上提到的常见定位方法,还有一起其他的定位方法,比如“惯性导航系统” , 这种方式不需要额外的传输手段,它使用内部的传感器和地图来确定位置,具体来说就是“使用加速器和陀螺仪来测量物体加速度和角速度,并使用计算机来连续估算 运动物体的位置、姿态和速度。通常不需要外部参考系,常被用在飞机,导弹, 潜艇和各种航天器中。” 摘自维基

其他可以考虑的因素是,大部分的地理位置数据会保存在移动设备的某个地方。因此开发者可以通过获取用户上一次的地理位置信息来判断当前的位置信息是否正确。比如你可能1min前还在北京海淀,然后现在定位信息在美国华盛顿,这样的位置变化可能有些问题。

以上翻译自Security StackOverflow (Bluetooth, RFID, Inertial nav, experimental, etc)

检测 Android 模拟位置

在讲完实现定位方式之后,探讨一下 Android 对于模拟 GPS 的检测方法。

Developer Mode Mock Location

在 6.0 以前在开发者选项中有模拟位置的选项可选,开发者可以用过模拟位置来伪造地理位置信息。这种方式可以被很多方法检测到。比如:

public static boolean isMockSettingsON(Context context) {
  // returns true if mock location enabled, false if not enabled.
  if (Settings.Secure.getString(context.getContentResolver(),
                                Settings.Secure.ALLOW_MOCK_LOCATION).equals("0"))
     return false;
  else
     return true;
 }

第二种方式是检测安装的应用中是否有应用使用了 android.permission.ACCESS_MOCK_LOCATION 权限。

public static boolean areThereMockPermissionApps(Context context) {
  int count = 0;
  PackageManager pm = context.getPackageManager();
  List<ApplicationInfo> packages =
     pm.getInstalledApplications(PackageManager.GET_META_DATA);
  for (ApplicationInfo applicationInfo : packages) {
     try {
        PackageInfo packageInfo = pm.getPackageInfo(applicationInfo.packageName,
                                                    PackageManager.GET_PERMISSIONS);
        // Get Permissions
        String[] requestedPermissions = packageInfo.requestedPermissions;
        if (requestedPermissions != null) {
           for (int i = 0; i < requestedPermissions.length; i++) {
              if (requestedPermissions[i]
                  .equals("android.permission.ACCESS_MOCK_LOCATION")
                  && !applicationInfo.packageName.equals(context.getPackageName())) {
                 count++;
              }
           }
        }
     } catch (NameNotFoundException e) {
        Log.e("Got exception " + e.getMessage());
     }
  }
  if (count > 0)
     return true;
  return false;
  }

通过这两个方法能够减少一定程度非 root 机模拟位置的可能性。

root 手机

而对于root机型,几乎无法从根源上反作弊,对于出来四年的 Ingress 也几乎无法避免作弊的问题,目前可知的 Ingress 对于位置欺骗的反作弊方式有:

  • 速度限制, 35 miles per hour 大概是 55km/h
  • 交叉验证 SSID,通过匹配数据库中记录的 SSID 来确定位置

摘自StackOverflow

而对于这两种方式 Ingress 官方并没有明确的文档指出,基本通过玩家黑盒测试得出。而对于最新出的 Pokemon Go,在全球作弊成风的情况下官方直接禁用了 Root 机型。因此目前对于 root 机型的反作弊我还是没有找到可用的方法。


2016-11-24 Android , AndroidDev

Android 减小 APK 大小

了解 APK 结构

通常一个 APK 包括以下目录:

  • META-INF/ 包括 CERT.SF 和 CERT.RSA 证书文件, MANIFEST.MF
  • assets/ 包含 App 的资源文件,可以通过 AssetManager 获取
  • res/ 包括App 图片等等资源文件,不会被编译进 resources.arsc
  • lib/ 包括编译的库文件,该目录包括一系列为不同平台打包的子目录,比如 armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, 和 mips

APK 还包括以下文件,AndroidManifest.xml 是强制必须的:

  • resources.arsc 包括编译过的资源文件。这个文件包含了 /res/values/ 目录下定义好的所有的 XML 内容。Packaging Tool 提取 XML 内容,并压缩到二进制。该文件包含了不同语言的字符串,样式,还有不包含在 resources.arsc 文件中的资源路径,比如 layout 文件和图片。
  • class.dex 包含编译过后的代码文件,可以被 Dalvik/ART 识别。如果开发者使用 multidex 来避免 the 65536 method limit 那么包中可能存在多个 Dex 文件。
  • AndroidManifest.xml 包含 Android 的 manifest 文件。该文件包含了应用的名字,版本,权限申请和引用的库文件。

在谈到具体缩减APK大小步骤之前,可以使用 Android Studio 内置的 APK 分析工具来分析现有 APK 内容文件。入口位置在:Build -> Analyze Apk ,然后选择APK即可,然后会显示:

apk size

减少APK大小

APK 文件的大小影响着应用的加载,内存的使用,消耗多少电力。减小 APK 大小的最简单的方法就是减少资源文件数量和大小。比如,可以移除程序内不再使用的资源图片,或者可以使用可变大小的 Drawable 来代替现有的图片文件。下面是一些常用做法。

ProGuard

使用 ProGuard 来缩减代码大小,ProGuard 还有其他一些优化,混淆等等的功能,可以参考 sourceforge 或者参考之前整理的文章。具体优化配置如下:

  1. 在 buildTypes 下开启 minifyEnabled 和 shrinkResources

     buildTypes {
         debug {
             minifyEnabled false
         }
         release {
             minifyEnabled true
             shrinkResources true
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
         }
     }
    

    在开启 shrinkResources 之后效果还是挺明显,经过我的尝试,30M的App,能够缩减1M~3M大小,而只需要增加一行代码,何乐不为。而在平时开发中,如果遇到删减代码的时候,最好将资源文件一同删去,免去在打包时无用文件占用资源。

    具体参照 https://developer.android.com/studio/build/shrink-code.html

  2. 关闭 png cruncher 在下面 PNG 手动压缩之后,关闭该压缩选项

     aaptOptions {
         cruncherEnabled = false
     }
    

移除无用资源文件

可以使用上面提到的 shrinkResources 来在发布 release 版本时让 Gradle 自动剔除没有使用的资源文件,也可以通过 android-resource-remover 这个脚本来移除无用资源文件,这个脚本基于 Android Lint 工具 。通过 Gradle 在打包时并没有从本地磁盘上删去文件,而使用后一种方法可以从根本上删除无用文件。

在 Android Studio 2.0 以后,使用菜单中 Refactor -> Remove Unused Resources .. 可以用来在项目中移除不在引用的资源。实际操作感觉 Android Studio 会列出不正确的无用资源,在使用时需要特别注意。对于不再需要的图片一定要及时删除,例如因功能更新老的图片不再使用等情形。

在 build.gradle 中定义

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

可以只打包指定语言的资源文件。

缩减 PNG 图片大小

而缩减 PNG 图片大小的方法又可以细分为以下几类:

  • 通过代码来实现图片,对于图片资源,能不用图片就不用图片,如果图片的效果可以通过代码来实现,例如用画布来画等方式,这样可以极大限度的降低因为图片的使用而造成的 APK 尺寸增大。能用矢量图就用矢量图,只支持 Android 4.1 以上的程序,
  • 尽量多使用 WebP 格式,能用 JPEG 图片的就用 JPEG 图片

    • JPEG 图片使用了量化编码压缩的方式,可以极大程度减少图片的尺寸,但它有如下缺点:JPEG 图片无法支持 alpha 通道,如果需要透明效果就无法使用了;不同的压缩比(量化参数)会导致图片的质量非常不同,对于内容丰富、纹理较多的图片,由于分块压缩会导致 JPEG 压缩之后图片出现一些斑块
    • 对于 WebP 格式图片来说目前还有一些值得注意:1. Web 文件格式只支持 4+ 以上 Android 设备 2. WebP 文件相较于 PNG 图片需要消耗更多的系统额外时间去 decode 图片。并且 Google Play 只支持包含 PNG 格式图标的 APK,如果需要使用 Google Play 来发布应用,则不要使用 WebP 来制作应用图标。
  • 在不影响效果的前提下可以尽量压缩图片资源,图片一定不要放到非 drawable 目录下,除非你有足够的理由,不放在 drawable 下的图片没有 png crunch
  • 减少帧动画中图片帧,帧动画会明显的增加包大小,一般在 App 中使用一张 PNG 来表示动画的一帧。如果动画只有 15 FPS,那么在设计导出图片时尽量减少图片的数量,而不是使用30张图片来做15帧的动画,比如在程序中有个动画是用了60帧,后来使用bash,删去一般图片,并调整代码,而效果几乎看不出区别。

      for((a=1;a<62;a=a+2))
      do
        rm "filename"$a".png"
      done
    
  • 还有方法就是使用 VectorDrawable 更多的内容可以参考官方文档。
  • 尽量压缩 PNG 图片,可以使用如下的压缩工具

基本原理就是讲 24-bit 的图片压缩到 8-bit ,对于程序中小 icon 或者 低分辨率的图片几乎无法看出区别。

When you upload a PNG (Portable Network Graphics) file, similar colours in your image are combined. This technique is called “quantisation”. Because the number of colours is reduced,24-bit PNG files can be converted to much smaller 8-bit indexed colour images. All unnecessary metadata is stripped too. The result: tiny 8-bit PNG files with 100% support for transparency. Have your cake and eat it too! It turns 24-bit RGB files into palettized 8-bit ones. You lose some color depth, but for small images it’s often imperceptible.

网上有很多压缩工具,比如 tinypngpngquantPngcrushOptiPNGzopflipng from Google 。下面分别简单介绍下。

  • TinyPNG uses smart lossy compression techniques to reduce the file size of your PNG files. By selectively decreasing the number of colors in the image, fewer bytes are required to store the data. The effect is nearly invisible but it makes a very large difference in file size!
  • pngquant is a command-line utility and a library for lossy compression of PNG images.
  • Pngcrush Pngcrush is an optimizer for PNG (Portable Network Graphics) files. It can be run from a commandline in an MSDOS window, or from a UNIX or LINUX commandline.
  • OptiPNG OptiPNG is a PNG optimizer that recompresses image files to a smaller size, without losing any information. This program also converts external formats (BMP, GIF, PNM and TIFF) to optimized PNG, and performs PNG integrity checks and corrections.
  • Zopfli Compression Algorithm is a compression library programmed in C to perform very good, but slow, deflate or zlib compression.

对于 tinypng 网上有人编写了脚本 在他们的开发者网站上 申请 API key 就能够使用,不过免费的版本每个月只能压缩 500 张图片,对于小程序可能已经足够使用了,但是对于稍微大一些的 App,可能需要付费或者用其他的 API key。

对于 JPG 的图片可以使用 Paint.NET 或者 官方建议的 packJPG

部分内容摘自 StackOverflow

避免重复

可以从以下方面避免程序使用重复内容:

  • 不要包含重复代码
  • 不要包含重复 assets,strings, bitmap 等等
  • 使用 Drawable 对象来重复使用图片资源文件,比如需要一个向左,一个向右的箭头,则可以使用同一张资源图片,而定义 Drawable 来在运行时构建图片

避免资源重复是最显而易见可以减少APK大小的方法,而如果产生了重复代码,则一定要考虑是否代码抽象不够,重复的内容是否能够抽象出单独的方法,然后重构产生重复的地方。

广泛地使用 Lint 工具

ProGuard 可以对 Java 进行优化,但是对于 Android 资源文件无能为力。因此,如果图片在 res/drawable 下, Proguard 可以从 R class 中移除引用,但是图片文件依然还在原地方。

Lint 是一个静态代码分析工具,帮助检测无用资源文件。使用命令 ./gradlew 来生成 Lint 报告,在 UnusedResources: Unused resources section 下就能查到所有没有被引用的资源文件。

Lint 工具分析 resources 比如 /res 下的文件,但是会跳过 assets 目录下的文件。事实上, assets 文件可以通过他们的名字而不是 Java 或者 XML 引用来在代码中使用,所以 Lint 工具不能决定 asset 目录下的文件是否被引用。所以在 assets 目录下的文件则需要开发者自己维护,保持干净和整洁。

在 Android Studio 中配置 Android Lint ,使用 Lint 工具检测在菜单 Analyze -> Inspect Code… ,点击之后等待分析完成即可查看分析报告。配置 Lint 工具检查内容可以在 Android Studio –> Preferences –> Editor –> Inspections (currently on Android Studio) 下配置。比如想要关闭 “Image without contentDescription” 检查,可以直接搜索并且关闭即可。

缩减 resource.arsc 文件大小

之前说过 resource.arsc 文件包含了 res/value/ 目录下定义的资源,还有 layout 和 string 等资源的路径。因此随着 App 的不断更新,该文件会越来越大。

资源混淆压缩以及 resource.arsc 文件,工具可以使用 andresguard https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md ,但因为风险较大,目前并没有集成。

通过混淆资源,将 r/drawable/login_background.png 混淆为 r/d/a.png 这样就可以减少 resource.arsc 文件的大小极限压缩 jpg、png、resource.arsc 等文件,采用 7z 来对这类文件进行进一步的压缩,极大的降低包尺寸使用 andresguard 时清楚自己 app 哪些是不能混淆的,例如 facebook_idcrashlytics key 这些对应的 string 就不能混淆了,必须加入白名单;利用 getIdentifier 来获取的资源也必须加入白名单

asset 等资源

  • 音频文件:尽可能可以使用 AAC,mp3 等压缩格式,如果 midi 格式可以就用 midi 格式的,不要使用 wav 等无损格式
  • 视频文件:尽可能使用 H264 AVC 文件格式
  • JSON、数据库类的配置文件:要想办法节制,可以考虑放置一部分基础配置,其它从网络下载,做好“大而全”和“小而做出一些效果上的折中”两种决定间的权衡与选择
  • 字体:尽可能控制程序中使用的字体、字形数目,确定需要额外引入字体的,如果显示的字符数目有限(比如只有数字或只有英文字母),使用 fontforge 等工具对字体进行裁剪后再放入程序,具体剪裁方法参考 http://wiki.unity3d.com/index.php?title=Create_a_new_TrueType_font_using_a_subset_of_characters_from_an_existing_TrueType_font

Images: PNG or JPEG. Use PNGs; since it is a lossless format it is very suitable for textures and artwork as there will be no visual artefacts from the compression. If there are space constraints, use JPEGs or a combination of PNGs and JPEGs. A high quality JPEG image may work fine for large photo-realistic images, which the JPEG compression scheme is optimised for.

Audio: AAC Audio is recommended for all audio resources. AAC achieves better compression at a given quality, compared to mp3 or Ogg Vorbis. Raw formats such as WAV should never be used. The common rational for using the WAV format is that decoding compressed audio streams usually means high latency at playback. However, Android provides the Sound Pool API which enables applications to use compressed audio streams without the penalty of high latency.

Video: Use H264 AVC. Encode the video to a resolution no larger than the screen resolution of the target device (if known).

使用 FFmpeg 缩减音频

AAC-LC is the default for all of the AAC encoders supported by ffmpeg.

可以使用如下 ffmpeg 转码:

ffmpeg -i input.wav -codec:a aac output.aac

使用 FFmpeg 缩减视频大小

Calculate the bitrate you need by dividing 1 GB by the video length in seconds. So, for a video of length 16:40 (1000 seconds), use a bitrate of 1000000 bytes/sec:

ffmpeg -i input.mp4 -b 1000000 output.mp4

Additional options that might be worth considering is setting the Constant Rate Factor, which lowers the average bit rate, but retains better quality. Vary the CRF between around 18 and 24 — the lower, the higher the bitrate.

ffmpeg -i input.mp4 -vcodec libx264 -crf 20 output.mp4

摘自StackOverflow

缩减 Dex 文件大小

决定 dex 文件尺寸主要有两个方面(归根结底都是代码文件)

依赖的库文件,包括 gradle 依赖、引用的 jar 包、aar 包等自己的代码

针对 Google Play Service,在依赖时尽量分开,使用到某一部分时尽量只依赖使用到的部分,而不是把整个库都pull 下来。比如在项目中只需要使用到 GCM,和 Ads,那么在申明依赖时只引用两个即可。各个部分的依赖在developers.google.com 上可以查到。

compile 'com.google.android.gms:play-services-gcm:8.4.0'
compile 'com.google.android.gms:play-services-ads:8.4.0'

总结

在总结完以上方法之后,我才发现这一系列文章,这系列的文章非常值得一看,几乎完全覆盖了上面提到的方法。

reference


2016-11-23 Android , AndroidDev , TinyPNG

Android Gradle 学习笔记

Gradle 是 Android 新的编译环境。随着 Android Studio 的发布,编译 Android 的环境逐渐转移到了 Gradle。

an advanced build toolkit, to automate and manage the build process, while allowing you to define flexible custom build configurations

根据Android 官网 的介绍,Gradle 是一个进阶的编译工具包,能够自动管理编译过程,并且允许用户配置编译过程。并且在后序的学习中可以通过大量的配置来对 Android 进行多渠道打包,自动打包持续集成。

Gradle 和它响应的 Android 插件可以独立于 Android Studio 运行,这也就意味着开发者可以在 Android Studio 内部编译生成应用,也可以通过命令行来打包 APK

对于新建的 Android 工程,一般会产生多个 gradle 文件,下面依次介绍。

根目录下 build.gradle

Android 项目最顶层,在项目根目录下的 build.gradle 如下:

buildscript {
   repositories {
       jcenter()
   }
   dependencies {
       classpath 'com.android.tools.build:gradle:1.0.0'
   }
}
apply plugin: 'android'
allprojects {
   repositories {
      jcenter()
   }
}

各个字段含义:

  • buildscript :用于设置驱动构建过程的代码。
  • jcenter():声明使用 maven 仓库。在老版本中,此处为 mavenCentral(),远端仓库地址。

    • mavenCentral() :表示依赖从 Central Maven 2 仓库中获取。
    • jcenter() :表示依赖从 Bintary’s JCenter Maven 仓库中获取。
    • mavenLocal() :表示依赖从本地的Maven仓库中获取。
  • dependencies :声明了使用 Android Studio gradle 插件版本。一般升级Android Studio 或者导入从Eclipse中生成的项目时需要修改下面gradle版本。具体的版本对应关系,请点击
  • allprojects:设置每一个 module 的构建过程。在此例中,设置了每一个 module 使用 maven 仓库依赖。

settings.gradle

项目根目录下的 settings.gradle 中配置当前项目的 module

默认为:

include ':app'

如果 module 不在 project 根目录下,可以设置:

include ':app2'

project(':app2').projectDir = new File('path/to/app2')

如果有多个 module ,可以依次在 include 后加入,比如 include ':app', ':module1', ':module2' 这样。

(module)/build.gradle

在 module 下的 build.gradle 默认内容:

apply plugin: 'com.android.application'
android {

    compileSdkVersion 21
    buildToolsVersion "21.1.2"
    defaultConfig {
        applicationId "cc.bb.aa.myapplication"
        minSdkVersion 10
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
}
  • apply plugin: ‘com.android.application’: 表示使用 com.android.application 插件。也就是表示,这是一个 android application module 。 注:如果Module本身是一个依赖库,那么此时的 apply plugin 为 ‘com.android.library’ 相应的,若是一个Java project,apply plugin 为 ‘java’。对于库项目,与普通项目仅仅是 app plugin 不同,其他完全相同。

  • android: 配置所有 Android 构建过程需要的参数。

  • defaultConfig: Android 项目默认设置。

  • buildTypes: 编译类型。默认有两个: release 和 debug 。我们可以在此处添加自己的 buildTypes ,可在 Build Variants 面板看到。Android 项目规定必须至少定义一个 buildTypes。

  • minifyEnabled: 是否使用混淆。在老版本中为 runProguard ,新版本之所换名称,是因为新版本支持去掉没使用到的资源文件,而 runProguard 这个名称已不合适了。

  • proguardFiles: 使用的混淆文件,可以使用多个混淆文件。此例中,使用了 SDK 中的 proguard-android.txt 文件以及当前 module目录下的 proguard-rules.pro 文件。更多关于代码混淆的以及 ProGuard 的内容可以参看我的另外一篇文章。

  • dependencies: 用于配制引用的依赖。

  • compile fileTree(dir: ‘libs’, include: [‘*.jar’]) : 引用当前 module 目录下的 libs 文件夹中的所有 .jar 文件。

  • compile ‘com.android.support:appcompat-v7:21.0.3’: 引用 21.0.3版本的 appcompat-v7 (也就是常用的 v7 library 项目)。

在 Eclipse 中,使用 android support ,需要在 SDK 中下载 Android Support Library 。在 Android Studio中,使用 android support ,需要在 SDK 中下载 Android Support Repository ,且项目中使用的版本不能大于 SDK 中的版本。

buildTypes

默认情况,Android Studio 会给项目设置 debug 和 release 两个 buildTypes,当然开发者也可以定义自己的 buildTypes。

buildTypes 在 Gradle 中有如下作用:

动态增加或修改 ApplicationId

可以使用 buildTypes 来给 application id 增加后缀,比如

buildTypes {
    release {
        debuggable false
    }
    development {
        debuggable true
        applicationIdSuffix ".dev"
    }
    testing {
        debuggable true
        applicationIdSuffix ".qa"
    }
}

最后得到的 applicationId 会是这样:

  • com.package.android for release
  • com.package.android.dev for development
  • com.package.android.qa for testing

Signing Configuration 打包签名

如果想要使用 Gradle 来自动签名打包,可以使用这样的配置,避免在版本控制中提交密码。

~/.gradle/gradle.properties 中配置:

RELEASE_STORE_FILE={path to your keystore}
RELEASE_STORE_PASSWORD=*****
RELEASE_KEY_ALIAS=*****
RELEASE_KEY_PASSWORD=*****

并修改 build.gradle 文件:

android {
...    
signingConfigs {

   release {
       storeFile file(RELEASE_STORE_FILE)
       storePassword RELEASE_STORE_PASSWORD
       keyAlias RELEASE_KEY_ALIAS
       keyPassword RELEASE_KEY_PASSWORD
   }
}

buildTypes {
        release {
            signingConfig signingConfigs.release
        }
}
....
}

之后就可以使用命令或者Gradle面板中的 gradle assembleRelease 来生成签名的apk文件

混淆

关于 ProGuard 的内容可以参考这篇文章

buildTypes {
    debug {
        minifyEnabled false
        proguardFile('proguard.cfg')
    }
    release {
        minifyEnabled true
        proguardFile('proguard.cfg')
    }
}

其他基本配置

以下是一些 buildTypes 的基本配置,举例:

release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
    signingConfig  signingConfigs.myConfig
    debuggable false
    jniDebuggable false
    versionNameSuffix ".suffix"
    zipAlignEnabled true
    pseudoLocalesEnabled true
    renderscriptDebuggable true
}

buildTypes 支持的配置:

配置名称 作用
minifyEnabled 是否开启 Minify ,包括混淆和压缩代码
debuggable 是否编译出可调试的 apk
applicationIdSuffix 添加 application id 后缀
proguardFiles 添加 ProGuard 配置文件
jniDebuggable Whether this build type is configured to generate an APK with debuggable native code.
renderscriptDebuggable Whether the build type is configured to generate an apk with debuggable RenderScript code.
renderscriptOptimLevel Optimization level to use by the renderscript compiler
versionNameSuffix Version name suffix.
zipAlignEnabled Whether zipalign is enabled for this build type.
testCoverageEnabled Whether test coverage is enabled for this build type.
pseudoLocalesEnabled Whether to generate pseudo locale in the APK.
embedMicroApp Whether a linked Android Wear app should be embedded in variant using this build type.

外部依赖 compile

引用一个外部依赖需要使用 group, name 和 version 属性. 根据你想要使用的库, group 和 version 可能会有所差别.

有一种简写形式, 只使用一串字符串 "group:name:version" .

在 build.gradle 中,如下方式引入依赖:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile files('libs/liba-3.4.5.jar')
    compile project(':libraryName')
}

代码解析:

  • compile fileTree(dir: 'libs', include: '*.jar') ,可以将 libs 目录下所有 jar 文件进行编译打包。也可以使用 compile fileTree(dir: 'libs', include: ['*.jar'], exclude: ['xx.jar']) 中 exclude 这样的语法来排除某些指定的jar
  • 默认从远端 repository 中下载依赖并编译打包
  • 第二个是从本地 libs 目录下寻找 jar 文件,并进行编译打包
  • 将本地另一个 module 进行编译打包,被引用的 module 需要在 projectName/settings.gradle 中注册。

compile file、compile project、compile fileTree都可以看成是 compile 的子命令,

dependencies {
    provided files('libs/libb.jar')
    provided 'com.squareup.dagger:dagger-compiler:1.2.1'
    // 在测试环境下引用依赖。
    // 引用jar文件。
    androidTestCompile files('libs/xx.jar')
    // 引用Maven。
    androidTestCompile 'junit:junit:4.11'

    // 在release buildTypes分支下引用依赖。
    // 引用jar文件。
    releaseCompile files('libs/xx.jar')
    // 引用Maven。
    releaseCompile 'aaa:bbb:x.x.x'
}

如果使用的是 provided 则表示该依赖只在编译时使用,不在最后打包时使用。

Product Flavors

Product Flavors 用来管理不同的 release 版本,比如免费版和收费版。可以通过自定义 product flavors 来使用为不同的发行版设置不同的资源文件和代码,同时共享相同部分的资源和代码。 Product Flavor 设置是可选的,具体步骤可参考官网

reference


2016-11-16 Android , AndroidDev

Google+

最近文章

  • 将 MySQL 升级到 5.7 这些天折腾 Django 的时候用到了 MySQL,然而本地和VPS 上使用的版本不一致,本地使用了 5.7 版本,而 VPS 上使用了 5.5 的老版本,在数据迁移的时候遇到了 5.5 版本下不支持 DATETIME(6) 这样的数据类型。 DATETIME(6) 用来保存精确到微秒的时间。
  • Docker 入门 Docker 是一个能够把开发环境的应用程序自动部署到容器的开源引擎。该引擎的目标是提供一个轻量、快速的环境,能够运行开发者的程序,并方便高效地将程序从开发者的笔记本部署到测试环境,然后再部署到生产环境。 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。
  • 使用 nethogs 查看每个进程流量 在 Linux 上查看系统流量有很多命令,平时一直使用 iftop 来查看单块网卡或者系统整体的流量,iftop 可以查看 TCP 链接的流量情况,分析出流量连往的 IP 地址。但是 iftop 无法做到查看系统中单个进程的网络流量情况。所以 Google 一下之后发现了 nethogs 。
  • 使用 supervisor 管理进程 Supervisor (http://supervisord.org) 是一个用 Python 开发的进程管理工具(client/server),可以很方便的用来启动、重启、关闭进程(不仅仅是 Python 进程)。除了对单个进程的控制,还可以同时启动、关闭多个进程,比如很不幸的服务器出问题导致所有应用程序都被杀死,此时可以用 supervisor 同时启动所有应用程序而不是一个一个地敲命令启动。
  • MySQL 数据类型 了解并熟悉 MySQL 中的数据类型,对建表和数据库优化都非常重要。 MySQL 实现了 SQL 定义的类型,也响应的增加乐意 tiny, small, big 的类型。 MySQL 的数据类型主要分成三个部分: Numeric Type 数值型 Date and Time Type 日期和时间 String Type 字符型