阿里巴巴Android开发手册

前言

代码是一个程序猿的门面,有门面的程序猿才是一个好程序猿。html

本文节选自阿里巴巴开发手册,下载地址android

本手册以开发者为中心视角分为Java语言规范(遵循《阿里巴巴Java开发手册》), Android 资源文件命名与使用,Android 基本组件,UI 与布局,进程、线程与消息通讯, 文件与数据库,Bitmap、Drawable 与动画,安全,其余等九大部分,根据约束力强弱, 规约依次分为强制、推荐、参考三大类:git

\color{red}{【强制】}必须遵照,违反本约定或将会引发严重的后果;github

\color{green}{【推荐】}尽可能遵照,长期遵照有助于系统稳定性和合做效率的提高;web

\color{royalblue}{【参考】}充分理解,技术意识的引导,是我的学习、团队沟通、项目合做的方向。算法

对于规约条目的延伸信息中,“说明”对内容作了适当扩展和解释;“正例”提倡 什么样的编码和实现方式;“反例”说明须要提防的雷区,以及错误案例。数据库

1、Java 语言规范

遵循《阿里巴巴 Java 开发手册》手册,下载地址canvas

2、Android 资源文件命名与使用

  1. \color{green}{【推荐】}资源文件需带模块前缀。数组

  2. \color{green}{【推荐】}layout 文件的命名方式。 Activity 的 layout 以 module_activity 开头 Fragment 的 layout 以 module_fragment 开头 Dialog 的 layout 以 module_dialog 开头 include 的 layout 以 module_include 开头 ListView 的行 layout 以 module_list_item 开头 RecyclerView 的 item layout 以 module_recycle_item 开头 GridView 的行 layout 以 module_grid_item 开头浏览器

  3. \color{green}{【推荐】} drawable 资源名称以小写单词+下划线的方式命名,根据分辨率不一样存放在不一样的 drawable 目录下,建议只使用一套,例如 drawable-xhdpi。采用规则以下:模块名_业务功能描述_控件描述_控件状态限定词 如:module_login_btn_pressed,module_tabs_icon_home_normal

  4. \color{green}{【推荐】}anim 资源名称以小写单词+下划线的方式命名,采用如下规则:模块名_逻辑名称_[方向|序号]tween 动画资源 : 尽量以通用的动画名称命名,如 module_fade_in ,module_fade_out , module_push_down_in (动画+方向);frame 动画资源:尽量以模 块+功能命名+序号。如:module_loading_grey_001

  5. \color{green}{【推荐】} color 资源使用#AARRGGBB 格式,写入modul_colors.xml 文件中,命名格式采用如下规则:模块名_逻辑名称_颜色。 如:<color name="module_btn_bg_color">#33b5e5e5</color>

  6. \color{green}{【推荐】}dimen 资源以小写单词+下划线方式命名,写入 module_dimens.xml 文件中,采用如下规则:模块名_描述信息。如:<dimen name="module_horizontal_line_height">1dp</dimen>

  7. \color{green}{【推荐】}style 资源采用小写单词+下划线方式命名,写入 module_styles.xml 文件中,采用如下规则:父 style 名称.当前 style 名称。 如: <style name="ParentTheme.ThisActivityTheme"> …</style>

  8. \color{green}{【推荐】}string资源文件或者文本用到字符须要所有写入module_strings.xml文件中,字符串以小写单词+下划线的方式命名,采用如下规则:模块名_逻辑名称 如:moudule_login_tips,module_homepage_notice_desc

  9. \color{green}{【推荐】}Id 资源原则上以驼峰法命名,View 组件的资源 id 须要以 View 的缩写做为前缀。经常使用缩写表以下

    image.png
    其它控件的缩写推荐使用小写字母并用下划线进行分割,例如: ProgressBar 对应的缩写为 progress_bar DatePicker 对应的缩写为 date_picker

10.\color{green}{【推荐】}大分辨率图片(单维度超过 1000)大分辨率图片建议统一放在 xxhdpi 目录下管理,不然将致使占用内存成倍数增长。 说明: 为了支持多种屏幕尺寸和密度,Android 为多种屏幕提供不一样的资源目录进行适配。 为不一样屏幕密度提供不一样的位图可绘制对象,可用于密度特定资源的配置限定符(在 下面详述) 包括 ldpi(低)、mdpi(中)、 hdpi(高)、xhdpi(超高)、xxhdpi (超 超高)和 xxxhdpi(超超超高)。例如,高密度屏幕的位图应使用 drawable-hdpi/。 根据当前的设备屏幕尺寸和密度,将会寻找最匹配的资源,若是将高分辨率图片放 入低密度目录,将会形成低端机加载过大图片资源,又可能形成 OOM,同时也是资 源浪费,没有必要在低端机使用大图。 正例: 将 144 * 144 的应用图标 PNG 文件放在 drawable-xxhdpi 目录 反例: 将 144 * 144 的应用图标 PNG 文件放在 drawable-mhdpi 目录

3、Android 基本组件

Android 基本组件指 Activity、Fragment、Service、BroadcastReceiver、 ContentProvider 等等。

  1. \color{red}{【强制】}Activity 间的数据通讯,对于数据量比较大的,避免使用 Intent + Parcelable 的方式,能够考虑 EventBus 等替代方案,以避免形成 TransactionTooLargeException。

  2. \color{green}{【推荐】}Activity#onSaveInstanceState()方法不是 Activity 生命周期方法,也不保证 必定会被调用。它是用来在 Activity 被意外销毁时保存 UI 状态的,只能用于保存临 时性数据,例如 UI 控件的属性等,不能跟数据的持久化存储混为一谈。持久化存储 应该在 Activity#onPause()/onStop()中实行。

  3. \color{red}{【强制】}Activity 间经过隐式 Intent 的跳转,在发出 Intent 以前必须经过 resolveActivity 检查,避免找不到合适的调用组件,形成 ActivityNotFoundException 的异常。

  4. \color{red}{【强制】}避免在 Service#onStartCommand()/onBind()方法中执行耗时操做,若是确 实有需求,应改用 IntentService 或采用其余异步机制完成。

  5. \color{red}{【强制】}避免在 BroadcastReceiver#onReceive()中执行耗时操做,若是有耗时工做, 应该建立 IntentService 完成,而不该该在 BroadcastReceiver 内建立子线程去作。 说明: 因为该方法是在主线程执行,若是执行耗时操做会致使 UI 不流畅。可使用 IntentService 、 创 建 HandlerThread 或者调用 Context#registerReceiver (BroadcastReceiver, IntentFilter, String, Handler)方法等方式,在其余 Wroker 线程 执行 onReceive 方法。BroadcastReceiver#onReceive()方法耗时超过 10 秒钟,可 能会被系统杀死。

  6. \color{red}{【强制】}避免使用隐式 Intent 广播敏感信息,信息可能被其余注册了对应 BroadcastReceiver 的 App 接收。 说明: 经过 Context#sendBroadcast()发送的隐式广播会被全部感兴趣的 receiver 接收,恶 意应用注册监听该广播的 receiver 可能会获取到 Intent 中传递的敏感信息,并进行 其余危险操做。若是发送的广播为使用 Context#sendOrderedBroadcast()方法发送 的有序广播,优先级较高的恶意 receiver 可能直接丢弃该广播,形成服务不可用, 或者向广播结果塞入恶意数据。 若是广播仅限于应用内,则可使用 LocalBroadcastManager#sendBroadcast()实 现,避免敏感信息外泄和 Intent 拦截的风险。 以上广播可能被其余应用的以下 receiver 接收致使敏感信息泄漏

  7. \color{green}{【推荐】} 添 加 Fragment 时 , 确 保 FragmentTransaction#commit() 在 Activity#onPostResume()或者 FragmentActivity#onResumeFragments()内调用。 不要随意使用 FragmentTransaction#commitAllowingStateLoss()来代替,任何 commitAllowingStateLoss()的使用必须通过 code review,确保无负面影响。 说明: Activity 可 能 因 为 各 种 原 因 被 销 毁 , Android 支 持 页 面 被 销 毁 前 通 过 Activity#onSaveInstanceState() 保 存 自 己 的 状 态 。 但 如 果 FragmentTransaction.commit()发生在 Activity 状态保存以后,就会致使 Activity 重 建、恢复状态时没法还原页面状态,从而可能出错。为了不给用户形成很差的体 验,系统会抛出 IllegalStateExceptionStateLoss 异常。推荐的作法是在 Activity 的 onPostResume() 或 onResumeFragments() ( 对 FragmentActivity )里执行 FragmentTransaction.commit(),若有必要也可在 onCreate()里执行。不要随意改用 FragmentTransaction.commitAllowingStateLoss() 或 者 直 接 使 用 try-catch 避 免 crash,这不是问题的根本解决之道,当且仅当你确认 Activity 重建、恢复状态时, 本次 commit 丢失不会形成影响时才可这么作。

  8. \color{green}{【推荐】}不要在 Activity#onDestroy()内执行释放资源的工做,例如一些工做线程的 销毁和中止,由于 onDestroy()执行的时机可能较晚。可根据实际须要,在 Activity#onPause()/onStop()中结合 isFinishing()的判断来执行。

  9. \color{green}{【推荐】}如非必须,避免使用嵌套的 Fragment。 说明: 嵌套 Fragment 是在 Android API 17 添加到 SDK 以及 Support 库中的功能, Fragment 嵌套使用会有一些坑,容易出现 bug,比较常见的问题有以下几种:

  • onActivityResult()方法的处理错乱,内嵌的 Fragment 可能收不到该方法的回调,须要由宿主 Fragment 进行转发处理;
  • 突变更画效果;
  • 被继承的 setRetainInstance(),致使在 Fragment 重建时屡次触发没必要要的逻 辑。 非必须的场景尽量避免使用嵌套 Fragment,如需使用请注意上述问题。

10.\color{green}{【推荐】}老是使用显式 Intent 启动或者绑定 Service,且不要为服务声明 Intent Filter, 保证应用的安全性。若是确实须要使用隐式调用,则可为 Service 提供 Intent Filter 并从 Intent 中排除相应的组件名称,但必须搭配使用 Intent#setPackage()方法设置 Intent 的指定包名,这样能够充分消除目标服务的不肯定性。

11.\color{green}{【推荐】}Service 须要以多线程来并发处理多个启动请求,建议使用 IntentService, 可避免各类复杂的设置。 说明: Service 组件通常运行主线程,应当避免耗时操做,若是有耗时操做应该在 Worker 线程执行。 可使用 IntentService 执行后台任务。

12.\color{green}{【推荐】}对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册 和发送,LocalBroadcastManager 安全性更好,同时拥有更高的运行效率。 说明: 对于使用 Context#sendBroadcast()等方法发送全局广播的代码进行提示。若是该广 播仅用于应用内,则可使用 LocalBroadcastManager 来避免广播泄漏以及广播被 拦截等安全问题,同时相对全局广播本地广播的更高效。

13.\color{green}{【推荐】}当前Activity的onPause方法执行结束后才会执行下一个Activity的onCreate方法,因此在 onPause 方法中不适合作耗时较长的工做,这会影响到页面之间的跳 转效率。

14.\color{red}{【强制】}不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享 请使用 Intent 等机制,也可以使用 SharedPreferences 等数据持久化机制。

15.\color{green}{【推荐】}使用 Toast 时,建议定义一个全局的 Toast 对象,这样能够避免连续显示 Toast 时不能取消上一次 Toast 消息的状况(若是你有连续弹出 Toast 的状况,避免 使用 Toast.makeText)。

16.\color{red}{【强制】}使用 Adapter 的时候,若是你使用了 ViewHolder 作缓存,在 getView()的 方法中不管这项 convertView 的每一个子控件是否须要设置属性(好比某个 TextView 设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需 要为其显式设置属性(Textview 的文本为空也须要设置 setText(""),背景透明也须要 设置),不然在滑动的过程当中,由于 adapter item 复用的缘由,会出现内容的显示错 乱。

17.\color{red}{【强制】}Activity或者 Fragment 中动态注册BroadCastReceiver 时,registerReceiver() 和 unregisterReceiver()要成对出现。 说明: 若是 registerReceiver()和 unregisterReceiver()不成对出现,则可能致使已经注册的 receiver 没有在合适的时机注销,致使内存泄漏,占用内存空间,加剧 SystemService 负担。 部分华为的机型会对 receiver 进行资源管控,单个应用注册过多 receiver 会触发管 控模块抛出异常,应用直接崩溃。 Activity 的生命周期不对应,可能出现屡次 onResume 形成 receiver 注册多个,但 最终只注销一个,其他 receiver 产生内存泄漏。

4、UI 与布局

  1. \color{red}{【强制】}布局中不得不使用 ViewGroup 多重嵌套时,不要使用 LinearLayout 嵌套,改用 RelativeLayout,能够有效下降嵌套数。 说明: Android 应用页面上任何一个 View 都须要通过 measure、layout、draw 三个步骤 才能被正确的渲染。从 xml layout 的顶部节点开始进行 measure,每一个子节点都需 要向本身的父节点提供本身的尺寸来决定展现的位置,在此过程当中可能还会从新 measure(由此可能致使 measure 的时间消耗为原来的 2-3 倍)。节点所处位置越 深,套嵌带来的 measure 越多,计算就会越费时。这就是为何扁平的 View 结构 会性能更好。 同时,页面拥上的 View 越多,measure、layout、draw 所花费的时间就越久。要缩 短这个时间,关键是保持 View 的树形结构尽可能扁平,并且要移除全部不须要渲染的 View。理想状况下,总共的 measure,layout,draw 时间应该被很好的控制在 16ms 之内,以保证滑动屏幕时 UI 的流畅。 要找到那些多余的 View(增长渲染延迟的 view),能够用 Android Studio Monitor 里的 Hierarachy Viewer 工具,可视化的查看全部的 view。 多重嵌套致使 measure 以及 layout 等步骤耗时过多。

  2. \color{green}{【推荐】}在 Activity 中显示对话框或弹出浮层时,尽可能使用 DialogFragment,而非 Dialog/AlertDialog,这样便于随Activity生命周期管理对话框/弹出浮层的生命周期。

  3. \color{green}{【推荐】}源文件统一采用 UTF-8 的形式进行编码。

  4. \color{red}{【强制】}禁止在非 ui 线程进行 view 相关操做。

  5. \color{green}{【推荐】}文本大小使用单位 dp,view 大小使用单位 dp。对于 Textview,若是在文字大小肯定的状况下推荐使用 wrap_content 布局避免出现文字显示不全的适配问 题。

  6. \color{red}{【强制】}禁止在设计布局时屡次设置子 view 和父 view 中为一样的背景形成页面过分绘制,推荐将不须要显示的布局进行及时隐藏。

  7. \color{green}{【推荐】}灵活使用布局,推荐 Merge、ViewStub 来优化布局,尽量多的减小 UI布局层级,推荐使用 FrameLayout,LinearLayout、RelativeLayout 次之。

  8. \color{green}{【推荐】}在须要时刻刷新某一区域的组件时,建议经过如下方式避免引起全局 layout 刷新:

  • 设置固定的 view 大小的高宽,如倒计时组件等;
  • 调用 view 的 layout 方式修改位置,如弹幕组件等;
  • 经过修改 canvas 位置而且调用 invalidate(int l, int t, int r, int b)等方式限定刷新 区域;
  • 经过设置一个是否容许 requestLayout 的变量,而后重写控件的 requestlayout、 onSizeChanged 方 法 , 判 断 控 件 的 大 小 没 有 改 变 的 情 况 下 , 当 进 入 requestLayout 的时候,直接返回而不调用 super 的 requestLayout 方法。
  1. \color{green}{【推荐】}不能在 Activity 没有彻底显示时显示 PopupWindow 和 Dialog。

10.\color{green}{【推荐】}尽可能不要使用 AnimationDrawable,它在初始化的时候就将全部图片加载到内存中,特别占内存,而且还不能释放,释放以后下次进入再次加载时会报错。 说明: Android 的帧动画可使用 AnimationDrawable 实现,可是若是你的帧动画中若是 包含过多帧图片,一次性加载全部帧图片所致使的内存消耗会使低端机发生 OOM 异常。帧动画所使用的图片要注意下降内存消耗,当图片比较大时,容易出现 OOM。

11.\color{red}{【强制】}不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;由于这样会把 ListView 的全部 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制图面。 说明: ScrollView 中嵌套 List 或 RecyclerView 的作法官方明确禁止。除了开发过程当中遇到 的各类视觉和交互问题,这种作法对性能也有较大损耗。ListView 等 UI 组件自身有 垂直滚动功能,也没有必要在嵌套一层 ScrollView。目前为了较好的 UI 体验,更贴 近 Material Design 的设计,推荐使用 NestedScrollView。

5、进程、线程与消息通讯

  1. \color{red}{【强制】}不要经过 Intent 在 Android 基础组件之间传递大数据(binder transaction缓存为 1MB),可能致使 OOM。

  2. \color{red}{【强制】}在 Application 的业务初始化代码加入进程判断,确保只在本身须要的进程初始化。特别是后台进程减小没必要要的业务初始化。

  3. \color{red}{【强制】}新建线程时,必须经过线程池提供(AsyncTask 或者 ThreadPoolExecutor 或者其余形式自定义的线程池),不容许在应用中自行显式建立线程。 说明: 使用线程池的好处是减小在建立和销毁线程上所花的时间以及系统资源的开销,解 决资源不足的问题。若是不使用线程池,有可能形成系统建立大量同类线程而致使 消耗完内存或者“过分切换”的问题。另外建立匿名线程不便于后续的资源使用分析, 对性能分析等会形成困扰。

  4. \color{red}{【强制】}线程池不容许使用 Executors 去建立,而是经过 ThreadPoolExecutor 的方式,这样的处理方式让写的同窗更加明确线程池的运行规则,规避资源耗尽的风险。 说明: Executors 返回的线程池对象的弊端以下:

  • FixedThreadPool 和 SingleThreadPool : 允 许 的 请 求 队 列 长 度 为 Integer.MAX_VALUE,可能会堆积大量的请求,从而致使 OOM;
  • CachedThreadPool 和 ScheduledThreadPool : 允 许 的 创 建 线 程 数 量 为 Integer.MAX_VALUE,可能会建立大量的线程,从而致使 OOM。
  1. \color{red}{【强制】}子线程中不能更新界面,更新界面必须在主线程中进行,网络操做不能在主线程中调用。

  2. \color{red}{【强制】}不要在非 UI 线程中初始化 ViewStub,不然会返回 null。

  3. \color{green}{【推荐】}尽可能减小不一样 APP 之间的进程间通讯及拉起行为。拉起致使占用系统资源,影响用户体验。

  4. \color{green}{【推荐】}新建线程时,定义能识别本身业务的线程名称,便于性能优化和问题排查。

  5. \color{green}{【推荐】}ThreadPoolExecutor 设置线程存活时间(setKeepAliveTime),确保空闲时线程能被释放。

  6. 【 推 荐 】 禁 止 在 多 进 程 之 间 用 SharedPreferences 共 享 数 据 , 虽 然 可 以 (MODE_MULTI_PROCESS),但官方已不推荐。

11.\color{green}{【推荐】}谨慎使用 Android 的多进程,多进程虽然可以下降主进程的内存压力,但会遇到以下问题:

  • 不能实现彻底退出全部 Activity 的功能;
  • 首次进入新启动进程的页面时会有延时的现象(有可能黑屏、白屏几秒,是白 屏仍是黑屏和新 Activity 的主题有关);
  • 应用内多进程时,Application 实例化屡次,须要考虑各个模块是否都须要在所 有进程中初始化;
  • 多进程间经过 SharedPreferences 共享数据时不稳定。

6、文件与数据库

  1. \color{red}{【强制】}任什么时候候不要硬编码文件路径,请使用 Android 文件系统 API 访问。 说明: Android 应用提供内部和外部存储,分别用于存放应用自身数据以及应用产生的用 户数据。能够经过相关 API 接口获取对应的目录,进行文件操做。

  2. \color{red}{【强制】}当使用外部存储时,必须检查外部存储的可用性。

  3. \color{red}{【强制】}应用间共享文件时,不要经过放宽文件系统权限的方式去实现,而应使用FileProvider。

  4. \color{green}{【推荐】}SharedPreference 中只能存储简单数据类型(int、boolean、String 等),复杂数据类型建议使用文件、数据库等其余方式存储。

  5. \color{green}{【 推 荐 】} SharedPreference 提 交 数 据 时 , 尽 量 使 用 Editor#apply() ,而非 Editor#commit()。通常来说,仅当须要肯定提交结果,并据此有后续操做时,才使 用 Editor#commit()。 说明: SharedPreference 相关修改使用 apply 方法进行提交会先写入内存,而后异步写入 磁盘,commit 方法是直接写入磁盘。若是频繁操做的话 apply 的性能会优于 commit, apply 会将最后修改内容写入磁盘。可是若是但愿马上获取存储操做的结果,并据此 作相应的其余操做,应当使用 commit。

  6. \color{red}{【强制】}数据库 Cursor 必须确保使用完后关闭,以避免内存泄漏。 说明: Cursor 是对数据库查询结果集管理的一个类,当查询的结果集较小时,消耗内存不 易察觉。可是当结果集较大,长时间重复操做会致使内存消耗过大,须要开发者在 操做完成后手动关闭 Cursor。 数据库 Cursor 在建立及使用时,可能发生各类异常,不管程序是否正常结束,必须 在最后确保 Cursor 正确关闭,以免内存泄漏。同时,若是 Cursor 的使用还牵涉 多线程场景,那么须要自行保证操做同步。

  7. \color{red}{【强制】}多线程操做写入数据库时,须要使用事务,以避免出现同步问题。 说明: Android 的经过 SQLiteOpenHelper 获取数据库 SQLiteDatabase 实例,Helper 中会 自动缓存已经打开的 SQLiteDatabase 实例,单个 App 中应使用 SQLiteOpenHelper 的单例模式确保数据库链接惟一。因为 SQLite 自身是数据库级锁,单个数据库操做 是保证线程安全的(不能同时写入),transaction 时一次原子操做,所以处于事务中 的操做是线程安全的。 若同时打开多个数据库链接,并经过多线程写入数据库,会致使数据库异常,提示 数据库已被锁住。

  8. \color{green}{【推荐】}大数据写入数据库时,请使用事务或其余可以提升 I/O 效率的机制,保证执行速度。

  9. \color{red}{【强制】}执行 SQL 语句时,应使用 SQLiteDatabase#insert()、update()、delete(),不要使用 SQLiteDatabase#execSQL(),以避免 SQL 注入风险。

10.\color{red}{【强制】}若是 ContentProvider 管理的数据存储在 SQL 数据库中,应该避免将不受信任的外部数据直接拼接在原始 SQL 语句中,可以使用一个用于将 ? 做为可替换参 数的选择子句以及一个单独的选择参数数组,会避免 SQL 注入。

7、Bitmap、Drawable 与动画

  1. \color{red}{【强制】}加载大图片或者一次性加载多张图片,应该在异步线程中进行。图片的加载,涉及到 IO 操做,以及 CPU 密集操做,极可能引发卡顿。

  2. \color{red}{【强制】}在 ListView,ViewPager,RecyclerView,GirdView 等组件中使用图片时,应作好图片的缓存,避免始终持有图片致使内存泄露,也避免重复建立图片,引发 性 能 问 题 。 建 议 使 用 Fresco Glide等图片库。

  3. \color{red}{【强制】}png 图片使用 tinypng 或者相似工具压缩处理,减小包体积。

  4. \color{green}{【推荐】}应根据实际展现须要,压缩图片,而不是直接显示原图。手机屏幕比较小,直接显示原图,并不会增长视觉上的收益,可是却会耗费大量宝贵的内存。

  5. \color{red}{【强制】}使用完毕的图片,应该及时回收,释放宝贵的内存。

  6. \color{green}{【推荐】}针对不一样的屏幕密度,提供对应的图片资源,使内存占用和显示效果达到合理的平衡。若是为了节省包体积,能够在不影响 UI 效果的前提下,省略低密度图片。

  7. \color{red}{【强制】}在 Activity.onPause()或 Activity.onStop()回调中,关闭当前 activity 正在执行的的动画。

  8. \color{green}{【推荐】}在动画或者其余异步任务结束时,应该考虑回调时刻的环境是否还支持业务处理。例如 Activity 的 onStop()函数已经执行,且在该函数中主动释放了资源,此时回调中若是不作判断就会空指针崩溃。

  9. \color{green}{【推荐】}使用 inBitmap 重复利用内存空间,避免重复开辟新内存。

10.\color{green}{【推荐】}使用 ARGB_565 代替 ARGB_888,在不怎么下降视觉效果的前提下,减小内存占用。 说明: android.graphics.Bitmap.Config 类中关于图片颜色的存储方式定义:

  • ALPHA_8 表明 8 位 Alpha 位图;
  • ARGB_4444 表明 16 位 ARGB 位图;
  • ARGB_8888 表明 32 位 ARGB 位图;
  • RGB_565 表明 16 位 RGB 位图。 位图位数越高,存储的颜色信息越多,图像也就越逼真。大多数场景使用的是 ARGB_8888 和 RGB_565,RGB_565 可以在保证图片质量的状况下大大减小内存 的开销,是解决 oom 的一种方法。 可是必定要注意 RGB_565 是没有透明度的,若是图片自己须要保留透明度,那么 就不能使用 RGB_565。

11.\color{green}{【推荐】} 尽可能减小 Bitmap(BitmapDrawable)的使用,尽可能使用纯色(ColorDrawable)、 渐变色(GradientDrawable)、StateSelector(StateListDrawable)等与 Shape 结 合的形式构建绘图。

12.\color{green}{【推荐】}谨慎使用 gif 图片,注意限制每一个页面容许同时播放的 gif 图片,以及单个gif 图片的大小。

13.\color{royalblue}{【参考】}大图片资源不要直接打包到 apk,能够考虑经过文件仓库远程下载,减少包体积。

14.\color{green}{【推荐】}根据设备性能,选择性开启复杂动画,以实现一个总体较优的性能和体验;

15.\color{green}{【推荐】}在有强依赖 onAnimationEnd 回调的交互时,如动画播放完毕才能操做页面 , onAnimationEnd 可 能 会 因 各 种 异 常 没 被 回 调 , 建 议 加 上 超 时 保 护 或 通 过 postDelay 替 代 onAnimationEnd。

16.\color{green}{【推荐】}当 View Animation 执行结束时,调用 View.clearAnimation()释放相关资源。

8、安全

  1. \color{red}{【强制】}使用 PendingIntent 时,禁止使用空 intent,同时禁止使用隐式 Intent 说明:
  • 使用 PendingIntent 时,使用了空 Intent,会致使恶意用户劫持修改 Intent 的内 容。禁止使用一个空 Intent 去构造 PendingIntent,构造 PendingIntent 的 Intent 必定要设置 ComponentName 或者 action。
  • PendingIntent 可让其余 APP 中的代码像是运行本身 APP 中。PendingIntent 的intent接收方在使用该intent时与发送方有相同的权限。在使用PendingIntent 时,PendingIntent 中包装的 intent 若是是隐式的 Intent,容易遭到劫持,致使 信息泄露。
  1. \color{red}{【强制】}禁止使用常量初始化矢量参数构建 IvParameterSpec,建议 IV 经过随机方式产生。 说明: 使用固定初始化向量,结果密码文本可预测性会高得多,容易受到字典式攻击。iv 的做用主要是用于产生密文的第一个 block,以使最终生成的密文产生差别(明文相 同的状况下),使密码攻击变得更为困难,除此以外 iv 并没有其它用途。所以 iv 经过 随机方式产生是一种十分简便、有效的途径。

  2. \color{red}{【强制】}将 android:allowbackup 属性设置为 false,防止 adb backup 导出数据。 说明: 在 AndroidManifest.xml 文件中为了方便对程序数据的备份和恢复在 Android API level 8 之后增长了 android:allowBackup 属性值。默认状况下这个属性值为 true,故 当 allowBackup 标志值为 true 时,便可经过 adb backup 和 adb restore 来备份和恢 复应用程序数据。

  3. \color{red}{【强制】}在实现的 HostnameVerifier 子类中,须要使用 verify 函数效验服务器主机名的合法性,不然会致使恶意程序利用中间人攻击绕过主机名效验。 说明: 在握手期间,若是 URL 的主机名和服务器的标识主机名不匹配,则验证机制能够 回调此接口的实现程序来肯定是否应该容许此链接。若是回调内实现不恰当,默认 接受全部域名,则有安全风险。

  4. \color{red}{【强制】}利用 X509TrustManager 子类中的 checkServerTrusted 函数效验服务器端证书的合法性。 说明: 在实现的 X509TrustManager 子类中未对服务端的证书作检验,这样会致使不被信 任的证书绕过证书效验机制。

  5. \color{red}{【强制】}META-INF 目录中不能包含如.apk,.odex,.so 等敏感文件,该文件夹没有通过签名,容易被恶意替换。

  6. \color{red}{【强制】}Receiver/Provider 不能在毫无权限控制的状况下,将 android:export 设置为 true。

  7. \color{royalblue}{【参考】}数据存储在 Sqlite 或者轻量级存储须要对数据进行加密,取出来的时候进行解密。

  8. \color{red}{【强制】}阻止 webview 经过 file:schema 方式访问本地敏感数据。

10.\color{red}{【强制】}不要广播敏感信息,只能在本应用使用 LocalBroadcast,避免被别的应用收到,或者 setPackage 作限制。

11.\color{red}{【强制】}不要把敏感信息打印到 log 中。 说明: 在 APP 的开发过程当中,为了方便调试,一般会使用 log 函数输出一些关键流程的信 息,这些信息中一般会包含敏感内容,如执行流程、明文的用户名密码等,这会让 攻击者更加容易的了解 APP 内部结构方便破解和攻击,甚至直接获取到有价值的敏 感信息。

12.\color{red}{【强制】}对于内部使用的组件,显示设置组件的"android:exported"属性为 false。 说明: Android 应用使用 Intent 机制在组件之间传递数据,若是应用在使用 getIntent(), getAction(),Intent.getXXXExtra()获取到空数据、异常或者畸形数据时没有进行异 常捕获,应用就会发生 Crash,应用不可以使用(本地拒绝服务)。恶意应用可经过向 受害者应用发送此类空数据、异常或者畸形数据从而使应用产生本地拒绝服务。

13.\color{red}{【强制】}应用发布前确保 android:debuggable 属性设置为 false。

14.\color{red}{【强制】}使用 Intent Scheme URL 须要作过滤。 说明: 若是浏览器支持 Intent Scheme Uri 语法,若是过滤不当,那么恶意用户可能经过浏 览器 js 代码进行一些恶意行为,好比盗取 cookie 等。若是使用了 Intent.parseUri 函 数 , 获 取 的 intent 必 须 严格过滤, intent 至少包含 addCategory(“android.intent.category.BROWSABLE”) , setComponent(null) , setSelector(null)3 个策略。

15.\color{red}{【强制】}密钥加密存储或者通过变形处理后用于加解密运算,切勿硬编码到代码中。 说明: 应用程序在加解密时,使用硬编码在程序中的密钥,攻击者经过反编译拿到密钥可 以轻易解密 APP 通讯数据。

16.\color{red}{【强制】}将所须要动态加载的文件放置在 apk 内部,或应用私有目录中,若是应用必需要把所加载的文件放置在可被其余应用读写的目录中(好比 sdcard),建议对不可信的加载源进行完整性校验和白名单处理,以保证不被恶意代码注入。

17.\color{red}{【强制】}除非 min API level >=17,请注意 addJavascriptInterface 的使用。 说明: API level>=17,容许 js 被调用的函数必须以@JavascriptInterface 进行注解,所以 不受影响; 对于 API level < 17,尽可能不要使用 addJavascriptInterface,若是必定 要用,那么:

  • 使用 https 协议加载 URL,使用证书校验,防止访问的页面被篡改挂马;
  • 对加载 URL 作白名单过滤、完整性校验等防止访问的页面被篡改;
  • 若是加载本地 html,应该会 HTML 内置在 APK 中,以及对 HTML 页面进行完整 性校验。

18.\color{red}{【强制】}使用 Android 的 AES/DES/DESede 加密算法时,不要使用默认的加密模式ECB,应显示指定使用 CBC 或 CFB 加密模式。 说明: 加密模式 ECB、CBC、CFB、OFB 等,其中 ECB 的安全性较弱,会使相同的铭文 在不一样的时候产生相同的密文,容易遇到字典攻击,建议使用 CBC 或 CFB 模式。

  • ECB:Electronic codebook,电子密码本模式
  • CBC:Cipher-block chaining,密码分组连接模式
  • CFB:Cipher feedback,密文反馈模式
  • OFB:Output feedback,输出反馈模式

19.\color{red}{【强制】}不要使用 loopback 来通讯敏感信息。

20.\color{green}{【推荐】}对于不须要使用 File 协议的应用,禁用 File 协议,显式设置 webView.getSettings().setAllowFileAccess(false),对于须要使用 File 协议的应用,禁止 File 协议调用 JavaScript,显式设置 webView.getSettings().setJavaScriptEnabled(false)。

21.\color{red}{【强制】}Android APP 在 HTTPS 通讯中,验证策略须要改为严格模式。说明:Android APP 在 HTTPS 通讯中,使用 ALLOW_ALL_HOSTNAME_VERIFIER,表示容许和 全部的 HOST 创建 SSL 通讯,这会存在中间人攻击的风险,最终致使敏感信息可能会被劫持,以及其余形式的攻击。

22.\color{green}{【推荐】}Android5.0 之后安全性要求 较高的应用 应该使 用 window.setFlag (LayoutParam.FLAG_SECURE) 禁止录屏。

23.\color{green}{【推荐】}zip 中不建议容许../../file 这样的路径,可能被篡改目录结构,形成攻击。 说明:当 zip 压缩包中容许存在"../"的字符串,攻击者能够利用多个"../"在解压时改变 zip 文件存放的位置,当文件已经存在是就会进行覆盖,若是覆盖掉的文件是 so、dex 或者 odex 文件,就有可能形成严重的安全问题。

24.\color{red}{【强制】}开放的 activity/service/receiver 等须要对传入的 intent 作合法性校验。

25.\color{green}{【推荐】}加密算法:使用不安全的 Hash 算法(MD5/SHA-1)加密信息,存在被破解的风险,建议使用 SHA-256 等安全性更高的 Hash 算法。

26.\color{green}{【推荐】}Android WebView 组件加载网页发生证书认证错误时,采用默认的处理方法handler.cancel(),中止加载问题页面。 说明: Android WebView 组件加载网页发生证书认证错误时,会调用 WebViewClient 类的 onReceivedSslError 方法,若是该方法实现调用了 handler.proceed()来忽略该证书 错误,则会受到中间人攻击的威胁,可能致使隐私泄露。

27.\color{green}{【推荐】}直接传递命令字或者间接处理有敏感信息或操做时,避免使用 socket 实现,使用可以控制权限校验身份的方式通信。

9、其余

  1. \color{red}{【强制】}不要经过 Msg 传递大的对象,会致使内存问题。

  2. \color{red}{【强制】}不能使用 System.out.println 打印 log。

  3. \color{red}{【强制】}Log 的 tag 不能是" "。 说明: 日志的 tag 是空字符串没有任何意义,也不利于过滤日志。