Quantcast
Channel: IT瘾android推荐
Viewing all 101 articles
Browse latest View live

Android 高管谈 Lollipop:为何它是 Android 重大版本更新?

$
0
0

Hiroshi-Lockheimer

 

几周之内,市面上一部分 Android 手机将改头换面,Google 和运营商将陆续向用户推送最新的 Android 5.0 系统——Lollipop。作为 Android 迄今为止最重大的版本更新,Lollipop 针对开发者它提供了多达 5000 个的新 API 接口,用户界面和交互动画也旧貌换新颜。

为何说 Lollipop 是 Android 迄今为止最重大的版本更新?Lollipop 系统背后有哪些故事?Android 未来将走向何方?近日,在接受 Business Insider 的采访时,Android 技术副总裁 Hiroshi Lockheimer 对以上问题一一进行了阐释。

Lollipop 为什么是大更新?

androidmaterialdesign

 

Lockheimer 提到,Lollipop 的诞生是一个多年努力的过程,而无论是在 Google 还是在 Android 团队,迭代都是一个常态的工作。自从迭代了 Gingerbread 和 Honeycomb 之后,团队就酝酿着下一次针对于 UI 的更新,这就是 Lollipop。

Lockheimer 认为,Lollipop 对于 Android 的大更新并非从一开始计划的,而是由多种努力综合作用的结果,他提到了三个因素:

  • 首要的便是 Material Design。“这是一个巨大的努力,在重新思考用户界面和动态效果上它堪称一个里程碑。”
  • 技术层面,则归功于 runtime 的改变。新 runtime 在多任务管理上非常顺畅,而这让用户界面更加流畅。
  • 另外则是产业的进步——处理器从 32 位向 64 位演进。

功能如何迭代完美?

Lockheimer 表示,团队一直致力于让产品更加完美,但有些功能的可能需要经历两个系统版本才逐渐完美。

androidfaceunlock-1

 

以面部解锁(Face Unlock)的功能为例,这个功能最早出现在 Ice Cream Sandwich 上,尽管创意十足,但实际上可用性不高——必须在极好的光线条件下,手机才能慢吞吞地认出用户的脸。

Lollipop 对此进行了改进,为了保证更快地响应速度,系统会在用户拿起手机处理锁屏界面上的消息通知时,便自动激活面部解锁功能。

永恒的分裂问题

生态竞争和分裂是 Android 永恒的话题,对于 Android 系统的分裂问题,Lockheimer 从生态发展的良性一面进行了解释,他认为不能“一刀切”:

“这关乎取向问题,从缔造这个操作系统第一天起,我们就明白它并不只与一家公司产生关系,它不仅仅关乎 Google 或 HTC,它是一个涉及诸多公司庞大的生态系统,它的背后是一个联盟,正因为如此它才能发展得更快。”

以屏幕尺寸为例,开放的生态环境的确造就了不同屏幕尺寸的设备,早期 Lockheimer 就认为这是“成长的烦恼”——应用开发者要不断地针对不同的设备进行调整。但是现在再看,它不仅仅只是负面。人们正在从中受益,它创造了一个多样性的设备生态,根据不同场景,不同屏幕的设备也在满足不同人的需求。

Lollipop 是后 Andy Rubin 时代的产物

回顾 Android 的迭代过程,Lockheimer 说:

“Android 已经历经了 12 个版本,6 款设备,我们也收获了 10 亿多运行我们系统的手机用户。Android 已经今非昔比,我甚至不能再称它为创业团队,但有时它的确给我一种创业团队的感觉。我们扮演的角色以及团队的规模比外界预想的要小得多。”

如果从 Android 团队关键人物的影响看,作为 Android 的缔造者,Andy Rubin 此前一直是作为团队的核心领导 Android 系统的发展,但早在一年前,这位令 Android 扶摇直上的关键人物就已经调离 Android,Android 全面进入 Sudar Pichai 时代。

Lockheimer 透露,Lollipop 是 Sundar Pichai 接手 Android 项目后首个自主领导的系统版本,而 KitKat 项目则是始于 Andy Rubin,终于 Sudar Pichai。

“今年 Android 一个明确的目标就是,扩大这个平台,比如电视。”Lockheimer 说。

Android 高管谈 Lollipop:为何它是 Android 重大版本更新?,首发于 极客范 - GeekFan.net


Android 教程:将农历和天气装进新版 Google 日历

$
0
0

看过了我们刚刚发布的 新版 Google 日历试用体验,相信你对 Google 日历又有了新的认识。不过,国外的日历应用向来不自带农历,对于国人来说,用起来真倒是有些不便。下面笔者将一步一步示范,教大家在 Google 日历中添加农历。

第一步:PC 端访问 Google 日历网页版,需科学上网。如果你只会使用手机翻 X,可用手机浏览器打开上述链接,并切换到桌面版;

010f55be43649ec11d726399c14328b7_mw_800_wm_1_wmp_3

 

第二步:点击「其他日历」右侧的下拉按钮,并选择「通过网址添加」;

6b3081e8b7f856dcb6e446b409acc741_mw_800_wm_1_wmp_3

 

在输入框中粘贴以下链接,点击「添加日历」

http://www.google.com/calendar/ical/ug2j3l2nqq7uch3m9n0pm5t2lo@group.calendar.google.com/public/basic.ics

9a759a33eb79b2130920a5e736219f37_mw_800_wm_1_wmp_3

第三步:在手机上打开 Google 日历,点击刷新,再转到设置中,便可看见农历选项;

69c0fd569510ce42235fb1473ff3e910_mw_800_wm_1_wmp_3d8a40e7880cd113bf7c2c00957394c12_mw_800_wm_1_wmp_3

 

第四步:点击农历,并开启同步,农历日期就被添加到 Google 日历中了。

另外,我们还可以向 Google 日历中添加 iCal 格式的天气,这样打开日历就可以直接查看天气情况了。只需访问  http://weather.raychou.com/,搜索自己的所在地,在最下方选择格式为 iCal,并复制 URL,重复第二步和第三步即可。

1ea671687981745b7ddb697df0e7acd8_mw_800_wm_1_wmp_36804d43d322cfced6f7ac9b60b49f1a8_mw_800_wm_1_wmp_3

 

Android 教程:将农历和天气装进新版 Google 日历,首发于 极客范 - GeekFan.net

使用curl来调试你的应用

$
0
0

原文链接: http://stormzhang.com/devtools/2014/11/07/use-curl-debug/

我们在客户端开发过程中总免不了和后端进行api对接,有时候需要对返回的数据格式进行调试,有时候每次运行客户端来发送请求,这个未免效率太低,这里就来介绍一个好用的工具--curl。

curl

curl是一个向服务器传输数据的工具,它支持http、https、ftp、ftps、scp、sftp、tftp、telnet等协议,这里只针对http进行讲解一些常用的用法,具体安装请自行搜索。

打开百度

curl http://www.baidu.com

接着你就会看到百度的页面源代码输出。

如果要把这个网页保存下来,可以这样:

curl http://www.baidu.com > /tmp/baidu.html

你会看到一条进度条,然后源码就被重定向到了/tmp/baidu.html。

或者:

curl -o /tmp/baidu.html http://www.baidu.com

GET请求

默认直接请求一个url就是发出一个get请求,参数的话直接拼接在url里就好了,如

curl http://www.baidu.com/s?wd=curl

上述请求会上百度发起一条查询请求,参数是wd=url

POST请求

curl -d "name=test&page=1" http://www.baidu.com

-d参数指定表单以POST的形式执行。

只展示Header

curl -I  http://www.baidu.com

可以看到只返回一些header信息

HTTP/1.1 200 OK
Date: Fri, 07 Nov 2014 09:48:58 GMT
Content-Type: text/html; charset=utf-8
Connection: Keep-Alive
Vary: Accept-Encoding
Set-Cookie: BAIDUID=E9DB2F0AC95CB6BFDAD9D5CFDCED0A12:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BAIDUPSID=E9DB2F0AC95CB6BFDAD9D5CFDCED0A12; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=0; path=/
Set-Cookie: H_PS_PSSID=9725_9165_1465_7800_9452_9498_6504_9509_6018_9700_9757_9531_9478_7798_9453_9793_9024; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Cache-Control: private
Cxy_all: baidu+3057b288b211c770a1463cc8519b62a8
Expires: Fri, 07 Nov 2014 09:48:17 GMT
X-Powered-By: HPHP
Server: BWS/1.1
BDPAGETYPE: 1
BDQID: 0xfa28eff900012706
BDUSERID: 0

显示通信过程

-v参数可以显示一次http通信的整个过程,包括端口连接和http request头信息

curl -v www.baidu.com

* Adding handle: conn: 0x7ffe4b003a00
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7ffe4b003a00) send_pipe: 1, recv_pipe: 0
* About to connect() to www.baidu.com port 80 (#0)
*   Trying 61.135.169.125...
* Connected to www.baidu.com (61.135.169.125) port 80 (#0)
> GET / HTTP/1.1> User-Agent: curl/7.30.0> Host: www.baidu.com> Accept: */*>< HTTP/1.1 200 OK< Date: Fri, 07 Nov 2014 09:49:49 GMT< Content-Type: text/html; charset=utf-8< Transfer-Encoding: chunked< Connection: Keep-Alive< Vary: Accept-Encoding< Set-Cookie: BAIDUID=062E02D23FBB651CF8455B699DF02B64:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com< Set-Cookie: BAIDUPSID=062E02D23FBB651CF8455B699DF02B64; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com< Set-Cookie: BDSVRTM=0; path=/< Set-Cookie: BD_HOME=0; path=/< Set-Cookie: H_PS_PSSID=7744_1429_7801_9583_9499_6506_6018_9769_9699_9757_9532_9477_7799_9453_9716_9023; path=/; domain=.baidu.com< P3P: CP=" OTI DSP COR IVA OUR IND COM "< Cache-Control: private< Cxy_all: baidu+7dcb6b3c03d32c334d42f311919a14d6< Expires: Fri, 07 Nov 2014 09:49:20 GMT< X-Powered-By: HPHP
* Server BWS/1.1 is not blacklisted< Server: BWS/1.1< BDPAGETYPE: 1< BDQID: 0xadb706860000088f< BDUSERID: 0

如果你觉得上面的信息还不够,那么下面的命令可以查看更详细的通信过程。

curl --trace output.txt www.baidu.com

或者

curl --trace-ascii output.txt www.baidu.com

运行后,请打开output.txt文件查看。

HTTP方法

curl默认的HTTP方法是GET,使用-X参数可以支持其他动词。

curl -X POST www.example.com

curl -X DELETE www.example.com

Referer字段

有时你需要在http request头信息中,提供一个referer字段,表示你是从哪里跳转过来的。

curl --referer http://www.example.com http://www.example.com

User Agent字段

这个字段是用来表示客户端的设备信息。服务器有时会根据这个字段,针对不同设备,返回不同格式的网页,比如手机版和桌面版。

iPhone4的User Agent是

Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7

curl可以这样模拟:

curl --user-agent "[User Agent]" [URL]

增加头信息

有时需要在http request之中,自行增加一个头信息。--header参数就可以起到这个作用。

curl --header "Content-Type:application/json" http://example.com

Android Design的根本问题到底是什么?

$
0
0

注1:笔者从Android1.5用到Android5.0,一直很喜欢开放的特质,但很愤恨Google早期的设计资源投入和思考得太少。
注2:Android Design中有一些非常傻的细节点(iOS/WinPhone早期也有),简直让人失去对它的讨论兴趣,但现在改得差不多了,这里就略过不谈,主要针对现今的Android Design来说。

Android Design目前是一个比较差的设计标准(4.0之前属于很差,2.3之前属于垃圾/没有设计/没有思考),在Android Design成为一个较好的设计标准之前,不建议用户量超过1000万的App使用Android Design(国外的不同,具体见下)。

知乎/设计社区有一些喜爱和宣扬Android Design的人,说真的,你们主导的App可能比较难做到大的用户量(的同时仍被主流用户喜欢),需要思考一点,设计师们是应该为自己/为标准(形式主义、教旨主义)设计,还是为了好用/产品体验/被主流用户喜欢而设计。

给你们的爸爸妈妈,身边不玩机的主流人群用用所谓的标准Android Design设计吧。

绝大多数Google的东西设计得比较工程师思维、过于理性,对逻辑有思考,得出了逻辑清晰的设计结论(因而容易产生深信逻辑而不顾用户感情的信徒),但对小白(特别是落后国家的小白)和小白的接受/学习能力的思考太少。

许多Google的App,我用着是觉得不算太差的(但必须得去掉二维应用导航的抽屉设计、大多数侧栏设计、图标仅露出右边的一半以暗示滑屏还有内容,等等一大堆极差的白痴思路),如Inbox、Gmail,但我给身边的主流不熟悉IT的人用,发现简直在折磨他们。

可以认为,Android Design根本问题在于设计思路略显超前(嗯早期Android系统的问题就是没有设计,恶心程度简直不想举例,如果你跟我一样从Android1.5用到Android5.0,你也会懂)。估计决策者早已知道这个问题,但此时没有必要改思路了(改回原始而更容易接受的设计思路,不知多久的以后还得再改回来,没有必要)。

Google的纯粹逻辑思维设计(某些时候为了简洁而简洁,某些时候只看逻辑不看体验和认知)是工程师式的思维。从逻辑和道理上说都是对的,比如常用APP放桌面,不常用放抽屉,看似很有道理,但是小白理解不了(他们只在一个地方找APP,就是他们第一眼看到的桌面),或许在几十年之后,智能手机对每一个人类,就像遇到奶嘴就自然地会去吮吸时,Android Design的思路才是对的。找APP这个具体设计点,可以做一个“关于储物”的类比。人类初始阶段的储物,是在屋子内随处乱放的,在人类对空间和物品储存思路足够熟悉、物品足够多足够复杂后,才有储物柜、分门别类的抽屉的做法。 谷歌的设计就是略过了前面阶段,直接到了后面(从科学/工程师/纯理性/逻辑的角度来说,后面的做法当然是更对更先进的,但用户就是暂时接受不了)。

前面提到的国外的不同,其实就在于国外的发达国家的人们更利于尝试、更喜欢尝鲜,学习/接受速度更快。 给第三世界的国家像中国市场一样足够大的市场、激烈的竞争环境、较低水平的国民教育程度和理解能力(和公司/企业无关),这些国家的互联网/移动互联网产品的设计,也一定会趋于以触摸、直观、逻辑层级浅、逻辑维度少的设计风格和标准(也就是iOS设计标准之于Android设计标准)。

从这个角度来说,其实iPhone的设计思路也是在往Android Design的思路上靠(大量的教育用户的细节,变为了更多是简洁和注重内容展现。例子来说,给无前置教育的小孩子用iOS6比用iOS7,前者他更会用),但iPhone有过成熟的设计标准和持续几代的风格和设计细节延续。

或许过几年/几十年之后,人类对手机交互天然就会包括“滑动”这个操作(现在人类对手机交互的无前置认知只有触摸/点击,这是从几千年的实物操作中总结来的基因和经验)。到那时,大量采用滑动操作的设计才能被无前置教育的人快速接受。

而在此之前,更保守、直观、逻辑层级更浅、逻辑维度更少的iOS设计标准,始终要比逻辑正确、思维超前、追求简洁大于易理解、追求效率快大于好接受的Android设计标准,要好得多(好的标准是更受主流用户的接受、使用和喜欢)。

另参见:
有综合实力超过了 iPhone 的 Android 手机吗? – 邹剑波Kant 的回答

DHH 谈混合移动应用开发

$
0
0

 

1053-DHHDavid,Ruby on Rails 作者,37signals 合伙人

畅销书作家、演说家、赛车手、业余摄影师、顾家好男人

 

37signals在2013年2月发布了 Basecamp 的 iPhone app,在此之前我们就使用原生开发(native)还是混合开发(hybrid)做了许多尝试。在2012年项目启动的时候,大多数人都倾向于原生开发。

Facebook 在2012年发布了他们新的 iOS app,为了获得更好的用户体验,他们放弃了原来的 HTML5 混合开发方式。考虑到2010~2011年的时候,HTML 在移动端的性能确实不尽如人意,这个决定在当时看来也在情理之中。2010年的时候我们觉得 iPhone 3G/3GS 够眩够快,但按照现在的标准来看它们就太慢了。因此在为移动应用开发做架构设计时,我们需要考虑新的移动设备的计算能力,而不是那些老的过时的设备。

移动开发架构设计不需要过多考虑设备的性能

我们从一些测试中得出的一个结论是:现在的移动设备计算能力都很强,运行原生应用和 HTML 应用的效果差别不大,而 HTML 开发的成本则要比原生开发小得多。

当然这个结论在某些领域并不太适用。如果你要开发一个 3D 游戏,原生开发方式能够带来更好的游戏体验。但如果你的移动应用象 Basecamp 一样侧重信息处理,为了降低开发成本,你就可以考虑混合开发方式。我们就是如此,下面是我们三代移动产品的发展轨迹:

第一代产品:原生外壳(native shell)+嵌套WebView

1159-basecamp-app-phones

这个版本就是一个简单的原生外壳负责界面导航,嵌套一个 WebView 来显示 Basecamp Rail application,显示的基本上都是我们移动网站页面,再加上一些特殊的样式。

在移动网站的页面上嵌套一个原生的壳,听起来还是 Web 页面,但实际带给用户的体验确是非常不同。用户可以在 Apple App Store 找到我们的 app,他们一旦登录 app 后可以再也不用重新登录(移动版本的 Safari 似乎会经常清空 cookie,让你不得不重新登录)。我们的 app 大受欢迎,用户评分在4和5之间。

整个 app 由一名程序员和一名设计师开发,成本不高,因为我们可以在已有的移动网站的基础上开发。

如果我们当初开发完全原生的 app,用10个人的团队1年半的时间也未必能完成。

 

第二代产品:原生外壳+原生导航界面

1543-unnamed

几个月前发布的 Basecamp Android app 是我们的第二代产品,我们在其中做了大量的改进。

从第一代 iPhone app 中我们感受到了原生导航界面的威力,所以在 Android 版本中,我们由 HTML 页面导航转向了原生导航界面。我们从 HTML 页面生成原生导航界面,用户体验更加流畅,原生界面和 HTML 页面的体验差别越来越小,甚至很难区分哪些是原生部分,哪些是 HTML 。

Android 版本是由一两个程序员和一个设计师开发(50%投入)完成的。我们重用了移动站点和 iPhone app 中使用的所有 webview,大大提高了开发效率,同时用户也很买账,超过1000名用户打了4.5~5的高分。

很多公司在抱怨他们的 iOS 移动项目进展缓慢,Android 项目似乎更是如此。或许他们已经习惯了 iOS 项目的开发流程,也许是因为 Android 的屏幕碎片化问题,但是这些对我们来说那都不是事。我们推出的 Android app 表现良好,重用了95%的代码,开发团队也一直保持在小规模。

 

因地制宜地运用原生开发方式

目前我们正在开发第三代产品,发布的平台暂时保密,不过你应该也不难猜到。在前两代产品中,我们增加了原生导航界面的使用,同时进一步确定了以 webview 为核心的整体架构。在第三代产品中,我们将因地制宜地选择需要使用原生开发的功能,好钢要用在刀刃上。

从之前的100% HTML,到现在的90% HTML +10%原生,我们会选择最值得做原生开发的那10%的部分,最终目的是让 app 原生部分和 HTML 部分的体验没有太大区别。

 

混合开发模式使用的技术

混合开发模式在技术很简单,主要是处理 webview 的集成、Web 页面的加载,以及原生内容和 HTML 内容之间的交叉链接,其实可能比你想像的还要简单得多。

HTML 方面,我们的 Rails Web 应用支持 Web 和移动两大平台,其中  Rails 4.1 feature of variants 起了很大的作用。

这也很大程度上有助于我们发布新功能。设想一下如果我们每次需要更新这么多平台:Rails desktop app, a Rails API app, a client-side MVC app, a mobile web wrapper app, an Android app, and an iPhone app,像我们这样只有10个程序员和7个设计师的公司根本无力承担如此巨大的工作量。

除了工作量的减轻,bug 修复效率也提高了,因为大部分的代码逻辑是在 Web 服务器端,我们可以随时修改代码并发布,不用通过 Apple App Store 的审批流程。所以我们的移动 app 和 Web 应用一样,也是持续部署。

就如我之前提到的,混合模式开发并不适用于所有情况。在2010年以前,那时手机的处理能力都不强,所以 HTML/JS 的体验并不好,用户也不喜欢。但是时过境迁,现在手机的处理能力大大提高了,HTML/JS 的性能也不再是一个问题。

 

混合开发模式对原生开发模式的挑战

混合开发模式在降低开发复杂度方面有它的优势,如果你的产品是以显示和处理信息为主,我认为都可以不同程度地采用这个模式。

对于小型团队和公司而言,并不一定需要采用 iOS 原生 app 先行的模式。使用混合模式,不需要你重头开发一个 app,这样可以降低维护成本,将来扩展到其他平台也更为方便。

当然我知道会有很多人质疑这个模式,或许因为他们的 app 中有很多地方需要原生开发(也许仅仅是他们自己这样认为罢了)。又或许他们已经花了很多时间让 app 里的 UITableView 看起来非常漂亮,以致如果其他地方不这样的话显得不是太完美。再或许大公司就是喜欢耗时耗力的原生开发,有钱就是这么任性。

无论怎样,混合开发当下应该能够成为我们移动开发策略的一个选择。如果你认为这是一个好的选择,那么恭喜你,尽情愉快地玩耍吧!

 

原文链接: Hybrid sweet spot: Native navigation, web content

 

下面补充一些 David 答读者问:

 

Mike Waite @ 2014-05-08:我很好奇你是如何决定哪些功能要用原生开发?
David @ 2014-05-08:主要靠感觉,这毕竟不是一门科学。如果你感觉你app的某一部分如果用原生开发会更好些,可以尝试做快速原型(spike)。很多时候我们通过这种方式证明我们的想法其实是错的。当然如果你需要使用到手机上的功能如:摄像和其他设备时,HTML目前还不太适用,不过永远也不要把话说死。

 

Mike Parsons @ 2014-05-08:好文。很好奇你们是否使用 PhoneGap 或者 Cordova 这样的框架,或者你们自己开发了一个?
David @ 2014-05-08:我们没有使用任何框架。(此处省去xxx字)

 

Derick @ 2014-05-08:你怎样解决 Android 浏览器渲染速度慢的问题?这也是 Android 平台上更多人倾向开发原生app得原因。
David @ 2014-05-08:不知道你这个结论是近期的还是以前的?Basecamp 的 Android app 在我的 Nexus 5 和 HTC One 上面运行得非常流畅。
Derick @ 2014-05-08:就是最近。我猜测可能和你使用JavaScript的多少有关系。因为以我个人的经验,Android 上 JavaScript 的运行速度非常慢。如果你感兴趣可以看看下面的文章: https://www.timroes.de/2013/11/23/old-webview-vs-chromium-webview/
David @ 2014-05-08:我们使用了很多JavaScript,当然没有 Web MVC 客户端用得那样多。另外我们使用了 Turbolinks :)

 

(转载本站文章请注明作者和出处 酷 壳 – CoolShell.cn,请勿用于任何商业用途)

——=== 访问 酷壳404页面寻找遗失儿童。 ===——

相关文章

HTML5 标准终定稿, 能否引领下一波技术热潮?

$
0
0

html5印象里第一次接触到 HTML5 还是在 Steve Jobs 那里,他坚持在 iOS 上面放弃对 Flash 的支持,力推 HTML5。在当时 Adobe 的 Flash Player 统治浏览器播放器的年代,这种做法想必也就只有 Apple 有勇气做得出来。Apple 用 HTML5 想要打破 Flash 打造的一个封闭生态圈,到现在大家也都有目共睹,Adobe 在由 Apple 引领的这次移动浪潮之中被远远抛在后面;移动端的播放器不再是 Adobe 统治的天下,使用 HTML5 的 <audio> 和 <video> 标签更加方便了多媒体的开发。伴随着 Google 推出自家浏览器 chrome 以及开源版本的 chromium,HTML5 的特性一致在被有力的支持和推动下发展。而现在 HTML5 标准的定稿,势必会是互联网的一个里程碑。

2007 年 W3C 立项 HTML5,到 2014 年 10 月底正式定稿,时间长达 8 年。接下来 HTML5 将真正开始颠覆 Native 原生 App 世界这样的论断是否还是危言耸听呢?我们拭目以待。
接下来我们来聊一聊 HTML5 的诞生:

W3C 在 1999 年发布了 HTML4 之后, Web 世界迅猛发展。人们一度认为 HTML 标准不再需要升级了。直到 2007 年 W3C 从一家致力于 Web App 开发的组织 WHATWG 接手了相关工作,重新发展 HTML5. HTML5 的发展,有用户需求的推动,有技术开发者的需求推动,更有巨大商业了利益在推动。

随着硬件的发展以及网络带宽的大幅改善,人们已经不再满足于能否打开一个基本的页面浏览信息,更丰富,更流畅的多媒体体验需求变得日益强烈。以前开个电影、视频,需要买个盘回去用光驱看;以前玩个游戏得买个盘安装然后玩,随着网络的改善和已经的提升,打开网站就可以播放流畅的 vod 视频,打开网页就可以玩流畅的页游(网页游戏)。在这一段时间里,HTML 标准并没有跟得上时代的脚步,Flash 抓住了这个机会,开始在互联网上变成了准标准。视频播放器以及网页游戏,都依赖 Flash 进行开发,Flash 提供的体验是 HTML 当时的标准所提供不了的。整个互联网事实上变成了微软(PC端操作系统) + Flash(网页端)统治了。

这个时候 Google 和 Apple 坐不住了。PC操作系统端很难有突破,因此 Web 浏览器被寄予厚望。 Google 大力赞助 Mozilla 的 Firefox 但并没有对 IE 主导的地位产生影响;收购了 Youtube 后发现命脉掌握在 Adobe 手里,非常不高兴。而且 Google 还要给 IE 的搜索框以及 Adobe 的 FLV 缴纳价格不菲的费用。因此也催生了 Web 标准的下一代 HTML5。

关注 HTML5 的朋友,想必都还记得 Facebook 放弃 HTML5 选择 Native 原生 App 的事情。这里有两个事情不得不提,第一个 HTML5 只是一个标准,就如同 C++ 一样, VC++ 和 GCC++ 在一些标准的支持上面和实现上面就存在不少差异,不同的浏览器厂商对于标准的支持力度也不一样,力度最大的应该就是 Apple 的 Safari 和 Google 的 chrome 了。尽管如此,在 Android 上,默认采用的 Webview 并不如 Google 大力推进的 chrome/chromium 支持的更好,Apple 也在 App 开发端限制使用第三方浏览器内核仅开放有限的接口调用,同样阻碍了采用 HTML5 开发的 Web App 的体验。尽管如此,我们仍旧看到了 HTML5 的潜力:
1.离线存储 解决断网情况下无法继续使用的问题
2.流媒体 audio video
3.游戏 webgl canvas
4.更丰富的表单,js线程,socket,以及css3

HTML5 新增的标签header、footer、article等优化了搜索引擎的搜索,并且在无障碍体验方面做了不少支持。HTML5 在流媒体和游戏方面成功遏制了 Flash 的发展。
在 HTML5 标准升级的过程中,Google 和 Apple 不仅大力支持和宣传 HTML5,并且在浏览器方面也做了不少工作。Apple 大力发展 Webkit,并且把 Safari 带到了 Windows 平台; Google 大力赞助 Mozilla,而后开发 V8 引擎,进而推出 chrome 浏览器。这个时候 Web 标准的发展步伐在显著提升。由于 chrome, Safari, Firefox 都在 Web 标准上给予非常多的支持,在 chrome 推出前,Web 开发者最爱的浏览器就是 Firefox 不单单是因为 Firebug 这个强大的辅助开发工具,更多的是因为 Firefox 更加标准,对标准的支持更好。而这个时候反观 IE 已经明显还没有反过神来, IE 7 8 9 10 一系列不完整支持标准又互不兼容的版本,彻底伤透了开发者的心。

由于 HTML5 标准,开发者开发的时候,完全可以不再需要单独一个 Flash 开发者,或兼职 Flash 开发,并且可以大大降低 Flash 引发的安全问题以及 Flash 插件的崩溃问题。这样一来开发者的开发体验更爽了,用户的浏览体验也上升了。

随着以 Apple 的 iOS 和 Google 的 Android 为首的新一代智能手机平台的到来,智能手机真的智能起来了。因为 iOS 和 Android 就是按照现代操作系统的理念来设计的,并不是按照嵌入式系统来设计的,这样一来就更加容易和 PC 上面的体验达成一致,而且功能和 PC 一样强大。由此催生的移动互联网的热潮,一波又一波功能强大的 App 丰富了平台的体验,Apple 的 AppStore 和 Google 的 GooglePlay 成为开发者最热衷的平台,在这里没多长时间就出现用户量千万甚至过亿的产品,这些在 PC 端需要积累十几年时间才能达到。

HTML5 的跨平台优势在移动互联网时代进一步显现。HTML5 是唯一一个通吃 PC, MAC, iPhone, iPad, Android, Windows Phone 等的跨平台语言。如果 HTML5 已经可以满足功能和性能的需求,那么一个懂 HTML5, CSS, Javascript 的开发者就可以很快推出不用跨平台编译的跨平台 App,而且版本迭代会更快。在当下这样的需求不能满足的情况下,一些跨平台的工具给了我们另一种选择的尝试。PhoneGap 就是其中非常知名的一个。Adobe 在看到了 PhoneGap 有可能让自己重振江湖的机会,就把 PhoneGap 收购了。但后来发现 PhoneGap 里面问题不少,而且开源的 PhoneGap 无法让 Adobe 的 Flash 那样获得商业利益,就把 PhoneGap 捐给了 Apache。

开放注定是互联网的未来。

即使如 Google 和 Apple 营造的 App 生态圈也一样,在庞大的互联网里面,TA 们只是一个小圈子。HTML5 就是这个开放的标准,打破巨头的垄断。 Facebook 为什么采用 HTML5 试水自己的 App 是不想被 Apple 和 Google 的生态圈所禁锢,不想被 iOS 和 Android 牵着鼻子走。话说回来,谁不是呢?
那么曾经的功能不健全的和巨头支持欠佳的 HTML5 现在定稿之后,是否真的会引发下一波技术浪潮呢?

首先从硬件方面来说,随着 Apple iPhone6 的发布,硬件性能的提升,已经抹平了 HTML5 的性能劣势。 Apple 和 Google 的策略也在发生变化,在 2013年底 Google 发布的 Android 4.4 内置的 Webview 已经不再是 Android Webkit 了,而是 chromium。2012 年的 iPhone5 上面的 HTML5 表现已经令人满意,Safari 独家的 Javascript 加速引擎 Nitro 已经不再那么重要。而且在 iOS8.0 发布后,Apple 还取消了第三方程序调用 Nitro 的限制,现在任意浏览器或应用调用 iOS 的 UIWebview 都可以利用 Nitro 加速。两大移动巨头有意或无意的改变,让 HTML5 再说手机平台上面的发展不再受限。

跨平台在多屏时代给开发者非常痛苦的体验,人们都期待当年 Java 的一次编译处处运行的理想情况。 HTML5 目前正在扮演一个开发者救星的角色。
并且采用开放标准的好处多多,比如入口更多、导入流量更容易,超级 App (微信朋友圈)、搜索引擎(可以直接搜索应用内部关键词,这个一直是 Native App 的弊端)、应用市场、浏览器,而原生 Native App 就只能是 AppStore。

好了以上就是写在 HTML5 定稿的一些感受和猜想,愿此文可以给大家一些启示或帮助。

关于 Android 安全的六个问题

$
0
0

Security-breach

由于 Android 的开放性,安全问题一直是人们关注的焦点。每当安全公司爆出手机恶意软件,Android 用户都要提心吊胆一番。为此,你或许已经安装了杀毒软件,安装软件也开始小心谨慎了。不过,Android 安全问题真的非常严重吗?我们不妨看看权威人士的看法。近日, Androidcentral 网站邮件采访了 Android 首席安全工程师 Andrian Ludwig,提到了六个方面的问题。

Google 扮演了什么角色

在设计 Android 的时候,Google 加入了许多层的安全措施。从系统层面上,有应用沙盒、SELinux、ASLR(地址空间配置随机加载);从应用和服务上,有 Google Play、设备管理器、应用验证。同时,Google 也鼓励第三方提供安全方案。当 Google 了解到新型的潜在风险后,也会将其考虑到未来的计划中。Andrian Ludwig 认为,移动设备最紧迫的安全问题包括:设备被盗;网络层面的攻击;恶意的应用程度。在这些方面,Google 都采取了应对措施。

Google 有什么样的支持策略

对于潜在的安全风险,Google 提供了不同类型的支持:

  • 如果安全问题能够通过升级Google 应用( Chrome、Gmail、Google Play 等)解决。那么,所有版本的 Android 都能够得到应用更新。
  • Nexus 和 Google Play Editon 设备能够及时得到安全升级。
  • Google 向 AOSP(Android 开源项目)提供补丁,并且直接向 Android 厂商提供补丁(至少支持最新的两个大版本)。如果厂商要求向老版本提供安全补丁,Google 也会提供帮助。
  • Google 会向所有的 Android 设备提供安全服务 ,即使这些设备已经不被厂商支持。
  • Google 向应用开发者提供必要的信息和工具,帮助他们对抗安全风险。
  • Google 会与厂商分享安全方面的信息。同时在进行系统兼容性测试的时候,也会对潜在的安全问题进行测试。

用户可以使用什么工具

Android 向用户提供了一系列的控制选项,比如,用户可以看到应用权限、限定其行为。当用户不想看到某项通知,可以在通知中心长按,看看通知来自那个应用。然后,用户可以关闭通知或者卸载应用。

如果用户忽视了安全警告呢

在对付恶意应用方面,Google 提供了多层安全措施。首先,Google 应用中集成警告系统,比如,用户使用 Chrome 下载软件之前,就有可能得到警告说,这是一个有恶意软件的网站。然后,如果用户决定下载软件,安装阶段会再次得到警告。再次,即使应用被安装,在运行前也不会做任何事情,用户仍有机会卸载它。最后,应用验证服务会对恶意程序进行标记,并且定期提醒用户卸载它。

第三方安全软件有用吗

Google Play 的安全措施是非常 。如果用户选择 Google Play 以外的软件,最好打开应用验证的功能。2014 年,Google 从应用验证收集的数据中发现,美国地区,在 Android 设备中安装的 Google Play 外应用中,恶意应用不超过 0.15%。因此,用户安装第三方安全软件,并没有太大的意义。

第三方 ROM 是否安全

一般来说,第三方 ROM 都是基于 AOSP 的,因此,Google 的安全措施也适用于这些 ROM。它们都支持应用沙盒,使用 Google 应用,包括 Google 的安全服务。

图片来自 tweaktown

It is well that there are palaces of peace,and discipline and dreaming and desire.

#欢迎关注爱范儿认证微信公众号:AppSolution(微信号:appsolution),发现新酷精华应用。



爱范儿 · Beats of Bits |原文链接· 查看评论· 新浪微博· 微信订阅· 加入爱范社区!


从零开始学Android应用安全测试(Part1)

$
0
0

在本系列文章中,利用InsecureBankv2这款含有漏洞的安卓应用,我们可以了解到有关安卓应用安全的种种概念。我们将从一个新手的角度看待每一个问题。所以,我建议新手朋友可以关注下本系列文章。

由于教程是从零开始,前面的东西不免会比较基础,老鸟请先飞过吧。

移动渗透平台搭建

在对安卓应用测试之前,我们需要搭建一个合适的移动渗透平台。

首先,我们需要下载Eclipse ADT bundle,并安装。这里我就不再过多重复造轮子的事情了。

这里面有俩个文件夹,一个叫 tools,另外一个叫做platform-tools。这俩是非常重要的,是需要加入环境变量里面的。以下命令可以用来添加路径到环境变量中

export PATH=/path/to/dir:$PATH.

将tools和platform-tools文件夹都添加到环境变量中,完成操作过后,你就可以随意的使用所有的命令了。然后检查是否工作,可以键入adb命令,你可以得到以下的输出结果。

为了保证应用能够在我们的计算机上运行,我们还需要一款趁手的模拟器。Eclipse Android Virtual Device就是一款安卓模拟器,如何进行创建虚拟设备,朋友们可以在网上搜搜。然而,对于本系列文章,我会使用另一款工具Genymotion 来创建虚拟设备。这里有许多原因,其一是处理速度比较快,其二使用Genymotion创建的虚拟设备默认是自动获取了root权限的。这也就意味着,你可以自由的安装应用,对于审计安卓应用也方便。

完成Genymotion的安装后,你需要注册一个账号(免费的)并基于你的需求创建不同模拟器。

好了,现在我们就将InsecureBankv2的源代码从github上克隆过来。

打开你创建的虚拟设备,这一步骤十分简单。

在刚才从github克隆的项目文件中,存在一个apk文件。你可以使用adb install InsecureBankv2.apk 命令来安装这个应用。

在上图中你可以看到success,这就表示这个apk文件已经成功安装了,同时你在模拟的设备中看到对应的应用图标。但是有时候你可能只是想编译这个文件而不是运行这个apk文件。这个时候你就需要打开Eclipse找到 File -> Switch Workspace,选择你创建的 Insecurebank文件夹,然后转到File -> Import并选择现有的Android代码放进工作区。

选择应用程序所在的文件夹,你可以看到Eclipse已经将应用程序放进了你的工作区。

这时候你就可以点击上端的play按钮,开始运行这个应用。在保证模拟器正常运行的情况下,选择运行安卓应用。

不出意外,这时候你就可以看到应用在模拟器中成功运行了。

同时启动后端的python服务,可以使用这个命令

python app.py –port 8888

在这个应用中填入ip地址以及端口。

现在你就可以使用默认凭证登录这个应用了。

dinesh/Dinesh@123$
jack/Jack@123$

请确保你安装了以下工具,在我们以后讨论的细节中,会用到的。

Drozer
Andbug
Introspy
dex2jar
apktool

另外,可以使用adb shell连接你的模拟器,然后看看你想要做些什么。

安卓命令合集

希望大家在空余时间多看看安卓命令[ http://developer.android.com/tools/projects/projects-cmdline.html]。

真心推荐大家多到这里了解下adb[ http://developer.android.com/tools/help/adb.html]尝试着玩转大多数命令。

下节预告

在下一篇文章中,我们将了解下InsecureBankv2项目中存在的各种漏洞,更详细的了解安卓应用的安全性。

InsecureBankv2项目地址: https://github.com/dineshshetty/Android-InsecureBankv2

Eclipse ADT bundle: https://developer.android.com/sdk/installing/index.html?pkg=adt

译者鸢尾注:此文原作者曾经完成了iOS安全专题。基于其完成度,鸢尾愿意跟着作者的步伐,一步一步的从零单排。

[参考来源infosec,翻译/鸢尾,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)]


Android 分类法:六个类型,八种用户

$
0
0

c350e-android

Android 是一个如此丰富而且复杂的生态圈,以至于人们谈论它的时候,常常讲述的是不同的东西。在个人博客上,风险投资公司安德森-霍洛维茨基金合伙人、科技博客作者 Benedict Evans分析了不同类型的 Android,并且对 Android 用户进行了归类。

他认为,市场上的 Android 可以分为六类:

1、“原生” Android。只出现在 Google 的 Nexus 设备上,完整的 Google 服务,销量很少。
2、三星、索尼、LG 等厂商的“定制”Android。完整的 Google 服务。改动上没有什么亮点,不过经过 Google 许可。
3、“AOSP” 或者开源的 Android。在中国市场上,可以看到与 2 中提到的手机,但是去除了 Google 服务。
4、小米及其追随者的“定制”Android。这些手机在国外也有用户。在中国,它去掉了 Google 服务,但是在其它地方却是包含 Google 服务的。
5、第三方的 ROM,比如小米的 MIUI 和 CyanogenMod。它们可能包括 Google 服务,也可能没有。由于对系统进行了优化和改进,赢得了一些用户。
6、Android 分支。比如亚马逊的 Fire 手机。这是对 Android 进行了重度修改,做出了完全不同的体验,因此,Google 拒绝其运行 Google 服务。小米和 Cyanogen 都不是分支。

其中,前两类(或许也可以包括第三类)是“封闭的”Android,后三类是“开放的”Android(从厂商的角度来看)。从用户数量来说,前两类 Android 的用户有 10 亿用户,是中国以外的;第三类和第四类有 4 亿到 5 亿用户,几乎都在中国。第五类 Android 的用户大概有 5000 万,中国和中国以外都有,并且,这些用户与其它类型用户存在重合。至于第六类 Android 用户,只有亚马逊才知道吧。

同样,Android 用户也可以分为许多种。

1、使用第三方 ROM 的用户。
2、那些喜欢安装各种应用,以完成 iOS 上不允许之事的人。
3、那些对 Android 有个人喜好的人。他们不会去装第三方 ROM,或者去做些 iOS 上禁止的事情。
4、那些并不关心系统的人。他们选择 Android 的原因,或许是因为硬件设计,或者因为大屏幕。
5、那些买不起 iPhone 或其它高端手机的人。
6、那些并不在意智能手机的人。他们只是想买个便宜的手机,并不会对生态圈投入什么东西。
7、那些只能买得起 50 到 100 美元 Android 手机的人(新兴市场),但是,他们非常热情地探索各种功能。
8、与第 7 类接近,但是,他们有相对昂贵的网络套餐,受限的 3G 覆盖,并且,他们给手机充电都比较受限。这是智能手机接下来要覆盖的下一个 10 亿人。

“旧金山和雅加达的青少年,拥有的必备手机是非常不同的。不过,上述列表的重点在于,科技和移动市场的发展已经远远超过某个点,不会再有满足一切需要的单一市场了。当你把每个人联系起来的时候,你就会得到每一个人,而且他们都与你完全不同。” Benedict Evans 总结说。

It is well that there are palaces of peace,and discipline and dreaming and desire.

#欢迎关注爱范儿认证微信公众号:AppSolution(微信号:appsolution),发现新酷精华应用。



爱范儿 · Beats of Bits |原文链接· 查看评论· 新浪微博· 微信订阅· 加入爱范社区!


数据来看,Android 还是挺安全的

$
0
0

android-960x854-wallpaper-832

Google 近日公布了一份白皮书,详细记载了 Android 安全小组去年一整年的工作内容。

从白皮书中可以看出,Google 需处理的每一个安全威胁的重要程度。据记载,2014 年 Google 共标记 79 个漏洞,其中 41 个为低危漏洞。这些安全威胁根据严重等级区分,相比 2013 年缓和不少。

The Verge报道,Google 从未停止打击恶意程序(PHA),文件称 2014 年全球恶意程序安装比例下降了 50%。Google 的数据则显示,去年受 PHA 干扰的手机只有不到 1%。而从 Google Play 检测到的 PHA 比例则下降到 15%。

去年 10 月,安全的 Android 设备百分比为 99.5%,这竟是去年最低值。由此可见,Android 设备总体安全性来讲,还是非常高的。不过,这项数据没统计 root 过的手机,Android 手机 root 后等于将安全设置从系统中完全删除。国内来说,root 现象尤为严重。

3044608-inline-i-3-androidgoogle

值得注意的是,安全最低值出现在 Android 4.4 更新和 Android 5.0 推出之前。这表明 Android 系统更新后增加的磁盘加密、访客模式,并改进身份验证方法,这些都真正加强了系统的安全性。开发者们也增加了访问工具来检测和修复漏洞,这更有利于加快找到漏洞修补方案。

Google 公布的 79 个漏洞中,73 个已经转交给 Android 开源项目组,剩下 6 个有待观察。据 engadget 报道,手机制造商和运营商都会及时收到漏洞信息,以便在普遍发现前找到修复补丁。这份文件还详细描述了 Google 如何在 Android 系统强化安全措施。

不过,该文件并未提到此前发现的 WebView 漏洞,它影响到运行 Android 4.1 及更早版本的手机。今年早些时候,Google 曾表示 不再为 Android 4.4 以前版本出官方补丁。Android 4.4 仍被广泛使用,约占 41% 的份额,4.4 之前版本也占据不小份额。

Google 的安全防范已升级到 Google Play,他们希望通过整体安全网络来保卫用户,以免除网络攻击的困扰。目前,安全小组在每一百万个应用中能发现一个恶意程序。此外,Google 也在密切留意 Chrome 扩展,上周他们宣布禁用了近 200 个不良扩展,这些扩展总体影响到 1400 万用户。

3044608-inline-i-1-googleandroid

据 Google 统计,Verify Apps 服务会对 Android 设备中的应用持续监控,约 10 亿 Android 设备接受其安全保护,每天就有超过 2 亿设备进行安全扫描。但是,Google 这样做可能侵犯到用户隐私。对此,Google 补充表示,可以保证用户的照片、位置数据以及个人信息等都不会出现任何形式的窃取和泄露。

 

题图源自 dailymobile,插图源自 FastComcany

这时代,很带感。

#欢迎关注爱范儿认证微信公众号:AppSolution(微信号:appsolution),发现新酷精华应用。



爱范儿 · Beats of Bits |原文链接· 查看评论· 新浪微博· 微信订阅· 加入爱范社区!


关于移动端的钓鱼式攻击

$
0
0

phishing-1今天,在微博上看了一篇《 微信和淘宝到底是谁封谁》的文章,我觉得文章中逻辑错乱,所以,我发了一篇 关于这篇文章逻辑问题的长微博。后面,我被原博主冷嘲热讽了一番,说是什么鸡汤啊,什么我与某某之流的人在一起混淆视听啊,等等。并且也有一些网友找我讨论一下相关的钓鱼式攻击的技术问题。所以,我想写下这篇纯技术文章,因为我对那些商业利益上的东西不关心,所以,只谈技术,这样最简单。

首先说明一下, 我个人不是一个安全专家,也不是一个移动开发专家,按道理来说,这篇文章不应该我来写,但是我就试一试,请原谅我的无知,也期待抛砖引玉了,希望安全的同学斧正

关于钓鱼式攻击,其实是通过一种社会工程学的方式来愚弄用户的攻击式,攻击者通常会模仿一个用户信任的网站来偷取用户的机密信息,比如用户密码或是信用卡。一般来说,攻击者会通过邮件和实时通信工具完成,给被攻击者发送一个高仿的网站,然后让用户看不出来与正统网站的差别,然后收集用户的机密数据。

移动端钓鱼攻击点分析

因为钓鱼式攻击并不新鲜,所以我这里只讲移动方面的。

在移动端,这个事情会更容易干,因为移动端有如下特点:

  • 移动端的UI只能有一个应用占据整个屏幕,你只能看到一个应用,而且用户屏幕小,能显示的信息有限,比如浏览器里的网址是显示不全的。这会给钓鱼攻击有很多可乘之机。
  • 移动端的平台有其安全的设计。每个应用都是隔离开的,一个应用无法获取另一个应用的数据。而且应用的下载基本上来说都是来自合法的地方。比如iOS的设备通过App Store下载,每个程序都有自己的签名保证不会被篡改。而且移动端的的应用有各种权限配置,这样也能很大程度提高安全性。
  • 移动端的APP有些有些是收费的,所以自然会有盗版需求,虽然在平台上做了一些安全设计,但是并不完美。用户可以越狱,可以root。这给恶意软件有了可乘之机。

下面我们来分析下移动端的用户操作,我们重点关注用户控制权的切换过程(因为这是攻击点)

在移动设备上,基本上来说,用户的控制切换有四种:

  • 从一个APP切到另一个APP,也就是我们所谓的唤出APP。
  • 从一个APP唤出一个Web,常见为一个嵌入式的WebView或是一个浏览器
  • 从一个Web唤出一个APP,这需要浏览器支持一些非标准的HTTP协议,比如skype://之类的。
  • 从一个Web到另一个Web,这和Web上的方式差不多。

基本上来说, 黑客的攻击从来都是找这样的转换环节来做文章的,并且需要一个用户非常熟悉的场景(这样用户才会放松警惕)

通过观察移动APP的特性,我们可以知道,当用户控制切换时,有下面的这些特性:

  • 到另一个APP时,需要用户登录(如果登录的session过期了)
  • 当支付的时候,需要用户输入支付信息(信用卡信息、支持密码)

那么用户在移动APP上经常做的事是什么?

  • 社交分享:分享到微博,分享到微信等等,分享的时候,可能需要你输入用户名和口令。
  • 应用内购:一般来说APP会有两种,一种免费的,一种是收费的,大量的用户都是下载免费的,然后通过什么“开通更多关卡”、“去广告”、“买道具”之类的东西,让用户输入支付信息。Apple的支付的时候也会要用户输入Apple ID的密码。
  • 点击链接:有时候,我们收到短信,或是二维码,或是一个微信微博,会让我们去点击一个网站链接,这个网站链接要么就是打开一个网页,要么就是启动应用,要么就是跳转到应用市场去下载应用(如果你没安装)。

所以,一个好的钓鱼式攻击一定会从这些地方入手,然后高仿UI以及交互流程,这个交互流程和用户日常操作的完全一样,让用户无法察觉。任何方式的钓鱼攻击简单来说,会有两种:

  • 一种是直接攻击:你下载了一个恶意的APP,或是打开了一个恶意的冒牌APP。
  • 一种是中间人攻击:用户控制权转换时的两端都是正规应用,但是中间的过程不是正常的。

攻击方式

下面是一些常见的攻击方式:

从一个应用唤起另一个应用的方式

直接攻击

当你点击一个社交分享按钮,或是一个支付按钮的时候。就会转到一个页面,这个页面需要你输入用户机密信息(密码或是支付信息),然后再唤起真正的APP。

一个有恶意的APP可能会让你放松警惕,因为,这个你在安装这个APP的时候,你会发现这个APP根本不需要任何的权限(Android上的),甚至连网络访问的权限都不要,因为在Android下,App可以通过别的组件访问互联网,比如:恶意应用可能创建一个MediaPlayer Object,然后就可以通过这个对象访问一个URL然后把偷到的信息发送出去。

你的手机要被安装一个恶意的应用并不难,同样通过社工的方式,比如:盗版,色情,伪装成客服等等通过人性的弱点让你去一些非受信的市场上安装。iOS设备上的应用也可以不用通过App Store安装(通过itms-services协议,可以通过safari浏览器直接在IOS设备上安装应用程序)。

还有,人们都是贪小便宜的人,所以,会到某些地方买一些便宜的手机(比如淘宝),现在的高仿手机,翻新的二手手机对于一般人甚至安全专家来说完全没有识别能力。这些手机中有很大可能藏有恶意程序。你千万不要以为你格式化手机就OK了。今天(2015年4月14日)早上CCTV2台的“第一时间”就说了一个案例,你可以看看。另外,你可以看看相关的新闻。(另外,你把你的旧手机卖了也要小心,因为你的数据就在里面,旧手机已经成了一个灰色产业链)

另外,Apple的App需要有一个review过程,这个过程对大众是神秘的,但我觉得应该会包括安全方面的review。不过,这个审核过程可能也有空子可以钻。比如:在review的时候,这个应用完全正常,但在用户使用的时候,会自己从网站下载一些自己的配置文件而改变行为(更为直接的就是访问外部网页时在审核时和在用户应用时可能完全不一样,Apple应该完全没有能力审核应用要访问的外部站点)

中间人攻击

我们知道,一个APP唤起另一个APP好多都是用url-scheme的,也就是某种协议,审核这样的协议非常简单,所以如果有恶意的东西在里面基本上很容易看到。但是,如果某些APP并没有注册自己的url-scheme,或是没有被安装,反而,另一个有恶意的APP注册了这个scheme,那么,就会导致恶意的APP被唤起来了( 这就是我为什么在我的微博中说,如果用户没有安装淘宝的客户端,那么,让微信唤起淘宝的客户端时,有可能是另一个有恶意的APP。但是很多人不懂这个事。在iOS下,两个APP通讯正确的做法是“钥匙串机制”)。

当然如果有两个应用被注册了同一个scheme,那么,iOS和Android会给出一个选择,让用户来选(注:iOS的系统有可能会直接跳某个 App 上去,不同版本的跳规则不明确,可以认为是随机跳转)。于是乎,恶意的APP就要努力的让自己比正规的APP看起来更像个正规的APP就可以了。

在Android平台上,这个事可能更变态,只要恶意的应用有两个权限,一个是随手机操作系统在后台启动,一个是task list(然而这两个权限都是一般权限)。这样一来,当你进行两个APP切换时,恶意程序可以通过task list权限监控到,然后自己马上先于正规的app出现,等到收集完用户数据后简单的退出就好了。这个方式只需要你的程序能在10ms以内反应过来(最佳是5ms左右),人的肉眼根本看不出来。(在iOS设备下,除了jail break后的iPhone可以这么干,正常的都iPhone还没有找到这样的攻击方式)

在一个应用内内嵌Web的方式

这种方式更容易攻击了,现在很多很多应用都是内嵌的Web的形式,你完全不知道打开的网页的网站是什么,因为这些内嵌的WebView你连地址都看不见。而且无论是iOS或Android,其WebView都可以执行任何的Javascript代码,就算显示URL,URL也可能是被混乱过的,你也看不全,你也很容易上当。当然,那些使用带SSL证书的支持HTTPS的网站(尤其是EV证书)可以在地址栏上显示一个绿色的标记表示你访问的就是正确网址,但是并不是所有的浏览器都会这样,比如iPhone的Safari并没有这个提示,所以,你一定要用Chrome。

更狠的是就算你打开的是一个正确的URL,你依然可能被中间人攻击。尤其是这个网站使用了明文的HTTP协议,而你又喜欢蹭那些免费的WiFi,于是很容易给把服务器返回给你的网页中做修改,比如,修改网页中login表单或是支付表单提交的网站(想想天朝的网络运营商给你访问的正常的网页弹广告这事吧)

关于DNS劫持,有些人觉得这事可能遇不上,因为这是一个全网的问题,如果你有这样的想法你就错了。还是那样,你爱占便宜,蹭上那些没有密码的WiFi,你完不知道,你连上去的那个WiFi会设置什么样的DNS服务器,你输入了www.taobao.com,但你打开的网站根本就是不是淘定,而是一个钓鱼网站。你会知道你打开的是错的了么?基本不可能。所以,安全点的网站都是要用HTTPS,但是还是那句话,iPhone的Safari并不会提示你打开网站的SSL证书合不合法(事实上,在手机上的很多浏览器都不会这提示,只有Chrome会)。

关于攻击的方式我不想讲太多,还有很多高级+猥琐的方式我也不是完全知道,知道了我也不说,不然,教人犯罪了。

关于从Web端唤起APP是和,APP唤醒APP的攻击方式基本一样。我就不说了。

怎么防范钓鱼式攻击

首先,我们要知道,钓鱼式攻击是一件非常难搞的事。要搞定这个事,一般来说需要四个方面: 立法层面用户培训层面宣传层面、与 技术保全措施层面

教育方面

打击网钓的策略之一,是试着培养人们识别网钓,并教导怎样处理这些问题。只需要稍稍修改人们浏览习惯的方式,很多问题都可以避免。随着人们越来越认识到网钓者所使用的社会工程学技俩,传统的网钓欺诈技术可能在未来过时。

  • 对别人发来的链接要小心,尤其是让你输入机密信息的链接要小心检查。
  • 到正规的地方买手机,不要贪图小便宜。旧手机在卖前要“物理删除”数据。
  • 不要对手机越狱,不要root。
  • 不要从非信任的地方下载软件。
  • 要小心免费的WiFi。
  • 输入机密数据的时候一定要小心检查。
  • 多依赖一些不同的安全体系,比如:网上支付不要只依赖支付宝,尽量使用信用卡(信用卡千万不要设密码),这样就算是被钓鱼了,你还有一个银行安全的缓冲地带——可以不承认交易。
  • 现在使用手机的频率越来越高,所以,我非常建议你使用更为安全的iPhone手机,一定要打开“查找我的iPhone”功能,然后设上开机密码。iPhone手机可以做到手机丢失了别人都无法使用,包括刷机都刷不了(iOS7以上版本)
  • 对于一些关键网站,开启两步验证,这样就算你的用户名和密码被钓走了,还有一个动态手机口令做为登录的关卡。

技术方面

  • 利用SSL证书来保证从浏览器到网站的访问是现在采用比较多的方式,也是在理论上可行的方式。现代的浏览器都会在URL上放上一个锁的标志,对于EV证书,你会看到浏览器的URL是绿色的(很容易分辨)
  • 另外,像firefox浏览器有一个petname的插件,你可以为你常上的网站设置一些标签。这样,当你打开钓鱼网站的时候,你会发现这些标签没有显示出来,那就有问题了。
  • 关于SSL的CA认证机构,你需要管理好你浏览的那些根证书,有些根证书你需要删掉。
  • 增加式登录方式。这种方式被美国银行采用,就是说,你可以上传一个你自己知道的图片,而当你打开登录页面里时,输入了自己的用户名后,你会看到你设置的这个图片被显示出来。如果没有或是显示错了,表示你打开的是钓鱼网站。
  • 两步验证,通过用户自设密码+手机动态口令登录(好些网站都在使用Google Authenticator的方式,这有点像公司VPN的动态口令)。

上述都是PC Web上的防范,然而我们的手机移动端做的并不够好,移动端的安全还是要加油。

安全风控方面

什么叫安全风控,说白了就是拿钱出来赔偿给被骗的用户,大家相信我,这个事情在基本上所有的公司都会做的,也就是说,无论你怎么做安全也无法保证绝对的安全,你只能缓解或是降低用户被骗的数量或概率。所以,几乎所有的公司都会有一笔钱专门用来赔偿。

在西方国家,用户体验很好,我说一个故事,我有一个妹妹在英国,有一天她到ATM上取钱,取完钱后忘了把卡取出,结果后面的人把她的卡里的钱取走了,于是她报了警,等警察做完笔录后,她给银行的客服打了个电话说明了情况,本想冻结银行卡的,但是银行方面二话不说就赔偿了她所有的损失。为什么英国的巴克莱银行这么痛快,是因为他们有风控基金,专门用来处理这样的事的。

在中国,其实银行和一些大的公司都有这笔安全风控基金,但是,要你非常坚持不懈地申诉,他们才会赔给你,而且还不是全部。要全部的话,我估计你要做一个“刁民”,否则欺负你,没道理。

关于微信和淘宝

微信和淘宝到底是谁先屏蔽谁我并不关心,这里面的商业利益我也不关心,微信是不是支持卖东西我也不关心。我关心的是寒冬文章中所说的微信上有淘宝钓鱼的安全问题。

从技术上来说,我觉得要微信和淘宝一起干这事,单方都不行,需要两边的安全专家一起讨论(如果需要,我可以帮你们约)。我这里给一个可能很不成熟的方案,算是抛砖引玉(我不考虑你们之间的商业竞争,我只从用户的角度出发,客户第一):

我觉得,从业务上来说,淘宝可以在微信上有一个官方的商城。而淘宝的商家,需要取得微信的认证后入住,才能分享相关的商品或店家链接,对此,商家入住,我觉得可通过微信的服务账号与淘宝的商家后台集成可以做到。

然后,商家也好,买家也好,他们分享商品只能通过微信官方的商城或是商家的服务账号分享出去,而分享出去的商品信息可以是一个比较unique的形式(比如有一个不能伪造的官方认证的标签),而用户的支付可以通过内置的微信支付也可以通过内置的支付宝(通过唤起App并不是一个好的方式,还是应该你们在服务端进行相互的通信)。

然后微信和淘宝双方通过宣传手段告诉全社会,微信里的商品什么才是正规的,才不是钓鱼的,并给教育用户更为安全地使用手机。

P.S. 我虽然这么说,但从我个人来说,我非常理解微信为了让用户有很好的体验而不让微信成为一个四处都是营销商品的地方。所以,我从个人来说,希望微信不要成为一个商家的营销地。另外,我也知道阿里对移动端的看重,所以,上述的方案虽然对用户体验和安全都比较好,但是从目前商业利益的情况看来基本无法实现。不过我这里也只是抛砖引玉了。

面对安全和用户这两个事, 你们两个中国最大的互联网公司,应该带头做好榜样,你们都是不缺钱的公司,应该更多的承担起社会的责任,真正为用户做点什么,而不是整天想着流量入口,互相屏蔽,互相指责,想着自己能有多少用户,这TMD太LOW了,和你们的地位完全不符。所以,从站在用户的角度上来说,我希望微信和淘宝都能站在用户的角度上思考问题,一起合作来真正的为用户更好的服务。

(全文完)

(转载本站文章请注明作者和出处 酷 壳 – CoolShell.cn,请勿用于任何商业用途)

——=== 访问 酷壳404页面寻找遗失儿童。 ===——

相关文章

移动端网络优化

$
0
0

介绍下针对移动端的网络优化,不限于 Android,同样适用于 iOS 和 H5。
这篇文章首发在微信公众号 codekk

 

本文为性能优化系列第四篇,目前性能调优专题已完成以下部分:
性能优化总纲——性能问题及性能调优方式
性能优化第四篇——移动网络优化
性能优化第三篇——代码优化
性能优化第二篇——布局优化
性能优化第一篇——数据库性能优化
Android 性能调优工具 TraceView
性能优化实例

 

一个网络请求可以简单分为连接服务器 -> 获取数据两个部分。
其中连接服务器前还包括 DNS 解析的过程;获取数据后可能会对数据进行缓存。

 

一、连接服务器优化策略

1. 不用域名,用 IP 直连
省去 DNS 解析过程,DNS 全名 Domain Name System,解析意指根据域名得到其对应的 IP 地址。
http://www.codekk.com的域名解析结果就是 104.236.147.76。

 

首次域名解析一般需要几百毫秒,可通过直接向 IP 而非域名请求,节省掉这部分时间,同时可以预防域名劫持等带来的风险。

 

当然为了安全和扩展考虑,这个 IP 可能是一个动态更新的 IP 列表,并在 IP 不可用情况下通过域名访问。

 

2. 服务器合理部署
服务器多运营商多地部署,一般至少含三大运营商、南中北三地部署。

 

配合上面说到的动态 IP 列表,支持优先级,每次根据地域、网络类型等选择最优的服务器 IP 进行连接。

 

对于服务器端还可以调优服务器的 TCP 拥塞窗口大小、重传超时时间(RTO)、最大传输单元(MTU)等。

 

二、获取数据优化策略

1. 连接复用
节省连接建立时间,如开启 keep-alive。

 

对于 Android 来说默认情况下 HttpURLConnection 和 HttpClient 都开启了 keep-alive。只是 2.2 之前 HttpURLConnection 存在影响连接池的 Bug,具体可见: Android HttpURLConnection 及 HttpClient 选择

 

2. 请求合并
即将多个请求合并为一个进行请求,比较常见的就是网页中的 CSS Image Sprites。
如果某个页面内请求过多,也可以考虑做一定的请求合并。

 

3. 减小请求数据大小
(1) 对于 POST 请求,Body 可以做 Gzip 压缩,如日志。

 

(2) 对请求头进行压缩
这个 Http 1.1 不支持,SPDY 及 Http 2.0 支持。
Http 1.1 可以通过服务端对前一个请求的请求头进行缓存,后面相同请求头用 md5 之类的 id 来表示即可。

 

4. CDN 缓存静态资源
缓存常见的图片、JS、CSS 等静态资源。

 

5. 减小返回数据大小
(1) 压缩
一般 API 数据使用 Gzip 压缩,下图是之前测试的 Gzip 压缩前后对比图。
android-http-compare

 

(2) 精简数据格式
如 JSON 代替 XML,WebP 代替其他图片格式,回复 20 查看关于 WebP 的介绍。

 

(3) 对于不同的设备不同网络返回不同的内容
如不同分辨率图片大小。

 

(4) 增量更新
需要数据更新时,可考虑增量更新。如常见的服务端进行 bsdiff,客户端进行 bspatch。

 

(5) 大文件下载
支持断点续传,并缓存 Http Resonse 的 ETag 标识,下次请求时带上,从而确定是否数据改变过,未改变则直接返回 304。

 

6. 数据缓存
缓存获取到的数据,在一定的有效时间内再次请求可以直接从缓存读取数据。

 

关于 Http 缓存规则 Grumoon 在 Volley 源码解析最后杂谈中有详细介绍。

 

三、其他优化手段

这类优化方式在性能优化系列总篇中已经有过完整介绍
1. 预取
包括预连接、预取数据。

 

2. 分优先级、延迟部分请求
将不重要的请求延迟,这样既可以削峰减少并发、又可以和后面类似的请求做合并。

 

3. 多连接
对于较大文件,如大图片、文件下载可考虑多连接。
需要控制请求的最大并发量,毕竟移动端网络受限。

 

四、监控

优化需要通过数据对比才能看出效果,所以监控系统必不可少,通过前后端的数据监控确定调优效果。

 

关注微信公众号 codekk,回复 perf 可查看 性能优化资料汇总
codeKK

十分钟教你看懂 Google I/O 2015

$
0
0

Google I/O 2015 都看了吧?
因为某些原因:加班、没梯子、陪家人、要考试、或者忙着恢复数据库,肯定有人没看。
当然,肯定也有人今天也没时间重新看时长两个小时的 Google I/O。
于是,只花费十分钟的时间,编者带你看懂今年的 Google I/O 大会。

clipboard.png

好啦,英文好的可以直接 戳这里,不需要梯子;英语不好的,可以跟着编者继续走下去。

还是这位大哥开场:
clipboard.png

简而言之,Google I/O 2015 一共有三个焦点:Android M,Android Anywhere,虚拟现实。

Android M

Android M 是整个大会的重中之重,也是和普通人最息息相关的部分。
Android M 还没有正式发布,Google I/O 大会上发布的仅仅是开发者预览版,其意义在于演示新特性、发布新版本并将新版提交开发者进行开发和测试,预计国外将会在今年末用上 Android M,国内则会在明年 3-5 月用上 Android M。然后编者掂了掂手里 Android L 跳票一个月的 MX4……

简单来说,Android M 是继续对 Android 的优化,但是不仅仅是优化。

从界面上看,Android M 和它的前辈 Android L 很相似,但是实际上,Android M 引入了六个新特性:

更好地管理应用权限

Android M 之前也提供过软件的应用权限管理功能,例如定位、监听听话状态等,不过这些都是在你安装应用的时候就给出提示是否赋予软件这些权限。在 Android M 中,这些得到了优化:安装软件时不需要再去一个一个去选权限,而是在软件用得到的时候,再去提示软件是否有权定位、有权访问日历和相册。

Chrome 模式

以往的 APP 调用浏览器,要么是和微信一样,调用内置浏览器,要么是调用系统浏览器,要么是使用软件提供的可能连后退按键都没有的浏览器。为了解决这个问题,Google 提供了一个解决方案:Chrome Custom Tabs。这个解决方案解决了第三方 APP 调用浏览器的体验问题,例如缓存和预加载(preload certain elements),同时顺带解决了第三方 APP 自带浏览器无法自动填充密码的问题。

APP 链接(APP LINKS)

APP LINKS 不是 Google 的原创,而是 Facebook 提出的协议。
在本次大会中现场演示了这个协议:点击电子邮件中的 Twitter 链接,会自动调用 Twitter 应用。

电池使用优化以及 USB-C

上次的 Android L 也是在致力于解决耗电问题,本次发布的 Android M 同样不例外。在这次的大会中,Google 公布了一项名叫 Doze 的省电技术。通过对消息的分级和运动检测等,电源管理更加智能。同样是待机模式下的 Nexus 9,Android M 比 Android L 待机时间长两倍。

本次发布的 Android M 同样支持 USB Type-C。

更加智能的 Google Now

Google Now 的目标就是在整个系统中实现完全智能。
本次发布可一个全新的功能:Now on Tap。
当收到一封关于看电影的邮件邀约时,长按 Home键,手机会自动在日历中记录看电影电影时间、电影名称,甚至会自动跳出 Youtube 的电影预告片、电影评级以及其他相关信息。
同时,在使用 Spotify 听 Skrillex 的歌的可以直接问“他是的原名是什么”,而不用加上艺名:“Skrillex 的原名是什么”。

新的图片应用以及免费在线存储空间

当然了,国内是享用不到在线空间了,不过简单介绍一下:

如果你喜欢在手机里存上千张图片,那么这个新应用可能正符合你的需求。
新的图片应用可以按照时间自动整理图片,但是同时自动识别图片并给图片加上标签信息,例如:“海滩”,“羊驼”。同时,Google Photos 是一个跨平台的应用,可以很方便地在不同设备上共享照片。

它可以将用户拍照后的照片自动分类并进行归纳整理,通过时间或者图像识别人物关系的紧密程度对照片进行分类保存。同时这是一个跨平台的应用,并且完全免费,用户可以随时随地不受限制的上传自己的照片以及视频到云端,并通过Google Photos在不同的设备上实现照片共享。。

同时,也提供了新的分享界面。

离线地图和针对中国网络的优化

本次大会并没有提到中国的手机网络,而是提到了发展中国家。很多发展中国家网络条件并不太乐观,存在数据流量费用高、网络速度慢等问题。Android 中的 Chrome 将会通过智能算法减少下载图片,并且提供离线页面的功能。
同时,Google 地图也会提供离线功能。当然,离线的 Google 地图仍然可以使用搜索,地区点评以及语音导航功能。

Android everywhere

Android 并不仅仅可以做成手机,也可以做成手环,做成智能家居,做智能支付等等等等。

Android Wear

Android Wear 上次便已发布,本次 Android Wear 的手机系统除了为了载入应用而进行重新设计启动器外,更是增加了几个重量级的 APP,包括快捷 Uber 打车功能等。全新的 Android Wear 拥有更加智能化的操作方式和更加智能的休眠管理功能。同样也有很多细节更新,例如 emoji 表情自动识别和转换。

Brillo

基于 Android 开发,Brillo 是谷歌专为物联网平台打造的底层操作系统。Brillo 可以得到蓝牙、WiFi 等技术支持,能耗低,安全系数高。
Weave 可以让物联网设备之间进行交流。它具有跨平台、API 开放等特性。锁门的时候,Weave 能够帮助家中的灯泡、空调等设备自动感知并关闭掉电源。

Android 支付

Android 支付是一个开放性平台,支持 4.4 (KitKat)以后系统的 NFC 设备,同样支持应用支付。用户就可以选择谷歌的服务或者使用银行的 APP。同时为了支付安全性,Google会开发官方的指纹识别功能。

HBO NOW

HBO NOW 是 Google TV 应用,然而和国内关系并,甚至可以说是并没有什么卵用。HBO 是一个可以在 Android 上看电视的应用,然而,因为有过 HBO警告美国境外付费收看HBO Now客户的事情,所以不要期待太多。

虚拟现实

上次的大会,谷歌就为每个在场的用户提供了一个 Cardboard,本次大会,Google 更是带来了更多炫酷的功能。

兼容 iPhone 的 Google Cardboard

最近的手机越做越大,于是 Google 也提供了最大达六英寸的 Cardboard,同样提供了 iPhone 版,也正在开发支持 Android iOS 双系统的 SDK。Android 上已经有 Cardboard(谷歌纸盒)可以尝鲜。

Cardboard 非常便宜,国外价格不到十美元,但是……
希望大家不要盲目相信美国物价表。

另外,编者提醒大家,大部分手机即便是将背景光调到最弱,在黑暗的环境中仍然刺眼,Google Cardboard 又是把手机放到眼睛前不到十厘米的位置,所以目前大家一定要注意避免长时间使用。

虚拟现实相机

为了让每个人都可以制作自己的虚拟现实情景,Google 推出了 Jump 拍摄工具。 GoPro已经加入这个项目。通过 GoPro 定制的相机拍摄的图片,经过 Jump 处理后,会生成非常逼真的虚拟现实情景。据介绍,今年夏天开始,Google 将会挑选实验者体验 Jump。

图片来自 163、sohu 和 TNW news。
部分内容来自 The 12 most important announcements from Google I/O 2015

关于Google IO 2015,你必须知道的9件事

$
0
0

1 Google 正式发布Android M, 提升用户体验

今天的大会开始,Google 公司发布了 Android M。

新的Android系统有了很大用户体验上的提升,主要体现在 App 权限管理,网页体验,App关联,Android Pay 支付功能,指纹识别以及续航能力上的改进。

Android M 预览版本将于今天发布,首批支持设备包含Nexus 5、6、9 等。

2 Android Pay 将在今年正式上线

Google 今天发布了Android Pay。Android Pay是一个开放平台,支持Android 4.4版本或更新的设备,Google会在最新的Android M里自建官方的指纹识别支持。

据悉,Google 的支付服务将在未来几个月内推出,将兼容Android的早期版本手机。另外,Android Pay并不需要一个单独的应用程序来运行。用户可以将自己的信用卡、借记卡和会员卡绑定到手机上,用现有密码解锁设备,并在美国超过70万家实体店进行线下支付。目前,已经参与Android Pay的零售商包括麦当劳、Macys、百思买、Walgreens和 有机食品Whole Foods超市。

3 Google 发布 Brillo,一个只保留基本内核功能的用于物联的 Android系统,以保证消耗最小

Google以Android为核心,推出了Brillo系统。Brillo 是一个物联网平台。Brillo出自Android,所以在设备配对和设置上将会非常方便,也就是说任何Android设备都可以轻松地与Brillo智能设备对接,并实现控制。

除了Brillo,Google还发布了Weave跨平台协议。这个协议可以连接云端、手机和Brillo支持的设备,比如被 Google 收购的 Nest 的恒温器。

Brillo将在今年第三季度被投入使用。届时,物联网设备能够与手机和云通讯,且所有设备都可以使用统一语言。

4 已经有 4000个 Android Wear 应用被开发,Uber 成为新成员

Google 公司今天宣布目前,已经有4000个 app 可以在 Android Wear 这个平台上,这其中包括Uber,Foursquare,以及 Citymapper 等。

Uber对于Android可穿戴设备来说是非常重要的。用户只用对着Android可穿戴设备说:OK,Google,给我叫一辆车。同时,uber司机就可以得到指令到达用户所在地点来接客户。

基本这些Android Wear的新功能你都可以在LG的新手机Urbane上看到了,但是当演讲者宣布Android Wear可以支持使用者发送表情符号以及手势控制时,现场还是响起了掌声。

5 Google Now 集合上下文联系、搜索、语音识别,变得越来越贴心

Google Now通过对用户行为的多年学习,已经变得非常智能。Google Now将可以回答更多的问题,也更加准确。它新加入了 “now on tap”功能更是让人觉得贴心。在特定应用里 ,长按home键,开启 Google Now,它会在当前界面提供给你你最需要的信息。例如,当你的朋友在微信里问你要不要看《超能陆战队》,Google Now 就会以此为依据,向你提供关于这部电影的各种有用信息,例如它的评分等等。

另外,大会上,演讲者额外展示了一些其他实际的应用场景。例如,Google Now可以为用户展示用户开车时前方最近的加油站位置;可以在播放歌曲时自主识别歌曲名称和演唱者;可以在发信息过程中提醒你未完成的事情(例如,你的家人发你一条信息:别忘了买苹果,Google Now 不但会提醒你购买苹果还会给你提示离你最近的售卖苹果的地方以及去的路线。)

6 Google Photos 将支持无限存储以及自动归类

Google 公司发布了新的照片管理应用 Google Photos。这款应用让用户有无限免费的云端图片和视频存储空间,可以自动地同步所有设备上的照片,可以在手机等设备上用手势进行管理,例如双指缩放可以切换时间线,查看照片,这基本是让Google Photos变得更有了苹果的气质。

但是,它仍然有一些值得说一说的事情:Google Photos结合了Google的识别技术,能自动识别照片中的人或不同事件,可以自动为用户添加便签,而无需手动。也就是说在管理图片时,它可以自动识别你的一位朋友的脸,从而把所有含有他的照片归类在一起。当然,当你搜索在crater lake 滑雪的时候,所有跟滑雪有关的照片也会被聚集在一起。按照演讲人所说,这款应用今天晚些时候就会上线,Pingwest品玩也会发布相关的测评,让你第一时间了解这款应用。

7 Google Map 将支持离线导航

Google公司今天在他的地图功能上再次出大招。为了照顾网络资源较为贫瘠的发展中国家的需求, Google Maps 将支持离线导航。同时,地图可支持用户离线查看景点以及餐厅的营业时间以及评价。

8 硬纸壳做的3D VR眼镜 Cardboard 变得更大,并可适配于苹果手机

在今天的大会上,Google 公司宣布更新 VR (virtual reality)产品Cardboard。对,就是在去年I/O大会上Google 公司送给参会开发者的那个硬纸壳叠成的虚拟可穿戴设备。这款产品较于先前的版本尺寸更大,可适用于适配6寸屏幕的手机。同时,它除了支持Android手机,也支持苹果手机了哦。

我在活动展示区适用下来发现相较于一般的 VR 产品,它所观看视频的清晰度更高,颜色更鲜艳,并且没有太多的眩晕感。但是,安装下来尽管简单,却不算非常稳固,手机非常容易从侧面漏出来掉在地上。

9 Google和 GoPro合作开发全景拍摄机器 Jump

为了给Cardboard眼镜提供更多的内容,Google推出了360度全景拍摄工具Jump。并且邀请GoPro加入了这个项目,通过Jump拍摄工具及16个GoPro的运动相机,用户可以360度进行拍摄。拍摄的视频经过Jump校正后,会生成非常逼真的3D视频。展厅工作人员介绍,这款产品将在今年夏天正式推出,用户可以将自己拍摄的3D视频上传Youtube,配合 Cardboard 其他人就能看到VR视频。

 

————-

更多关于2015年 Google I/O 的文章请查阅汇总专题: http://www.pingwest.com/hot-tags/google-io/ ,或查看发布会直播回顾: http://live.pingwest.com/c/google_io 

相关阅读:

     【PW晨报】Android M 正式亮相,Moto Maker 登陆中国

     想要体验最先进的人工智能,就在 Google Now

     一场 I/O 大会,让我看懂了 Google 对第三世界的爱

     作为 Android 史上最人性化的升级,Android M 的新功能全在这

10个 iOS 用户暂可以嘲笑 Android 的特点

$
0
0

Android 与 iOS 设备之间的争斗从未停止,毕竟一切高科技产品的理念和实际表现方式都不相同。就拿 Android 来说,很多功能令用户并
不太开心,甚至是令人愤怒,下面让我们来简单的盘点 10 个 iOS 比 Android 优秀的特征。当然,这并不意味
着 Android 比 iOS 差,因为每天让库克最为头痛的事情,就是每天都会有用户转投 Android,反之亦然,因为我们还会盘
点 Android 比 iOS 更好的 10 个特征。

1、设计不一致


我们面对现实,即使谷歌公布了 Material Design(材料设计)作为设计语言,并希望开发者能够遵循,但是目前真正采
用 Material Design 风格界面的应用程序非常少,而大多数仍然使用老旧的 Holo Design 设计语言。不清楚是否是因
为  Material Design 不佳还是开发者认为没必要,Google Play 上还是有很多不同风格应用程序,而且看起来统一设计的道路还
非常长。就设计语言凝聚力和统一性而言,苹果的应用程序做得好很多,大多数应用程序都已经专门针对新的系统风格调整用户界面设计。

2、本身就不像精简的 iOS

Android 操
作系统远不及 iOS 直观,随便一台 Android 设备总能找到不同的选项或功能,而苹果的 iOS  系统上做每一件事情都使用了同样的方式。当
然,原生的 Android 操作系统可能最为直观,但设备制造商就是不喜欢原生 Android,几乎每一个品牌的智能手机都有自家定制的用户界面。这
意味着,一个用户如果要换不同品牌的手机,必须要通过一定的学习才能适应,这个学习过程有可能是轻量级,也可能难以使用。更重要的是,同一品牌的智能手
机,每一款的界面还不一样,这一点与 iOS 用户更换新  iPhone 直接上手相比体验大为不同。

3、系统更新升级


一点也是事实。每当 Android 的新版本出来时,大多数 Android 用户必须等待很长一段时间,才能够获得来自官方的正式版系统升级,而这已
经是幸运儿了,如不幸可能永久等待也无任何升级希望。反观 iOS 设备,在规定新系统版本发布之日,总是会有大量用户直接升级,随后新系统的人数占据绝
大多数。当然,如果用户手持 Nexus 设备的话,将最快获得升级,不过 Nexus 在全球 Android 手机之中市场份额相当之低。

4、内置大量臃肿的应用程序


置应用程序的数量和臃肿程度,完全取决于用户购买的是哪一款 Android 智能手机。品牌制造商和运营商,两者都非常喜欢在智能手机里预装各种应用程
序,而且大部分没办法直接禁用或者完全手动删除,不过其中也有一些设备不会太过于臃肿。反观 iOS 设备,虽然也有不少预装应用程序,一些对个人可能没
有多大用处,比如 Apple Watch,但所预装的应用程序并没有让用户感受到十分臃肿。总之,虽然 iOS 系统正在变大,但不可否认很
多 Android 设备的体验的确毁在大量预装应用上。

5、控制中心更直观易用


一点不同的用户感受不同,反应有好有坏。iOS 设备支持直接从任何界面向上滑动访问控制中心,并提供一些重要的开关,包括音乐控制和音量调节。
Android 是最早提供快捷设置和通知栏智能手机,但是一些用户认为其排列混乱不够直观,比如 Android Lollipop 系统里,用户必须
滑动那个两次顶部或者使用双指手势,才能找到需要的快捷开关,而 iOS 只要简单的从底部滑动,显得更简单也更人性化,只是缺陷在于快捷开关无法自定
义。

6、内置的相机应用功能有限

就默认相机功能而言,iOS 相比 Android 看起来更直观功能也更多,比如手动控制曝光,自动曝光/自动对焦等,很多功能在 Android 设备上的默认相机里缺失。不过,新版 Android 以及大多数设备制造商提供的相机应用,可以作为弥补。

7、无 iCloud 备份功能

iOS 自
带的强大的数据备份功能莫过于 iCloud,而且直观性和易用性良好,用户只要打开开关,选择需要备份的应用和数据即可,在 Wi-Fi 环境下还能自
动备份,随时还原。Android 上也有相类似的解决方案,只是大多数难以完整的备份,真要完美则需要 Root 获取权限,然后再通过第三
方 Recovery 备份和恢复,比如 Nandroid 和钛备份的方案。

8、应用程序更新


一点也是事实,Google Play 现在的确比苹果 App Store 拥有更多的游戏和应用,但后者总是更讨开发者欢迎,尤其当涉及到发布新款或
新版应用程序,iOS 总是开发者优先首选,Android 才紧随其后,很多用户对开发者或开发商的“应用无更新”不满也源于此,不过苹果的确为开发者
带来了更多的收入。

9、缺乏连续互通功能


果家里有苹果家族全套产品,比如 Mac、iPad 和 iPhone,只要移动设备升级到了新版 iOS 8,很多工作和生活上的任务处理将变得更方便
一些,比如 Mac 未完成的工作可以在 iPad 上继续,iPhone 来电时 Mac 可以代替接电话,就算没有 Wi-Fi 也能共享热点等等,
很多功能在苹果设备之间都能实现无缝衔接。而这一点在 Android 上还无法真正实现,谷歌也正在完善 Chrome OS,让其代替接受通知,甚至
就直接运行 Android 应用。

10、苹果的健康应用目前比 Google Fit 完善

提到苹果的健康应用就难免不让人想起 Google Fit。相比苹果而言,谷歌的方案目前在功能上还是令很多很多用户失望,尤其是生态系统不够完善。苹果
的健康功能更为丰富一些,同时还拥有很多配套的第三方应用程序和配件产品,得益于完善的 HealthKit 和 ResearchKit,iOS 设备
就像是一个强大的医学平台。


Google《Android性能优化》学习笔记

$
0
0

渲染篇

1) Why Rendering Performance Matters

现在有不少App为了达到很华丽的视觉效果,会需要在界面上层叠很多的视图组件,但是这会很容易引起性能问题。如何平衡Design与Performance就很需要智慧了。

2) Defining ‘Jank’

大多数手机的屏幕刷新频率是60hz,如果在1000/60=16.67ms内没有办法把这一帧的任务执行完毕,就会发生丢帧的现象。丢帧越多,用户感受到的卡顿情况就越严重。

552dd22e52006_middle

3) Rendering Pipeline: Common Problems

渲染操作通常依赖于两个核心组件:CPU与GPU。CPU负责包括Measure,Layout,Record,Execute的计算操作,GPU负责Rasterization(栅格化)操作。CPU通常存在的问题的原因是存在非必需的视图组件,它不仅仅会带来重复的计算操作,而且还会占用额外的GPU资源。

4) Android UI and the GPU

了解Android是如何利用GPU进行画面渲染有助于我们更好的理解性能问题。一个很直接的问题是:activity的画面是如何绘制到屏幕上的?那些复杂的XML布局文件又是如何能够被识别并绘制出来的?

Resterization栅格化是绘制那些Button,Shape,Path,String,Bitmap等组件最基础的操作。它把那些组件拆分到不同的像素上进行显示。这是一个很费时的操作,GPU的引入就是为了加快栅格化的操作。

CPU负责把UI组件计算成Polygons,Texture纹理,然后交给GPU进行栅格化渲染。

然而每次从CPU转移到GPU是一件很麻烦的事情,所幸的是OpenGL ES可以把那些需要渲染的纹理Hold在GPU Memory里面,在下次需要渲染的时候直接进行操作。所以如果你更新了GPU所hold住的纹理内容,那么之前保存的状态就丢失了。

在Android里面那些由主题所提供的资源,例如Bitmaps,Drawables都是一起打包到统一的Texture纹理当中,然后再传递到GPU里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。当然随着UI组件的越来越丰富,有了更多演变的形态。例如显示图片的时候,需要先经过CPU的计算加载到内存中,然后传递给GPU进行渲染。文字的显示比较复杂,需要先经过CPU换算成纹理,然后交给GPU进行渲染,返回到CPU绘制单个字符的时候,再重新引用经过GPU渲染的内容。动画则存在一个更加复杂的操作流程。

为了能够使得App流畅,我们需要在每帧16ms以内处理完所有的CPU与GPU的计算,绘制,渲染等等操作。

5) GPU Problem: Overdraw

Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的UI结构里面,如果不可见的UI也在做绘制的操作,会导致某些像素区域被绘制了多次。这样就会浪费大量的CPU以及GPU资源。

当设计上追求更华丽的视觉效果的时候,我们就容易陷入采用复杂的多层次重叠视图来实现这种视觉效果的怪圈。这很容易导致大量的性能问题,为了获得最佳的性能,我们必须尽量减少Overdraw的情况发生。

幸运的是,我们可以通过手机设置里面的开发者选项,打开Show GPU Overdraw的选项,观察UI上的Overdraw情况。

蓝色、淡绿、淡红、深红代表了4种不同程度的Overdraw情况,我们的目标就是尽量减少红色Overdraw,看到更多的蓝色区域。

6) Visualize and Fix Overdraw – Quiz & Solution

这里举了一个例子,通过XML文件可以看到有好几处非必需的background。通过把XML中非必需的background移除之后,可以显著减少布局的过度绘制。其中一个比较有意思的地方是:针对ListView中的Avatar ImageView的设置,在getView的代码里面,判断是否获取到对应的Bitmap,在获取到Avatar的图像之后,把ImageView的Background设置为Transparent,只有当图像没有获取到的时候才设置对应的Background占位图片,这样可以避免因为给Avatar设置背景图而导致的过度渲染。

总结一下,优化步骤如下:

  • 移除Window默认的Background
  • 移除XML布局文件中非必需的Background
  • 按需显示占位背景图片

7) ClipRect & QuickReject

前面有提到过,对不可见的UI组件进行绘制更新会导致Overdraw。例如Nav Drawer从前置可见的Activity滑出之后,如果还继续绘制那些在Nav Drawer里面不可见的UI组件,这就导致了Overdraw。为了解决这个问题,Android系统会通过避免绘制那些完全不可见的组件来尽量减少Overdraw。那些Nav Drawer里面不可见的View就不会被执行浪费资源。

但是不幸的是,对于那些过于复杂的自定义的View(通常重写了onDraw方法),Android系统无法检测在onDraw里面具体会执行什么操作,系统无法监控并自动优化,也就无法避免Overdraw了。但是我们可以通过canvas.clipRect()来帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个API可以很好的帮助那些有多组重叠组件的自定义View来控制显示的区域。同时clipRect方法还可以帮助节约CPU与GPU资源,在clipRect区域之外的绘制指令都不会被执行,那些部分内容在矩形区域内的组件,仍然会得到绘制。

除了clipRect方法之外,我们还可以使用 canvas.quickreject()来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操作。

8) Apply clipRect and quickReject – Quiz & Solution

上面的示例图中显示了一个自定义的View,主要效果是呈现多张重叠的卡片。这个View的onDraw方法如下图所示:

打开开发者选项中的显示过度渲染,可以看到我们这个自定义的View部分区域存在着过度绘制。那么是什么原因导致过度绘制的呢?

9) Fixing Overdraw with Canvas API

下面的代码显示了如何通过clipRect来解决自定义View的过度绘制,提高自定义View的绘制性能:

下面是优化过后的效果:

10) Layouts, Invalidations and Perf

Android需要把XML布局文件转换成GPU能够识别并绘制的对象。这个操作是在DisplayList的帮助下完成的。DisplayList持有所有将要交给GPU绘制到屏幕上的数据信息。

在某个View第一次需要被渲染时,Display List会因此被创建,当这个View要显示到屏幕上时,我们会执行GPU的绘制指令来进行渲染。

如果View的Property属性发生了改变(例如移动位置),我们就仅仅需要Execute Display List就够了。

然而如果你修改了View中的某些可见组件的内容,那么之前的DisplayList就无法继续使用了,我们需要重新创建一个DisplayList并重新执行渲染指令更新到屏幕上。

请注意:任何时候View中的绘制内容发生变化时,都会需要重新创建DisplayList,渲染DisplayList,更新到屏幕上等一系列操作。这个流程的表现性能取决于你的View的复杂程度,View的状态变化以及渲染管道的执行性能。举个例子,假设某个Button的大小需要增大到目前的两倍,在增大Button大小之前,需要通过父View重新计算并摆放其他子View的位置。修改View的大小会触发整个HierarcyView的重新计算大小的操作。如果是修改View的位置则会触发HierarchView重新计算其他View的位置。如果布局很复杂,这就会很容易导致严重的性能问题。

11) Hierarchy Viewer: Walkthrough

Hierarchy Viewer可以很直接的呈现布局的层次关系,视图组件的各种属性。 我们可以通过红,黄,绿三种不同的颜色来区分布局的Measure,Layout,Executive的相对性能表现如何。

12) Nested Hierarchies and Performance

提升布局性能的关键点是尽量保持布局层级的扁平化,避免出现重复的嵌套布局。例如下面的例子,有2行显示相同内容的视图,分别用两种不同的写法来实现,他们有着不同的层级。

下图显示了使用2种不同的写法,在Hierarchy Viewer上呈现出来的性能测试差异:

13) Optimizing Your Layout

下图举例演示了如何优化ListItem的布局,通过RelativeLayout替代旧方案中的嵌套LinearLayout来优化布局。

两款免费的Android应用代码安全检测工具

$
0
0

‍FreeBuf前不久刚刚 报道过,美‍‍图秀秀、gReader、福昕PDF阅读器等14款Android应用易遭中间人攻击。今天,央视《 新闻直播间》也用“黄金三分钟”介绍了安卓手机上存在的名为“寄生兽”的通用型安全漏洞,影响规模达到数以千万级的用户,市面上安卓90%APP都中招。

今年6月Android智能手机在美国的市场份额上升2.8%,达到64.9%。而这带给安卓开发者及用户更多的则是对移动安全及隐私问题的担忧。

‍‍如果你是正在开发手机应用的程序员,那你应该阅读一下 OWASP手机-十大移动威胁。或许你会好奇哪些安全工具可以帮助你解决安卓应用程序日益增长的复杂性难题。嗯,其实是 很多工具的。

这篇文章将介绍两个免费的静态分析工具,可以从集成开发环境(IDE)直接扫描你的代码。‍‍

Android Lint

这是个什么?
这是由IDE 安卓工作室官方提供的一个静态代码分析器。

它有什么用?

检测列表是相当长,而安全检测的数量却十分有限。通常重要的定期检测仍在使用这个工具。

安装包

没有!正如之前提到的,这是IDE 安卓工作时官方的,但是如果你只想要与安全相关的检测,你可以使用这个“ 只要安全”文件。

视频演示

   

FindBugs 与 Find Security Bugs插件

这是个什么?

FindBugs是一款受欢迎的静态分析引擎,广泛用于Java社区。发现安全漏洞( Find Security Bugs)是一该工具的一个插件,为分析提供了安全规范。

它有什么用?

安全插件 FindSecBugs的主要焦点在于标记漏洞,比如应用程序中不安全的通讯、 密码学的误用以及一些 敏感部分

安装包

FindBugs的安装及配置可以通过 几个简单点击就能完成。如果你仍然坚持使用Eclipse(前官方IDE),Eclipse市场中也有一个相同的插件。

视频演示

这里有一个简短的视频,展示了FindBugs在安卓工作室的集成。

   

(注意:这里使用的是Find Security Bugs的一个旧版本)

接下来,我们再聊点什么呢?

不幸的是,程序客户端安全问题仅仅是冰山一角。你的应用程序后端也特别需要注意。毕竟,OWASP十大移动威胁的头号风险便是 薄弱的服务器端控制

另一个不错的建议便是在持续集成环境中将这两种工具结合使用。

BlackHat USA 2015 即将到来

我将在 黑帽大会上展示FindBugs的安全插件,演示IntelliJ和SonarQube的集成。如果你已经使用了该工具,有任何问题都请不要犹豫地反馈给我。

如果你从事的是安卓开发工作,也不要错过在同一时间段的 QARK的展示

如果你有任何可以运用到安卓上的新安全规范,不要犹豫快去GitHub吧。

参考文献

OWASP:Source Code Analysis Tools 静态代码分析工具列表

NIST:Source Code Security Analyzers 另一些不错的按语言分类的工具列表

Android Lint:Android Lint的官方文件

Find Security Bugs:Github网站的FindBugs安全插件

Mobile Security Wiki:一个全面的资源列表,包括用于安卓的工具

*参考来源: blog,转载需注明来自FreeBuf黑客与极客(FreeBuf.COM)

Android Design Support Library的代码实验

$
0
0

原文: Codelab for Android Design Support Library used in I/O Rewind Bangkok session----Make your app fancy with few lines of code

原文项目 demo: Lab-Android-DesignLibrary

双语对照地址: 【翻-双语】Android Design Support Library 的 代码实验——几行代码,让你的 APP 变得花俏

  • 翻译: MrFu
  • 校验: MrFu
  • 能去小小的 star 一下吗?非常感谢! Codelab

目前,我相信,没有任何 Android 开发者不知道 Material Design的,因为它的设计在过去的一年震惊了世界,正式的变成了一个设计理念。

令人惊讶的是,在 Android 应用中材料设计是不容易实现的,因为材料设计的 UI 组件 如: Floating Action Button (FAB) 在低于 Android L 系统上是不可用的。我们只能选择使用由独立开发者公布出来的第三方库。

来了一个好消息,上周(2015.5.29)在谷歌2015 I/O 大会时,谷歌宣布了一个今年最让人兴奋的支持库,名叫 Android Design Support Library,在这个单独的 library 里提供了一堆有用的材料设计 UI 组件。通过这篇文章,让我用这个机会向你一个一个描述如何来使用他们。

请查看下面这个视频作为本教程最终的结果。

0

从这里开始,空白 Activity 里面有一个 DrawerLayout 。

1

Activity 已经调整为材料设计风格的主题。

1
2
3
<item name="colorPrimary">#2196F3</item>
<item name="colorPrimaryDark">#1565C0</item>
<item name="colorAccent">#E91E63</item>

好了,让我们开始吧!

步骤一:从 Github 上拷贝源码

我已经为这个 codelab 准备了源码,你可以从 GitHub轻松的 clone 它。MainActivity 是上面所示的最终结果。请在这个 project 的 CodeLabActivity中做我们的代码实验。

你一定要自己做的一个任务是... 成功的运行它,它应该是通过简单的点击“运行”按钮来完成。

步骤二:添加 Android Design Support Library 依赖

第一件要做的事是在我们的项目中添加 Android Design Support Library,在 app 的 build.gradle文件下添加一行依赖代码。

1
compile 'com.android.support:design:22.2.0'

`
请注意 Design Support Library 依赖于 Support v4 和 AppCompat v7。一旦你在你的项目中添加这个 library,你也将获得一个这些 libraries 的组件的入口。(译者注:就是说 Design Support Library 中就已经包含了 Support v4 和 AppCompat v7)

顺便说一下,从 Github 克隆的源码已经添加了上面这行代码。但是如果你创建了你自己的项目,你需要自己添加它。

步骤三:添加 FAB

Floating Action Button (FAB) 是一个有一些阴影的圆形按钮,这个令人难以置信的,可以改变世界的设计。毫不奇怪它为什么会变成材料设计的标志。因此我们从这开始。添加一个 FAB 在布局文件,因为它需要一些父类来使它在屏幕的右下方位置对齐,所以用FrameLayout来包裹 FloatingActionButton。请做这样的事情作为 DrawerLayout 的内容:更换 activity_code_lab.xml中已经存在的 TextView,像下面的代码这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<android.support.v4.widget.DrawerLayout ...
xmlns:app="http://schemas.android.com/apk/res-auto"
....>
<FrameLayout
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:src="@drawable/ic_plus"
app:fabSize="normal" />
</FrameLayout>
...
</android.support.v4.widget.DrawerLayout>

android:src是用来定义你想要的资源文件 ID(推荐 40dp 的清晰的 png 文件),而 app:fabSize="normal"是用来定义 FAB 的大小的, normal的意思是在大多数情况下标准尺寸为 56dp 的按钮,但是万一你想使用较小的一个, mini是另一个选择,它的大小将变成 40dp。

就这样,FAB 现在准备使用!下面是当我在 Android 4.4 上运行这段代码的结果。

p0

但是当我们运行在 Android 5.0 上时,结果变成了这样...

p1

这不是特效,只是一个 bug。幸运的是 design library 的开发者团队已经知道这个问题并在不久的将来会发布一个修复的版本。但是如果你现在想要使用它,我们可以做一些事情:通过设置 FAB 的 margin right 和 margin bottom 为 16dp 在 API Level 21+ 上面并在 低于 Android L 的版本上 设置为 0dp。感谢配置资源可以让我们非常容易的做到这一点。

res/values/dimens.xml

1
2
<dimen name="codelab_fab_margin_right">0dp</dimen>
<dimen name="codelab_fab_margin_bottom">0dp</dimen>

res/values-v21/dimens.xml

1
2
<dimen name="codelab_fab_margin_right">16dp</dimen>
<dimen name="codelab_fab_margin_bottom">16dp</dimen>

res/layout/activity_code_lab.xml

1
2
3
4
5
<android.support.design.widget.FloatingActionButton
...
android:layout_marginBottom="@dimen/codelab_fab_margin_bottom"
android:layout_marginRight="@dimen/codelab_fab_margin_right"
.../>

好了!

p2

这里有另一个 bug。阴影,你在哪里?这个 bug 和先前的那个是有关联的。你可以通过定义 app:borderWidth="0"作为 FAB 的属性 作为一个快速的解决方案。

p3

欢迎回来,阴影!其深度是自动设置的最佳实践之一:6dp 在空闲状态,12dp 是按下状态。反正你可以通过定义重写这些值, app:elevation为空闲状态下的阴影深度, andapp:pressedTranslationZ为按下状态的。

关于按钮的颜色,FAB 基本上使用强调色,但是你可以重写 app:backgroundTint属性来修改。

就像传统的按钮,你可以通过 setOnClickListener()处理点击,在 CodeLabActivity.java文件的 initInstances方法中添加下面的代码。

1
2
3
4
5
6
7
8
9
10
11
FloatingActionButton fabBtn;
...
private void initInstances() {
...
fabBtn = (FloatingActionButton) findViewById(R.id.fabBtn);
fabBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}

完成!

步骤四:使用 Snackbar

Snackbar,在屏幕的地步一个微小的黑色条显示着一条简短的消息,在这个 library 中也是可用的。Snackbar 和 Toast 有着相同的概念,但是不同于 Toast,它的表现是作为 UI 的一部分而不是覆盖在屏幕上。

p4

不只是概念相同,编码风格也是由 Toast 所启发,你可以通过下面的代码唤起 Snackbar。

1
2
3
4
5
6
7
Snackbar.make(someView, "Hello. I am Snackbar!", Snackbar.LENGTH_SHORT)
.setAction("Undo", new View.OnClickListener() {
@Override
public void onClick(View v) {
}
})
.show();

make()的第一个参数是一个 View 或者 Layout,你想在它的底部位置显示一个 Snackbar。在这个例子中,一个 FrameLayout 包裹着一个 FAB 就是其中一个例子。 setAction()方法是用在设置动作显示在 Snackbar 的右侧并有对应的监听。这个方法不是必需的,可以移除。

现在,让我们通过添加下面的代码去试试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FrameLayout rootLayout;
...
private void initInstances() {
...
rootLayout = (FrameLayout) findViewById(R.id.rootLayout);
fabBtn = (FloatingActionButton) findViewById(R.id.fabBtn);
fabBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(rootLayout, "Hello. I am Snackbar!", Snackbar.LENGTH_SHORT)
.setAction("Undo", new View.OnClickListener() {
@Override
public void onClick(View v) {
}
})
.show();
}
});
}

点击 FAB 以及看到的结果。

p5

有用!但是... 还不是很完美。它是出现在放置 Snackbar 顶部的位置,长期的用户体验是很差的。不管怎么样,这个行为已经是正确的,因为这里没有为 Snackbar 和 FAB 定义任何关联。

为了这个目的专门发明了一个特殊的布局,使子 Views 协调工作。这就不用奇怪为什么它的名字是 CoordinatorLayout了。

步骤五:使他们和 CoordinatorLayout 协作

CoordinatorLayout 是一个让子 Views 协调工作的布局。这里没有任何魔法。每个 View 中肯定是设计和实现了和 CoordinatorLayout 协同工作的。FAB 和 Snackbar 就是这两个view。

所以... 现在让我们将 FrameLayout 改成 CoordinatorLayout包裹一个FAB。

res/layout/activity_code_lab.xml

1
2
3
4
5
6
7
<android.support.design.widget.CoordinatorLayout
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.FloatingActionButton
... />
</android.support.design.widget.CoordinatorLayout>

而且,不要忘了在 CodeLabActivity.java改变 rootLayout 的变量类型为 CoordinatorLayout,否则就会崩溃。

1
2
3
4
//FrameLayout rootLayout;
CoordinatorLayout rootLayout;
//rootLayout = (FrameLayout) findViewById(R.id.rootLayout);
rootLayout = (CoordinatorLayout) findViewById(R.id.rootLayout);

结果:现在 FAB 随着 Snackbar 的出现和消失而移动。还增加了一些功能。Snackbar 现在能够滑动消失了!请试一试。

2

但是 bug 到处都是… bug 出现在低于 Android L 的系统上,当 Snackbar 滑动消失的时候,FAB 忘记了移动下来。

3

这显然是一个 bug,但是我不知道确切的原因。感谢天主,这里有一些解决方法。从我的实验中,我发现当我们设置 FAB 的 margin bottom 和 margin right 为一些非零的正数值时,它将会奇迹般的正常工作,所以..就只需要为低于 Android L 的系统改变 margin 的值为 0.1dp就行。

res/values/dimens.xml

1
2
<dimen name="codelab_fab_margin_right">0.1dp</dimen>
<dimen name="codelab_fab_margin_bottom">0.1dp</dimen>

完成。下面是结果。

4

从现在起,如果你计划使用 Android Design Support Library。请首先考虑 CoordinatorLayout,因为它就像是这个 library 的核心。

步骤六:再见 ActionBar,你好,Toolbar

Toolbar 不是 Android Design Support Library 的一部分,而是在这个库中需要与其他组件一起使用。

Toolbar 是一个替代传统的 Action Bar 具有更灵活的行为。我鼓励你们从现在开始隐藏 Action Bar 并且切换到 Toolbar。因为这些有奇妙功能的新库,包括 Design Support Library 的组件中,都被设计为和 Toolbar 协同工作而不是 Action Bar。

很容易切换到 Toolbar。只需要从 Activity 定义的 AppTheme 的 style 属性隐藏掉 Action Bar 开始。

1
2
3
4
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

然后在 CoordinatorLayout 里面的 FAB 之前正确的放一个 Toolbar 组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
<android.support.design.widget.CoordinatorLayout
...>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<android.support.design.widget.FloatingActionButton
...>
</android.support.design.widget.FloatingActionButton>
</android.support.design.widget.CoordinatorLayout>

现在写代码来告诉系统,我们将使用 Toolbar 作为一个 Action Bar,更换下面的 Java 代码。

1
2
3
4
5
6
Toolbar toolbar;
private void initInstances() {
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
...
}

虽然它现在可以运行成功,但是根据我之前说的,放在 CoordinatorLayout 的东西必须被设计和实现成与它一起合作的,否则将不与任何其他兄弟 views(sibling views) 协作。但是... Toolbar是不合适的。别担心,这里没有任何新的特殊 Toolbar。只是一个组件是为了准备让 Toolbar 与 CoordinatorLayout 一起工作的更加完美。这是简单的任务,只是简单的用 AppBarLayout包裹 Toolbar,就这样!

1
2
3
4
5
6
7
8
9
10
11
12
<android.support.design.widget.CoordinatorLayout
...>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
.../>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.FloatingActionButton
...>
</android.support.design.widget.FloatingActionButton>
</android.support.design.widget.CoordinatorLayout>

现在运行和测试,如果你做的都是对的,你将会看到 Drawer Menu 会覆盖在 App Bar区域的顶部。使用了 AppBarLayout 的输出结果是:低于应用栏区域的阴影现在回来了,耶!(译者注:不晓得怎么翻了:The outgrowth of applying AppBarLayout is the drop shadow below App Bar area is now returned ! Yah !)

5

这个步骤现在完成了。从现在开始,我建议你总是用 AppBarLayout 包裹 ToolBar 元素。光凭它能带回来阴影的能力就足够有说服力。

步骤7:在内容区域放东西

我们已经得到了 FAB 和 Toolbar,现在是时候在 Activity 的内容区域放上东西了。

额。如果是两个简单的按钮呢?好吧,让我们把它们放在在 AppBarLayout 和 FAB 之间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yo Yo"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yo Yo"/>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
...>

下面是结果...

p6

这些按钮似乎都出人意料的放在了 Toolbar 下面。猜猜为什么?

是的,一些古老的原因, LinearLayout 没有被设计成与 CoordinatorLayout 协同工作。在这样的情况下,没有任何布局用来包裹 LinearLayout,使它像 Toolbar 的做法那样。但它是更加容易的,你只需要在 LinearLayout 添加一个属性告诉它的滚动行为,就像下面写的这样:

1
2
3
4
<LinearLayout
...
app:layout_behavior="@string/appbar_scrolling_view_behavior"
...>

现在,他们被放在了正确的位置了,耶!

p7

完成!=)

步骤8:玩转 TabLayout

Tab 是在 Android 应用程序中用户体验(UX)最佳实践的一部分。在以前,如果我们想要使用新的材料设计风格的 Tab,我们需要自己去为项目中下载 SlidingTabLayout 和 SlidingTabStrip 的源码。现在,我们只需要使用这个库提供的 TabLayout,它也有很多可以调整的选项。

我们应该把 TabLayout 放在哪里?根据 Android 应用程序用户体验指导原则,Tab 应该放在屏幕的顶部而不是在底部。还有,它应该在阴影部分的上面。所以,我们将其放在 AppBarLayout 里面,沿着 Toolbar。这是可以做到的, 因为 AppBarLayout 是继承自一个垂直的 LinearLayout

1
2
3
4
5
6
7
<android.support.design.widget.AppBarLayout ...>
<android.support.v7.widget.Toolbar ... />
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>

在 Java 代码中添加一些 tabs。

1
2
3
4
5
6
7
8
TabLayout tabLayout;
private void initInstances() {
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));
...
}

下面是结果:

p8

背景色会自动设置成 primary color(主题色),而导航线的颜色是强调色。但是你将会注意到 Tab 的字体仍然是黑色的,但是我们希望字体是白色的。这是因为我们还没有为 TabLayout 提供任何主题呢。TabLayout 定义主题是简单的,就像这样:

1
2
3
<android.support.design.widget.TabLayout
...
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

现在,他们是白色的了。

p9

你可以像上面这样选择手动控制 TabLayout,或者让它和 ViewPager 一起工作,自动调用 setupWithViewPager(...)。我相信这种情况会很频繁的使用。

还有,我们可以调整两个属性来显示 TabLayout。

app:tabMode - 如果你想在屏幕上显示出每个单独的 tab,就设置 tab 为 fixed的, 。它适合只有少数 tab 的时候,但是如果有很多的 tab 的时候这是一个完全错误的选择。在这种情况下你是不确定所有的 tab 是否能很好的在同一时间显示出来的。所以,你可以设置这个属性为 scrollable让用户去滚动 tab,就像 Google Play Store 那样。

app:tabGravity - 如果你想要分配所有的可用空间给每个 tab,就设置这个属性为 fill。如果你想要所有的 tab 在屏幕的中间,就设置这个属性为 center。请注意,如果 tabMode 是设置成 scrollable 的,则这个属性将会被忽略。

每个模式的样子就像下面这样:

p10

TabLayout 完成了!

步骤9:当随着内容滚动时,让 AppBarLayout 退出屏幕

一个优美的 Android 用户体验是引导 App Bar 可以随着内容滚动出屏幕的,以获得额外的空间来显示内容,并且,这已经是被证明这样的用户体验是很棒的。以前有一些应用程序已经实现了这种行为,但是开发者必须自己来实现。现在它只需要用一行代码就能轻松的完成。

首先,我们需要让内容能够滚动,先往 LinearLayout 加入一些 Button。大约20个?

1
2
3
4
5
6
7
8
9
10
11
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yo Yo"/>
...
<!-- Add 20 more buttons here -->
...
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yo Yo"/>

然后用 ScrollView 包裹这个 LinearLayout,还有, 不要忘了将 LinearLayout 里的 layout_behavior 移动到 ScrollView,因为现在 ScrollView 是 CoordinatorLayout的最直接的子 view。

1
2
3
4
5
6
7
8
9
10
11
12
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
...
</LinearLayout>
</ScrollView>

然后给 Toolbar 添加一个滚动标志,就像这样:

1
2
3
<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways" />

试试吧

6

额... 原先假定的 Toolbar 会随着内容的滚动滚出屏幕的,但是为什么它看起来什么都没有实现呢?

同样的老原因啦... ScrollView 没有被设计成与 CoordinatorLayout 协同工作(又来)。你需要另一个 view: NestedScrollView,Android Support Library v4 中有提供。这个 NestedScrollView 设计出来的目的就是为了与 CoordinatorLayout 协同工作的。

1
2
3
4
5
<android.support.v4.widget.NestedScrollView ...>
<LinearLayout ...>
...
</LinearLayout>
</android.support.v4.widget.NestedScrollView>

同样的原因,请注意了: ListView 类也是和 CoordinatorLayout 不能协同工作的。只有 RecyclerView可以。也许需要时间来改变咯~

这里将 ScrollView 改变成 NestedScrollView 后的结果。

7

运行起来真赞!你会注意到 Toolbar 滚出了屏幕,但是 TabLayout 仍然还在。这是因为我们没有给 TabLayout 设置任何滚动标志。如果你想要 TabLayout 同样从屏幕上消失,只需要给 TabLayout 定义相同的属性就可以了。

1
2
3
<android.support.design.widget.TabLayout
...
app:layout_scrollFlags="scroll|enterAlways" />

结果:

8

这里会有一些手势上的 bug。我发现拉它回到屏幕是非常困难的。看来我们得等下一个版本了。

现在,让我们来看看它的一些细节。很好奇这些标志的真实意思是什么: scrollenterAlways?事实上我们可以在这里设置4个属性值。

scroll - 你想你想要设置这个 view 随着内容滚动,你需要应用这个标志。

enterAlwaysCollapsed - 这个标志定义了 View 是如何回到屏幕的。当你的 view 已经声明了一个最小高度(minHeight) 并且你使用了这个标志,你的 View 只有在回到这个最小的高度的时候才会展开,只有当 view 已经到达顶部之后它才会重新展开全部高度。滚动标志像这样来使用它: scroll|enterAlwaysCollapsed

9

它好像在这个 minHeight 部分死活不工作。这里和 TabLayout 有另一个问题。很难把这些 View 拉回到屏幕来。

enterAlways - 这个标志确保了任何向下滚动的操作都会让这个 view 变得可见,达到“快速返回”(‘quick return’ )的效果,滚动标志像这样来使用它: scroll|enterAlways

10

exitUntilCollapsed - View 将关闭滚动直到它被折叠起来(有 minHeight) 并且一直保持这样,举个例子:

1
2
3
4
5
6
7
<android.support.v7.widget.Toolbar
...
android:layout_height="192dp"
android:gravity="bottom"
android:paddingBottom="12dp"
android:minHeight="?attr/actionBarSize"
app:layout_scrollFlags="scroll|exitUntilCollapsed"/>

下面是上述代码的结果:

11

这种模式在组件中经常使用,我将在下一个部分讨论。

步骤10: 移除 TabLayout

从实验来看,在上述情况下当我们用 TabLayout 来滚动的时候,有一些明显的 bug。我相信这只是一个 bug,而且以后会被修复的。现在,让我们首先从代码中移除 TabLayout,确保下一步运行是流畅的。

1
<!--android.support.design.widget.TabLayout -->

从 Java 代码中也删除

1
2
3
4
//tabLayout = (TabLayout) findViewById(R.id.tabLayout);
//tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
//tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
//tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));

好了,让我们去做下一步!

Step 11: Make Toolbar collapsable 步骤11:使工具栏可折叠

就像在 exitUntilCollapsed 部分所示的例子中,Toolbar 可以展开和折叠,但是你会看到它还不是很完美。Toolbar 仍然离开了屏幕,最好的体验是让这些 icon (汉堡等-即菜单栏) 应该留在屏幕内。

Design Support Library 已经为这个准备好了。用 CollapsingToolbarLayout你可以像魔术一样让 Toolbar 折叠起来,就像其他组件一样,它是非常容易使用的,具体操作步骤如下:

  • CollapsingToolbarLayout包裹 Toolbar,但仍然在 AppBarLayout

  • Toolbar中删除 layout_scrollFlags

  • CollapsingToolbarLayout声明 layout_scrollFlags,并且将 layout_scrollFlags设置成 scroll|exitUntilCollapsed

  • 改变 AppBarLayout 扩张状态时的布局高度大小。在这个例子中,我用 256dp

这是最终代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="256dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

这个结果是:

12

看起来不错,但是这些 Toolbar icons 仍然滚出了屏幕。我们可以声明这个属性给 Toolbar 来固定住它,让它总是在屏幕的顶部。

1
2
3
<android.support.v7.widget.Toolbar
...
app:layout_collapseMode="pin"/>

Toolbar现在被定住了!

13

但是,等一下…标题的文字在哪里?!不幸的是,在用 CollapsingToolbarLayout 包裹住 Toolbar 后,它随风而逝了。我们必须通过在 Java 代码中手动设置 setTitle(String)来实现。

1
2
3
4
5
6
CollapsingToolbarLayout collapsingToolbarLayout;
private void initInstances() {
...
collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout);
collapsingToolbarLayout.setTitle("Design Library");
}

结果:

14

这里的字体颜色仍然是黑的的。这是因为我们还没有为 App Ba 设置任何主题。要做到这一点,只需要简单的为 AppBarLayout声明 android:theme属性就可以了,就像这样:

1
2
3
<android.support.design.widget.AppBarLayout
...
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

现在,标题变成了白色的了!

15

由于CollapsingToolbarLayout 的 特点,应用的标题文字在收缩和展开状态是会自动过渡的。如果你想要在展开状态改变标题文字的位置,你可以这样做:通过应用的 margin 的4个属性,就是: app:expandedTitleMargin, app:expandedTitleMarginBottom, app:expandedTitleMarginEnd以及 app:expandedTitleMarginStart

或者如果你想要在折叠和展开状态时改变文本的显示。你可以这样来简单的实现:设置 TextAppearance,分别通过 app:collapsedTitleTextAppearanceapp:expandedTitleTextAppearance来设置。

让我们从试着改变 margin 为64dp 开始。

1
2
3
<android.support.design.widget.CollapsingToolbarLayout
...
app:expandedTitleMarginStart="64dp">

结果:

16

真棒!

步骤12:为 App Bar 添加背景图片

在这种情况下,我们想要用一张美丽的图片作为 App Bar 的背景,而不只是像现在这样的一个普通的颜色。幸运的是 CollapsingToolbarLayout 是继承自 FrameLayout 所以我们可以轻松的添加一个 ImageView 作为 Toolbar 的背景图层,就像这样:

1
2
3
4
5
6
7
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/header" />
<android.support.v7.widget.Toolbar
...

结果:

17

图片已经显示出来了,但是这里有一点还没有达到预期,蓝色的导航条仍旧显示着。有一个 Toolbar 的背景看起来不是酷炫的。从 Toolbar 移除它,只需要下面这行代码就行了。

1
android:background="?attr/colorPrimary"

结果:

18

现在图片是随着内容的滚动了,但是看起来太呆了。我们可以使用视差模式让它变得更优雅一些,只需要声明 collapse 就行了,像下面这样:

1
2
3
<ImageView
...
app:layout_collapseMode="parallax" />

结果:

19

你也可以设置视差的系数,介于 0.0-1.0之间。

1
app:layout_collapseParallaxMultiplier="0.7"

请你自己去尝试一下=)

最后你可能会注意到 App Bar 的背景总显示一张图片。你可以让它在收缩的时候自动的变化到普通的颜色,通过声明属性 app:contentScrim 像下面这样来实现:

1
2
3
<android.support.design.widget.CollapsingToolbarLayout
...
app:contentScrim="?attr/colorPrimary">

结果:

20

只用了几行代码,就让 App Bar 变得这么漂亮了 =)

步骤13:玩转 Navigation Drawer

现在从左侧拉出 Drawer Menu 仍然只是一个空白的面板。在以前,实现这个菜单是非常麻烦的,因为我们不得不手动的用 LinearLayout 或者 ListView 去实现。

在 Android Design Support Library 中提供了 NavigationView,实现它变得更容易了,它为我们节省了15.84321倍的时间!

首先,为 Drawer Menu 创建一个标题视频布局文件。(它已经在 Github的项目中了)

res/layout/nav_header.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="192dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/nav_header_bg"
android:scaleType="centerCrop" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/nuuneoi"
android:layout_gravity="bottom"
android:layout_marginBottom="36dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="16dp"
android:text="nuuneoi"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
</FrameLayout>

现在创建一个菜单资源文件

res/menu/navigation_drawer_items.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="all">
<item
android:id="@+id/navItem1"
android:icon="@drawable/ic_action_location_found_dark"
android:title="Home"/>
<item
android:id="@+id/navItem2"
android:icon="@drawable/ic_action_location_found_dark"
android:title="Blog"/>
<item
android:id="@+id/navItem3"
android:icon="@drawable/ic_action_location_found_dark"
android:title="About"/>
<item
android:id="@+id/navItem4"
android:icon="@drawable/ic_action_location_found_dark"
android:title="Contact"/>
</group>
</menu>

NavigationView与两个资源文件绑定起来,作为 Drawer Menu 的菜单区域,用下面的代码来替换一个已经存在的 白色的 LinearLayout :

1
2
3
4
5
6
7
8
9
10
11
12
...
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
app:itemIconTint="#333"
app:itemTextColor="#333"
app:menu="@menu/navigation_drawer_items" />
</android.support.v4.widget.DrawerLayout>

现在:召唤 Drawer Menu!哇喔,哇喔

21

NavigationView 就是为了 Drawer Menu 而特别设计的。所以,所有的东西都会被创建并且自动测量包括菜单的宽度等,我们自己定义案例来配置以前的设计。

为了处理这些菜单项的点击事件,你可以声明 setNavigationItemSelectedListener来监听,就像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NavigationView navigation;
private void initInstances() {
...
navigation = (NavigationView) findViewById(R.id.navigation);
navigation.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
int id = menuItem.getItemId();
switch (id) {
case R.id.navItem1:
break;
case R.id.navItem2:
break;
case R.id.navItem3:
break;
}
return false;
}
});
}

在实际使用中,请随意的区声明你想要定义的 header view 和修改菜单项。

步骤14:用上 TextInputLayout 让 EditText 变的更风骚

这是 Codelab 的最后一部分了。你可以改变一个旧的 EditText 的风格,让它变得更时髦,即:总是会显示一个提示或者一个错误信息。

要做到这一点,只需要简单的用 TextInputLayout 包裹住一个 EditText ,就这么简单!

1
2
3
4
5
6
7
8
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Username" />
</android.support.design.widget.TextInputLayout>

把这两个控件放到 NestedScrollView 里看下结果。

22

难以置信的容易吧?=)

结论

Android Design Support Library 是非常有前途的支持库,它非常值得在你的产品上使用。虽然它仍然包含了很多错误,我建议你再等等,直到每个错误都被修复。

这么长的教程,希望希望你觉得它有用 =)

`
p11
Author: nuuneoi (Android GDE, CTO & CEO at The Cheese Factory)
A full-stack developer with more than 6 years experience on Android Application Development and more than 12 years in Mobile Application Development industry. Also has skill in Infrastucture, Service Side, Design, UI&UX, Hardware, Optimization, Cooking, Photographing, Blogging, Training, Public Speaking and do love to share things to people in the world!

Android 和 Mac 连爆毁灭级安全漏洞,数字居民何以安身立命?

$
0
0

glebstock140501410

数字安全事件我们常有耳闻,比如  12306 账户信息泄露和携程用户信用卡泄露,它们都属于网络安全范畴。而最近两件重大安全事件则实属罕见,一个是系统级别的漏洞,一个是固件层面的隐形蠕虫。

几天前,网络安全机构 Zimperium 在 Android 系统上发现了一个堪称 Android 有史以来最严重漏洞——Stagefright。

这个漏洞波及了 9.5 亿左右的 Android 手机,从多年前的 Android 2.2 到最近的 Android 5.1 之间的各个系统版本都有可能中招。它的厉害之处在于,黑客只需要知道你的手机号码,发一条彩信就可以入侵用户的手机,在远端执行代码读取、控制你手机中的内容,甚至不需要你去打开这条彩信。

stagefright

无独有偶,近日不少媒体接连报道了一个在 Mac 固件层面上的隐形蠕虫—— Thunderstrike 2。与计算机病毒不同的是,计算机蠕虫不需要附在别的程序内。计算机蠕虫未必会直接破坏被感染的系统,却几乎都对网络有害。

这个蠕虫其实是 Thunderstrike 的升级版。今年年初德国汉堡举行的 CCC 大会(Chaos Communication Congress )上,安全专家 Trammell Hudson 展示了一种针对 Mac 固件层面的恶意软件——Thunderstrike(雷击)。它实际上是利用了一个在 Thunderbolt Option ROM 的漏洞,这个漏洞在 2012 年首次被发现但至今仍未修补。

Thunderstrike 主要通过 Mac 上的 Thunderbolt 接口传播恶意软件。恶意软件通过 Thunderbolt 接口进入到 Mac 中,然后自动在固件层面安装,获得系统控制权限,接着肆无忌惮地偷取用户一切信息。

这种 Thunderbolt 恶意软件厉害的地方在于,它独立于操作系统和硬盘驱动,难以被系统侦测到,即使格式化硬盘和重装操作系统也没有办法彻底根除。

近日,这位 Trammell Hudson 联手另一位安全专家 Xeno Kovah 研究出了 Thunderstrike 的升级版——Thunderstrike 2。前面说到,Thunderstrike 依靠 Thunderbolt 接口的物理接触,而 Thunderstrike 2 则可以通过恶意网站或者电子邮件来远程传播。

对于这两个重大安全漏洞,Google 和苹果的反应还算迅速。Google 今日 宣布,除了常规的平台升级之外,从本周开始,所有 Nexus 设备每个月都将收到 OTA 升级推送。首个安全更新在 8 月 5 日放出。

据《卫报》 报道,苹果已经承诺尽快修复 Mac 这个固件层面的漏洞。与此同时,苹果将采取临时的措施来阻止漏洞被利用,其中包括废除利用这个漏洞的开发者证书,以及任何利用恶意软件进行升级的应用。

(Thunderstrike 2 攻击演示)

对于没有技术背景的大众普通消费者来说,不管是 Android 在系统层面上的漏洞,还是 Mac 在固件上的蠕虫,能做的似乎也只有保持关注,厂商或者软件开发商一发布漏洞补丁立刻更新安装。

事实上,相较于上面提到的系统安全问题和计算机固件层面的漏洞,我们平时使用电子设备上网遇到的更多是网络安全问题。

中国互联网协会近日发布的《中国网民权益保护调查报告(2015)》 显示,78% 的网民个人身份信息曾遭泄露,包括姓名、身份证号码、工作单位及家庭住址等。63% 的网民个人网上活动信息被泄露过,包括通话记录、网络浏览纪录、IP 地址及地理位置等。82% 的网民亲身感受到了个人信息泄露对日常生活造成的影响。

image

日常生活中我们知道保护手机号码和身份证号码,正确的网络安全防范措施同样应该成为每个“数字居民”的常识。

Google 近期发表了一篇名为“没有人能攻击我的大脑:专业人士与非专业人士安全行为对比”的 报告。这份报告针对 231 名安全专家和 294 名非安全专家的网络用户做了调查,询问他们在网络安全方面通常采取哪些措施。

调查结果显示,专业人士的 5 个首选安全行为是:

  1. 安装软件更新
  2. 使用独有密码
  3. 使用双重认证
  4. 使用安全性强的密码
  5. 使用密码管理器

而非安全专家的网络用户的 5 个首选安全行为则是:

  1. 使用防病毒软件
  2. 使用安全性强的密码
  3. 经常更改密码
  4. 仅访问自己了解的网站
  5. 不共享个人信息

w1408

这里有一个有趣的点,专业人士的 5 个首选安全行为里面全部没有“使用防病毒软件”,而非安全专家的的网络用户则把“使用防病毒软件”放在了第 1 位。

调查指出,非专业人士往往没有意识到及时更新软件的重要性,并且有所质疑:

我不了解更新软件是否能够确保安全。如果下载了恶意软件岂不是很糟糕?我认为软件自动更新并不安全,因为它可能会被用于更新恶意内容。

对此,专业人士解释道,防病毒软件有它自身的优势,但它会误导用户对安全性的理解,以为安装了防病毒软件就能一劳永逸。及时更新软件才是网络安全的重要保障。

在专业人士的选择中,我们还可以看到 2-4 位的都是和密码相关的安全措施。“使用独有密码”可以最大限度地防止“ 撞库攻击”所造成的密码泄露。之前 12306 用户信息泄露事件就是黑客通过“撞库攻击”所引起的。

“双重认证”相当于给你的家门上了两把锁,而且是两把完全不一样的锁。像 Gmail 的双重认证就包括第一重的密码认证,以及第二重的短信认证或者身份验证器( Google Authenticator)生成的随机数字组合认证。

Google 的调查还显示,仅有 24% 的非专业人士为部分账户使用密码管理器,而 73% 的专业人士会把全部密码都交由密码管理器管理。调研结果指出,这种差异存在的原因在于,非专业人士对密码管理器的优势缺乏了解,以及对此类程序缺乏信任。

尽管 LastPass 曾爆出安全漏洞,但专业付费的密码管理器仍是现在安全系数比较高的密码管理解决方案。密码管理器还可以生成高强度的不规律密码组合,提高密码的破解难度。

对于希望进一步了解网络安全的读者,我们鼓励阅读这份调研报告的 英文原文。报告不仅阐述了大众对于基本网络安全实践的主要误解,还提供一系列技巧帮助大家过上更安全的数字生活。

 

题图来自 123RF

报道倾向:消费电子、虚拟现实、工具类 app。工作邮箱:oudi@ifanr.com。

#欢迎关注爱范儿认证微信公众号:AppSolution(微信号:appsolution),发现新酷精华应用。



爱范儿 · Beats of Bits |原文链接· 查看评论· 新浪微博· 微信订阅


Android M 新的运行时权限开发者需要知道的一切

$
0
0

英文: http://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
译文: http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/

android M 的名字官方刚发布不久,最终正式版即将来临!
android在不断发展,最近的更新 M 非常不同,一些主要的变化例如运行时权限将有颠覆性影响。惊讶的是android社区鲜有谈论这事儿,尽管这事很重要或许在不远的将来会引发很严重的问题。
这是今天我写这篇博客的原因。这里有一切关于android运行时权限你需要知道的,包括如何在代码中实现。现在亡羊补牢还不晚。

新运行时权限

android的权限系统一直是首要的安全概念,因为这些权限只在安装的时候被询问一次。一旦安装了,app可以在用户毫不知晓的情况下访问权限内的所有东西。
难怪一些坏蛋利用这个缺陷恶意收集用户数据用来做坏事了!
android小组也知道这事儿。7年了!权限系统终于被重新设计了。在android6.0棉花糖,app将不会在安装的时候授予权限。取而代之的是,app不得不在运行时一个一个询问用户授予权限。

图片描述

注意权限询问对话框不会自己弹出来。开发者不得不自己调用。如果开发者要调用的一些函数需要某权限而用户又拒绝授权的话,函数将抛出异常直接导致程序崩溃。

图片描述

另外,用户也可以随时在设置里取消已经授权的权限。

图片描述

你或许已经感觉到背后生出一阵寒意。。。如果你是个android开发者,意味着要完全改变你的程序逻辑。你不能像以前那样直接调用方法了,你不得不为每个需要的地方检察权限,否则app就崩溃了!
是的。我不能哄你说这是简单的事儿。尽管这对用户来说是好事,但是对开发者来说就是噩梦。我们不得不修改编码不然不论短期还是长远来看都是潜在的问题。
这个新的运行时权限仅当我们设置targetSdkVersion to 23(这意味着你已经在23上测试通过了)才起作用,当然还要是M系统的手机。app在6.0之前的设备依然使用旧的权限系统。

已经发布了的app会发生什么

新运行时权限可能已经让你开始恐慌了。“hey,伙计!我三年前发布的app可咋整呢。如果他被装到android 6.0上,我的app会崩溃吗?!?”
莫慌张,放轻松。android小队又不傻,肯定考虑到了这情况。如果app的targetSdkVersion 低于 23,那将被认为app没有用23新权限测试过,那将被继续使用旧有规则:用户在安装的时候不得不接受所有权限,安装后app就有了那些权限咯!

图片描述

然后app像以前一样奔跑!注意,此时用户依然可以取消已经同意的授权!用户取消授权时,android 6.0系统会警告,但这不妨碍用户取消授权。

图片描述

问题又来了,这时候你的app崩溃吗?
善意的主把这事也告诉了android小组,当我们在targetSdkVersion 低于23的app调用一个需要权限的函数时,这个权限如果被用户取消授权了的话,不抛出异常。但是他将啥都不干,结果导致函数返回值是null或者0.

图片描述

别高兴的太早。尽管app不会调用这个函数时崩溃,返回值null或者0可能接下来依然导致崩溃。
好消息(至少目前看来)是这类取消权限的情况比较少,我相信很少用户这么搞。如果他们这么办了,后果自负咯。
但从长远看来,我相信还是会有大量用户会关闭一些权限。我们app不能再新设备完美运行这是不可接受的。
怎样让他完美运行呢,你最好修改代码支持最新的权限系统,而且我建议你立刻着手搞起!
代码没有成功改为支持最新运行时权限的app,不要设置targetSdkVersion 23 发布,否则你就有麻烦了。只有当你测试过了,再改为targetSdkVersion 23 。
警告:现在你在android studio新建项目,targetSdkVersion 会自动设置为 23。如果你还没支持新运行时权限,我建议你首先把targetSdkVersion 降级到22

PROTECTION_NORMAL类权限

当用户安装或更新应用时,系统将授予应用所请求的属于 PROTECTION_NORMAL 的所有权限(安装时授权的一类基本权限)。这类权限包括:

android.permission.ACCESS LOCATIONEXTRA_COMMANDS
android.permission.ACCESS NETWORKSTATE
android.permission.ACCESS NOTIFICATIONPOLICY
android.permission.ACCESS WIFISTATE
android.permission.ACCESS WIMAXSTATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE NETWORKSTATE
android.permission.CHANGE WIFIMULTICAST_STATE
android.permission.CHANGE WIFISTATE
android.permission.CHANGE WIMAXSTATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND STATUSBAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET PACKAGESIZE
android.permission.INTERNET
android.permission.KILL BACKGROUNDPROCESSES
android.permission.MODIFY AUDIOSETTINGS
android.permission.NFC
android.permission.READ SYNCSETTINGS
android.permission.READ SYNCSTATS
android.permission.RECEIVE BOOTCOMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST INSTALLPACKAGES
android.permission.SET TIMEZONE
android.permission.SET_WALLPAPER
android.permission.SET WALLPAPERHINTS
android.permission.SUBSCRIBED FEEDSREAD
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE SYNCSETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

只需要在AndroidManifest.xml中简单声明这些权限就好,安装时就授权。不需要每次使用时都检查权限,而且用户不能取消以上授权。

让你的app支持新运行时权限

是时候让我们的app支持新权限模型了,从设置compileSdkVersion and targetSdkVersion 为 23开始吧.

android {
    compileSdkVersion 23
    ...
    defaultConfig {
        ...
        targetSdkVersion 23
        ...
    }

例子,我想用一下方法添加联系人。

private static final String TAG = "Contacts";
private void insertDummyContact() {
    // Two operations are needed to insert a new contact.
    ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(2);
    // First, set up a new raw contact.
    ContentProviderOperation.Builder op =
            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
    operations.add(op.build());
    // Next, set the name for the contact.
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,"__DUMMY CONTACT from runtime permissions sample");
    operations.add(op.build());
    // Apply the operations.
    ContentResolver resolver = getContentResolver();
    try {
        resolver.applyBatch(ContactsContract.AUTHORITY, operations);
    } catch (RemoteException e) {
        Log.d(TAG, "Could not add a new contact: " + e.getMessage());
    } catch (OperationApplicationException e) {
        Log.d(TAG, "Could not add a new contact: " + e.getMessage());
    }
}

上面代码需要WRITE_CONTACTS权限。如果不询问授权,app就崩了。
下一步像以前一样在AndroidManifest.xml添加声明权限。

<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

下一步,不得不再写个方法检查有没有权限。如果没有弹个对话框询问用户授权。然后你才可以下一步创建联系人。

权限被分组了,如下表:

图片描述

同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE CONTACTS被授权了,app也有READCONTACTS和GET_ACCOUNTS了。
源码中被用来检查和请求权限的方法分别是Activity的checkSelfPermission和requestPermissions。这些方法api23引入。

final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
private void insertDummyContactWrapper() {
    int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
    if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
    }
    insertDummyContact();
}

如果已有权限,insertDummyContact()会执行。否则,requestPermissions被执行来弹出请求授权对话框,如下:

图片描述

不论用户同意还是拒绝,activity的onRequestPermissionsResult会被回调来通知结果(通过第三个参数),grantResults,如下:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_PERMISSIONS:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission Granted
                insertDummyContact();
            } else {
                // Permission Denied
                Toast.makeText(MainActivity.this, "WRITE_CONTACTS Denied", Toast.LENGTH_SHORT)
                        .show();
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

这就是新权限模型工作过程。代码真复杂但是只能去习惯它。。。为了让app很好兼容新权限模型,你不得不用以上类似方法处理所有需要的情况。
如果你想捶墙,现在是时候了。。。

处理 “不再提醒”

如果用户拒绝某授权。下一次弹框,用户会有一个“不再提醒”的选项的来防止app以后继续请求授权。

图片描述

如果这个选项在拒绝授权前被用户勾选了。下次为这个权限请求requestPermissions时,对话框就不弹出来了,结果就是,app啥都不干。
这将是很差的用户体验,用户做了操作却得不到响应。这种情况需要好好处理一下。在请求requestPermissions前,我们需要检查是否需要展示请求权限的提示通过activity的shouldShowRequestPermissionRationale,代码如下:

final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
private void insertDummyContactWrapper() {
    int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
    if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
                showMessageOKCancel("You need to allow access to Contacts",
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                                        REQUEST_CODE_ASK_PERMISSIONS);
                            }
                        });
                return;
            }
        requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
    }
    insertDummyContact();
}
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setPositiveButton("OK", okListener)
            .setNegativeButton("Cancel", null)
            .create()
            .show();
}

当一个权限第一次被请求和用户标记过不再提醒的时候,我们写的对话框被展示。
后一种情况,onRequestPermissionsResult 会收到PERMISSION_DENIED ,系统询问对话框不展示。

图片描述

搞定!

一次请求多个权限

当然了有时候需要好多权限,可以用上面方法一次请求多个权限。不要忘了为每个权限检查“不再提醒”的设置。
修改后的代码:

final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
private void insertDummyContactWrapper() {
    List<String> permissionsNeeded = new ArrayList<String>();
    final List<String> permissionsList = new ArrayList<String>();
    if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
        permissionsNeeded.add("GPS");
    if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
        permissionsNeeded.add("Read Contacts");
    if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
        permissionsNeeded.add("Write Contacts");
    if (permissionsList.size() > 0) {
        if (permissionsNeeded.size() > 0) {
            // Need Rationale
            String message = "You need to grant access to " + permissionsNeeded.get(0);
            for (int i = 1; i < permissionsNeeded.size(); i++)
                message = message + ", " + permissionsNeeded.get(i);
            showMessageOKCancel(message,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                        }
                    });
            return;
        }
        requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
        return;
    }
    insertDummyContact();
}
private boolean addPermission(List<String> permissionsList, String permission) {
    if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
        permissionsList.add(permission);
        // Check for Rationale Option
        if (!shouldShowRequestPermissionRationale(permission))
            return false;
    }
    return true;
}

如果所有权限被授权,依然回调onRequestPermissionsResult,我用hashmap让代码整洁便于阅读。

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
            {
            Map<String, Integer> perms = new HashMap<String, Integer>();
            // Initial
            perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
            // Fill with results
            for (int i = 0; i < permissions.length; i++)
                perms.put(permissions[i], grantResults[i]);
            // Check for ACCESS_FINE_LOCATION
            if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED&& perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED&& perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
                // All Permissions Granted
                insertDummyContact();
            } else {
                // Permission Denied
                Toast.makeText(MainActivity.this, "Some Permission is Denied", Toast.LENGTH_SHORT)
                        .show();
            }
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

条件灵活的,你自己设置。有的情况,一个权限没有授权,就不可用;但是也有情况,能工作,但是表现的是有所限制的。对于这个我不做评价,你自己设计吧。

用兼容库使代码兼容旧版

以上代码在android 6.0以上运行没问题,但是23 api之前就不行了,因为没有那些方法。
粗暴的方法是检查版本

if (Build.VERSION.SDK_INT >= 23) {
    // Marshmallow+
} else {
    // Pre-Marshmallow
}

但是太复杂,我建议用v4兼容库,已对这个做过兼容,用这个方法代替:

  • ContextCompat.checkSelfPermission()

被授权函数返回PERMISSION GRANTED,否则返回PERMISSIONDENIED ,在所有版本都是如此。

  • ActivityCompat.requestPermissions()
    这个方法在M之前版本调用,OnRequestPermissionsResultCallback 直接被调用,带着正确的 PERMISSION GRANTED或者 PERMISSIONDENIED 。

  • ActivityCompat.shouldShowRequestPermissionRationale()
    在M之前版本调用,永远返回false。

用v4包的这三方法,完美兼容所有版本!这个方法需要额外的参数,Context or Activity。别的就没啥特别的了。下面是代码:

private void insertDummyContactWrapper() {
    int hasWriteContactsPermission = ContextCompat.checkSelfPermission(MainActivity.this,
            Manifest.permission.WRITE_CONTACTS);
    if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
        if (!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_CONTACTS)) {
            showMessageOKCancel("You need to allow access to Contacts",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[] {Manifest.permission.WRITE_CONTACTS},
                                    REQUEST_CODE_ASK_PERMISSIONS);
                        }
                    });
            return;
        }
        ActivityCompat.requestPermissions(MainActivity.this,
                new String[] {Manifest.permission.WRITE_CONTACTS},
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
    }
    insertDummyContact();
}

后两个方法,我们也可以在Fragment中使用,用v13兼容包:FragmentCompat.requestPermissions() and FragmentCompat.shouldShowRequestPermissionRationale().和activity效果一样。

第三方库简化代码

以上代码真复杂。为解决这事,有许多第三方库已经问世了,真有速度!我试了很多最终找到了个满意的hotchemi’s PermissionsDispatcher。
他和我上面做的一样,只是简化了代码。灵活易扩展,试一下吧。如果不满足你可以找些其他的。

如果我的app还开着呢,权限被撤销了,会发生什么

权限随时可以被撤销。

图片描述

当app开着的时候被撤消了会发生什么呢?我试过了发现这时app会突然终止 terminated。app中的一切都被简单粗暴的停止了,因为terminated!对我来说这可以理解,因为系统如果允许它继续运行(没有某权限),这会召唤弗雷迪到我的噩梦里。或许更糟…

结论建议

我相信你对新权限模型已经有了清晰的认识。我相信你也意识到了问题的严峻。
但是我们没得选择。新运行时权限已经在棉花糖中被使用了。我们没有退路。我们现在唯一能做的就是保证app适配新权限模型.
欣慰的是只有少数权限需要运行时权限模型。大多数常用的权限,例如,网络访问,属于Normal Permission 在安装时自动会授权,当然你要声明,以后无需检查。因此,只有少部分代码你需要修改。

两个建议:

  1. 严肃对待新权限模型

  2. 如果你代码没支持新权限,不要设置targetSdkVersion 23 。尤其是当你在Studio新建工程时,不要忘了修改!

说一下代码修改。这是大事,如果代码结构被设计的不够好,你需要一些很蛋疼的重构。每个app都要被修正。如上所说,我们没的选择。。。
列出所有你需要请求的权限所有情形,如果A被授权,B被拒绝,会发生什么。blah,blah。

祝重构顺利。把它列为你需要做的大事,从现在就开始着手做,以保证M正式发布的时候没有问题。

希望本文对你有用,祝你好运。。。

Viewing all 101 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>