作者归档:drakeet

Android 密钥保护和 C/S 网络传输安全理论指南

预览:本文将着重讲解 Android KeyStore、so 库保护 app key / secret、HTTPS 原理及其防中间人攻击措施。

谈到 Android 安全性话题,Android Developers 官方网站给出了许多很好的建议和讲解,涵盖了存储数据、权限、网络、处理凭据、输入验证、处理用户数据、加密等方方面面,甚至对于动态加载代码也提供了建议,具体可以看看 training 的 security tips 章节。而今天,我想特别来讲一讲在 Android 密钥保护和 C/S 网络传输安全 这两方面的具体安全措施。

密钥的保护以及网络传输安全 应该是移动应用安全最关键的内容。

所谓的密钥,简单来说,可以认为是我们常用的 app key / secret / token 或数据加密的 key,这些 keys 就像我们宝库的钥匙,一旦泄露,就像大门被人撬开,什么安全都无从谈起。因此,密钥们的安全存储、防窃取便显得异常重要。我曾经看过许多国内外著名的应用在使用自家 API 或 SaaS 服务的时候,在 Java 代码或 SharePreferences 里明文记录着 app key / secret / token,这样的做法,就算使用了 proguard 对代码进行混淆,也是非常容易被逆向获得服务端接入密钥,非常危险。

在这一方面,Android 提供大量用来保护数据的加密算法,例如 Cipher 类中提供了 AES 和 RSA 算法,再例如安全随机数生成器 SecureRandom 给 KeyGenerator 提供了更加可靠的初始化参数,避免离线攻击等等。

而如果需要存储密钥以供重复使用,Android 提供了 KeyStore 等可以长期存储和检索加密密钥的机制,Android KeyStore 系统特别适合于存储加密密钥。”AndroidKeyStore” 是 KeyStore 的一个子集,存进 AndroidKeyStore 的 key 将受到签名保护,并且这些 key 是存在系统里的,而不是在 App 的 data 目录下,依托于硬件的 KeyChain 存储,可以做到 private key 一旦存入就无法取出,总之,每个 App 自己创建的 key,别的应用是访问不到的。

继续阅读

Android 复杂的列表视图新写法: MultiType 详解篇

前言

在开发我的 TimeMachine 时,我有一个复杂的聊天页面,于是我设计了我的类型池系统,它是完全解耦的,因此我能够轻松将它抽离出来分享,并给它取名为 MultiType.

从前,比如我们写一个类似微博列表页面,这样的列表是十分复杂的:有纯文本的、带转发原文的、带图片的、带视频的、带文章的等等,甚至穿插一条可以横向滑动的好友推荐条目。不同的 item 类型众多,而且随着业务发展,还会更多。如果我们使用传统的开发方式,经常要做一些繁琐的工作,代码可能都堆积在一个 Adapter 中:我们需要覆写 RecyclerView.AdaptergetItemViewType 方法,罗列一些 type 整型常量,并且 ViewHolder 转型、绑定数据也比较麻烦。一旦产品需求有变,或者产品设计说需要增加一种新的 item 类型,我们需要去代码堆里找到我们原来的逻辑去修改,或者找到正确的位置去增加代码。这些过程都比较繁琐,侵入较强,需要小心翼翼,以免改错影响到其他地方。

现在好了,我们有了 MultiType,简单来说,MultiType 就是一个多类型列表视图的中间分发框架,它能帮助你快速并且清晰地开发一些复杂的列表页面。它本是为聊天页面开发的,聊天页面的消息类型也是有大量不同种类,并且新增频繁,而 MultiType 能够轻松胜任,代码模块化,随时可拓展新的类型进入列表当中。它内建了 类型View 的复用池系统,支持 RecyclerView,使用简单灵活,令代码清晰、拥抱变化。

因此,我写了这篇文章,目的有几个:一是以作者的角度对 MultiType 进行入门和进阶详解。二是传递我开发过程中的思想、设计理念,这些偏细腻的内容,即使不使用 MultiType,想必也能带来很多启发。最后就是把我自觉得不错的东西分享给大家,试想如果你制造的东西很多人在用,即使没有带来任何收益,也是一件很自豪的事情。

目录

MultiType 的特性

  • 轻盈,整个类库只有 10 个类文件,aarjar 包大小只有 10KB
  • 周到,支持 局部类型池 和 全局类型池,并支持二者共用,当出现冲突时,以局部的为准
  • 灵活,几乎所有的部件(类)都可被替换、可继承定制,面向接口/抽象编程
  • 纯粹,只负责本分工作,专注多类型的列表视图 类型分发
  • 高效,没有性能损失,内存友好,最大限度发挥 RecyclerView 的复用性
  • 可读,代码清晰干净、设计精巧,极力避免复杂化,可读性很好,为拓展和自行解决问题提供了基础

总览

MultiType 能轻松实现如下页面,它们将在示例篇章具体提供:


继续阅读

支持 LowPoly, 轻巧强大的打码应用:纯纯打码 v2.9

纯纯打码是一款由我独立设计和开发、专注打码的轻应用,包含功能:传统马赛克、毛玻璃效果、选区和手指模式打码,更有创新型高亮打码和 LowPoly 风格马赛克。只为满足一个纯纯的打码需求,让打码也能成为一种赏心悦目。

只有 2.6MB 大小,精致而专业。photo_2016-10-13_12-51-32

v2.9.3 (大幅优化和更新):

  • 新增 LowPoly 马赛克风格
  • 修复 Android 5.0 以下系统无法使用 LowPoly 问题
  • 优化 缩放图片流畅度
  • 优化 图片边缘选择
  • 新增 模式选中下标
  • 新增 显式调整栏
  • 新增 高亮模式暗度调整
  • 提示: 可通过其他应用分享图片到纯纯打码进行打码

下载:http://fir.im/puremosaic

动态导航总线 Phoenix – URL Router

在我们 Android 开发过程中,在做页面跳转的时候,一般情况下都是写死了代码逻辑,比如 startActivity(new Intent(context, SomeActivity.class)) 或者使用 scheme URL 方式隐性 Intent 跳转,无论如何,一旦我们写完了代码发布出去后,便无法更改跳转逻辑了,而且传统的 Class 跳转将强依赖目标类文件,造成了模块化开发的困难。

如果这时候某个页面出现了巨大的 bug,我们无法在不更新程序的情况下,动态将它转向到一个专门的 error 页面或者某个临时替代的 H5 Web 页面。

即 A -> B 是一个既定的关系,为了达到动态化,必然需要对整个 App 的导航进行统一处理,经过路由中心分发,这就是 URL Router 要做的事情。

Phoenix-URLRouter 便是这样一个 Android 平台上的 URL Router,实现了路由规则的动态可配置性,AOP,以及方便的参数、数据传递。

特性

继续阅读

当我们谈 XML 布局文件代码的优雅性

当我们谈代码的优雅性,是不可以忽略经常在打交道的 Android XML 布局文件的书写。有人会问,XML 文件内容有什么优雅不优雅的,不都是随便写吗?嗯,是有很多人,根本就没有意识到或者不关心布局文件内容应该怎么写更好看,更漂亮。我觉得,优雅的 Android XML 布局文件的内容,应该做到以下几点:

  • 不能有多余的空行;
  • 不要保留你注释掉的代码(要回溯我们有 git);
  • 尽量避免 hard code(硬编码);
  • 能复用的资源尽量抽出到对应的 value 文件;
  • 尽量消除警告、单词拼写错误;
  • 不要使用废弃的关键词,如 fill_parent、dip;
  • 属性条目要有序;

其中,本文特别想讲的就是最后一条,“属性条目要有序”,属性条目指的是,比如一个 ImageView 节点下的 android:id, android:layout_width, android:paddingLeft, android:src … 等等这些。大部分人在书写 Android XML 布局文件的时候,都是想到一个要设置的属性,就随意在原有的属性们之下一行,再加上一行新属性,这样导致诸如 android:id 有时会在最后一行,有时在一堆属性中间,不仅不利于我们在需要 id 的时候,肉眼查找阅读,也会使得整个 XML 文件内容没有规则,很凌乱。

继续阅读

使用 MailOtto 做预加载

最近我开源了一个专注懒事件的事件总线 MailOtto: https://github.com/drakeet/MailOtto 并写了一个用它来做预加载的实践案例:第一个页面预先为第四个页面发起数据加载请求,等用户进入第四个页面,那加载好的数据才会分发给它,若在数据下来前进入第四个页面,也会等完成的时候自动接收到。

这个数据需要 8 秒,如果进入到第四个页面才开始加载,体验就很不好,就算只要 1 秒,也会有一个文本从无到有闪动的过程。如果在第一个页面停留超过 8 秒,它足够完成全程预加载,进入第四个页面里面就能直接拿到数据,可谓完美预加载。

本文就是来介绍一下这个实践案例。
继续阅读

Android 内存泄漏案例和解析

Android 编程所使用的 Java 是一门使用垃圾收集器(GC, garbage collection)来自动管理内存的语言,它使得我们不再需要手动调用代码来进行内存回收。那么它是如何判断的呢?简单说,如果一个对象,从它的根节点开始不可达的话,那么这个对象就是没有引用的了,是会被垃圾收集器回收的,其中,所谓的 “根节点” 往往是一个线程,比如主线程。因此,如果一个对象从它的根节点开始是可达的有引用的,但实际上它已经没有再使用了,是无用的,这样的对象就是内存泄漏的对象,它会在内存中占据我们应用程序原本就不是很多的内存,导致程序变慢,甚至内存溢出(OOM)程序崩溃。

内存泄漏的原因并不难理解,但仅管知道它的存在,往往我们还是会不知觉中写出致使内存泄漏的代码。在 Android 编程中,也是有许多情景容易导致内存泄漏,以下将一一列举一些我所知道的内存泄漏案例,从这些例子中应该能更加直观了解怎么导致了内存泄漏,从而在编程过程中去避免。
继续阅读

浅谈 Android 编程思想和架构

我主要是想讲一讲自己对于 接口、模块化、MVP 的一些心得。

有这么一个场景,两个不同的页面,包含了看起来一模一样的界面内容(或者称 frame/UI),这种场景可能很常见,有时看到会说:“哈哈,我可以设计个复用!” 但是遇到一个问题是,这两个页面需要分别去请求不同的服务端 API,返回下来的数据结构也不一样(姑且不说去和服务端开发协商),这样就会导致具体的 view holder 或者适配器在绑定数据的时候无法复用,为何说无法复用或难以复用呢?举个例子,比如传进 Apdapter 的 list item 数据内容不一样,你总不能把 item 再拆了,分好几个 list 传进去吧?面向具体编程情况下,适配器得到不同的 items,得对 item 分发数据绑定到 UI,难免要写很多重复的代码。

这时候我们可以采取面向抽象编程,既然不同的数据对应一样的 UI,如果它们都实现了一样的接口,这个接口的设计取决于 UI 需要哪些数据块,然后不同的 Item model 去实现这个接口提供数据即可,这时适配器只要持有这个接口类型的 Item 即可,举个通俗的例子:数据模型1和2都实现了 IPost 接口,那么适配器就只要持有 List<IPost> 数据即可,List<数据模型1> 和 List<数据模型2> 都可以视作“一样的鸭子”传递给这个适配器。这样把数据模型的数据块抽取放到了数据模型本身实现,不仅不用写很多重复的分发代码,而且适配器本身都能复用了;当接口需要新的方法,也能驱动着实现者们去实现。
继续阅读

Retrofit 2.0 + OkHttp 3.0 配置

Retrofit 和 OkHttp 都是伟大的 Square 公司开源的伟大项目。前段时间也是从 Retrofit 1.9 升级到 2.0 beta 4 版本,从 OkHttp 2.+ 版本升级到  3.0.1 版本。这两者在各自的这两个大版本升级中,都改变了不少,使得原本的代码都需要进行一些修改才能使用,我也是稍微摸索了几下,如今大致摸清,把一些基础配置,比如设置 Json 转换器、RxJava 适配器、设置 Debug Log 模式、设置超时、错误重连,以及配置 Access token Interceptor 等等一些内容,分享一下。
继续阅读