《阿里巴巴Android开发手册》是阿里巴巴集团各大Android开发团队的集体智慧结晶和经验总结,将淘宝、天猫、闲鱼、钉钉等App长期开发迭代和优化经验系统地整理成册,以指导Android开发者更加高效、高质量地进行App开发,呈现给用户体验好、性能优、稳定性佳、安全性高的产品。
《阿里巴巴Android开发手册》作为阿里巴巴开发规约重要的一环,我们的目标是:
防患未然,提升质量意识,降低故障率和维护成本;
标准统一,提升协作效率;
追求卓越的工匠精神,打磨精品代码。
本手册以开发者为中心视角分为Java语言规范(遵循《阿里巴巴Java开发手册》),Android资源文件命名与使用,Android基本组件,UI与布局,进程、线程与消息通信,文件与数据库,Bitmap、Drawable与动画,安全,其他等九大部分,根据约束力强弱,规约依次分为强制、推荐、参考三大类:
【强制】必须遵守,违反本约定或将会引起严重的后果;
【推荐】尽量遵守,长期遵守有助于系统稳定性和合作效率的提升;
【参考】充分理解,技术意识的引导,是个人学习、团队沟通、项目合作的方向。
对于规约条目的延伸信息中,“说明”对内容做了适当扩展和解释;“正例”提倡什么样的编码和实现方式;“反例”说明需要提防的雷区,以及错误案例。
一、Java语言规范遵循《阿里巴巴Java开发手册》
私信回复手册获取
二、Android资源文件命名与使用
1.【推荐】资源文件需带模块前缀。
2.【推荐】layout文件的命名方式。
3.【推荐】drawable资源名称以小写单词+下划线的方式命名,根据分辨率不同存放在不同的 drawable目录下,如果介意包大小建议只使用一套,系统去进行缩放。
4.【推荐】anim资源名称以小写单词+下划线的方式命名
5. 【推荐】color资源使用#AARRGGBB 格式,写入 module_colors.xml 文件中
6.【推荐】dimen 资源以小写单词+下划线方式命名,写入 module_dimens.xml 文件中, 采用以下规则:
模块名_描述信息 如:<dimen name="module_horizontal_line_height">1dp</dimen>
7. 【推荐】style 资源采用“父 style 名称.当前 style 名称”方式命名,写入 module_styles.xml 文件中,首字母大写。如:
8.【推荐】string 资源文件或者文本用到字符需要全部写入 module_strings.xml 文件中, 字符串以小写单词+下划线的方式命名,采用以下规则:
模块名_逻辑名称如:moudule_login_tips,module_homepage_notice_desc
9. 【推荐】Id 资源原则上以驼峰法命名,View 组件的资源 id 建议以 View 的缩写作为前缀,
其它控件的缩写推荐使用小写字母并用下划线进行分割,例如:ProgressBar 对应的缩写为 progress_bar;DatePicker 对应的缩写为 date_picker。
三、Android 基本组件
Android 基本组件指 Activity 、 Fragment 、 Service 、 BroadcastReceiver 、 ContentProvider 等等。
1.【强制】Activity 间的数据通信,对于数据量比较大的,避免使用 Intent + Parcelable的方式,可以考虑 EventBus 等替代方案,以免造成
TransactionTooLargeException。
2.【推荐】Activity#onSaveInstanceState()方法不是 Activity 生命周期方法,也不保证一定会被调用。它是用来在 Activity 被意外销毁时保存 UI 状态的,只能用于保存临时性数据,例如 UI 控件的属性等,不能跟数据的持久化存储混为一谈。持久化存储应该在 Activity#onPause()/onStop()中实行。3.【强制】Activity 间通过隐式 Intent 的跳转,在发出 Intent 之前必须通过 resolveActivity 检查,避免找不到合适的调用组件,造成 ActivityNotFoundException 的异常。
4.【强制】避免在 Service#onStartCommand()/onBind()方法中执行耗时操作,如果确实有需求,应改用 IntentService 或采用其他异步机制完成。
5.【强制】避免在 BroadcastReceiver#onReceive()中执行耗时操作,如果有耗时工作,应该创建 IntentService 完成,而不应该在 BroadcastReceiver 内创建子线程去做。
说明:由于该方法是在主线程执行,如果执行耗时操作会导致 UI 不流畅。可以使用 IntentService 、 创 建 HandlerThread 或 者 调 用 Context#registerReceiver (BroadcastReceiver, IntentFilter, String, Handler)方法等方式,在其他 Wroker 线程执行 onReceive 方法。BroadcastReceiver#onReceive()方法耗时超过 10 秒钟,可能会被系统杀死。
6.【强制】 避免使用隐式 Intent 广播敏感信息,信息可能被其他注册了对应BroadcastReceiver 的 App 接收。
说明:通过 Context#sendBroadcast()发送的隐式广播会被所有感兴趣的 receiver 接收,恶意应用注册监听该广播的 receiver 可能会获取到 Intent 中传递的敏感信息,并进行其他危险操作。如果发送的广播为使用 Context#sendOrderedBroadcast()方法发送的有序广播,优先级较高的恶意 receiver 可能直接丢弃该广播,造成服务不可用,或者向广播结果塞入恶意数据。如果广播仅限于应用内,则可以使用 LocalBroadcastManager#sendBroadcast()实现,避免敏感信息外泄和 Intent 拦截的风险。
7.【 推 荐 】 添 加 Fragment 时 , 确 保 FragmentTransaction#commit() 在Activity#onPostResume()或者 FragmentActivity#onResumeFragments()内调用。不要随意使用 FragmentTransaction#commitAllowingStateLoss() 来代替,任何commitAllowingStateLoss()的使用必须经过 code review,确保无负面影响。
说明:Activity 可 能 因 为 各 种 原 因 被 销 毁 , Android 支 持 页 面 被 销 毁 前 通 过 Activity#onSaveInstanceState() 保 存 自 己 的 状 态 。 但 如 果
FragmentTransaction.commit()发生在 Activity 状态保存之后,就会导致 Activity 重建、恢复状态时无法还原页面状态,从而可能出错。
8.【推荐】不要在 Activity#onDestroy()内执行释放资源的工作,例如一些工作线程的销毁和停止,因为 onDestroy() 执行的时机可能较晚 。 可根据实际需要,在Activity#onPause()/onStop()中结合 isFinishing()的判断来执行。
9.【推荐】如非必须,避免使用嵌套的 Fragment。
说明:嵌套 Fragment 是在 Android API 17 添加到 SDK 以及 Support 库中的功能,Fragment嵌套使用会有一些坑,容易出现 bug,
比较常见的问题有如下几种:
1)onActivityResult()方法的处理错乱,内嵌的 Fragment 可能收不到该方法的回调,需要由宿主 Fragment 进行转发处理;
2)突变动画效果;
3)被继承的 setRetainInstance(),导致在 Fragment 重建时多次触发不必要的逻辑。
非必须的场景尽可能避免使用嵌套 Fragment,如需使用请注意上述问题。
10【.推荐】总是使用显式 Intent 启动或者绑定 Service,且不要为服务声明 Intent Filter,保证应用的安全性。
如果确实需要使用隐式调用,则可为 Service 提供 Intent Filter 并从 Intent 中排除相应的组件名称,但必须搭配使用 Intent#setPackage()方法设置 Intent 的指定包名,这样可以充分消除目标服务的不确定性。
11.【推荐】Service 需要以多线程来并发处理多个启动请求,建议使用 IntentService,可避免各种复杂的设置。
说明:Service 组件一般运行主线程,应当避免耗时操作,如果有耗时操作应该在 Worker 线程执行。可以使用 IntentService 执行后台任务。
12.【推荐】对于只用于应用内的广播,优先使用 LocalBroadcastManager 来进行注册和发送,LocalBroadcastManager 安全性更好,同时拥有更高的运行效率。
说明:对于使用 Context#sendBroadcast()等方法发送全局广播的代码进行提示。如果该广播仅用于应用内,则可以使用 LocalBroadcastManager 来避免广播泄漏以及广播被拦截等安全问题,同时相对全局广播本地广播的更高效。
13.【推荐】当前 Activity 的 onPause 方法执行结束后才会创建(onCreate)或恢复(onRestart)别的 Activity,所以在 onPause 方法中不适合做耗时较长的工作,这会影响到页面之间的跳转效率。
14.【强制】Activity 或者 Fragment 中动态注册 BroadCastReceiver 时,registerReceiver()和unregisterReceiver()要成对出现。
说明:如果 registerReceiver()和 unregisterReceiver()不成对出现,则可能导致已经注册的receiver 没有在合适的时机注销,导致内存泄漏,占用内存空间,加重 SystemService 负担。
Activity 的生命周期不对应,可能出现多次 onResume 造成 receiver 注册多个,但最终只注销一个,其余 receiver 产生内存泄漏。
15.【强制】Android 基础组件如果使用隐式调用,应在 AndroidManifest.xml 中使用或在代码中使用 IntentFilter 增加过滤。
说明:
如果浏览器支持 Intent Scheme Uri 语法,如果过滤不当,那么恶意用户可能通过浏览器 js 代码进行一些恶意行为,比如盗取 cookie 等。如果使用了 Intent.parseUri 函数,获取的 intent 必须严格过滤。
四、UI 与布局
1.【强制】布局中不得不使用 ViewGroup 多重嵌套时,不要使用 LinearLayout 嵌套,改用 RelativeLayout,可以有效降低嵌套数.
2.【推荐】在 Activity 中显示对话框或弹出浮层时,尽量使用 DialogFragment,而非Dialog/AlertDialog,这样便于随 Activity 生命周期管理对话框/弹出浮层的生命周期。
3.【推荐】源文件统一采用 UTF-8 的形式进行编码。
4.【强制】禁止在非 UI 线程进行 View 相关操作。
5.【推荐】文本大小使用单位 dp,View 大小使用单位 dp。对于 TextView,如果在文字大小确定的情况下推荐使用 wrap_content 布局避免出现文字显示不全的适配问题。
说明:之所以文本大小也推荐使用 dp 而非 sp,因为 sp 是 Android 早期推荐使用的,但其实sp 不仅和 dp 一样受屏幕密度的影响,还受到系统设置里字体大小的影响,所以使用 dp 对于应用开发会更加保证 UI 的一致性和还原度。
6.【强制】禁止在设计布局时多次为子 View 和父 View 设置同样背景进而造成页面过度绘制,推荐将不需要显示的布局进行及时隐藏。
7.【推荐】灵活使用布局,推荐 merge、ViewStub 来优化布局,尽可能多的减少 UI布局层级,推荐使用 FrameLayout,LinearLayout、RelativeLayout 次之。
8.【推荐】在需要时刻刷新某一区域的组件时,建议通过以下方式避免引发全局 layout 刷新:
1)设置固定的 View 大小的宽高,如倒计时组件等;
2)调用 View 的 layout 方法修改位置,如弹幕组件等;
3)通过修改 Canvas 位置并且调用 invalidate(int l, int t, int r, int b)等方式限定刷新区域;
4)通过设置一个是否允许 requestLayout 的变量,然后重写控件的 requestlayout、 onSizeChanged 方法,判断控件的大小没有改变的情况下,当进入 requestLayout 的时候,直接返回而不调用 super 的 requestLayout 方法。
9.【推荐】不能在 Activity 没有完全显示时显示 PopupWindow 和 Dialog。
10.【推荐】尽量不要使用 AnimationDrawable,它在初始化的时候就将所有图片加载到内存中,特别占内存,并且还不能释放,释放之后下次进入再次加载时会 错。
11.【强制】不能使用 ScrollView 包裹
ListView/GridView/ExpandableListVIew;因为这样会把 ListView 的所有 Item 都加载到内存中,要消耗巨大的内存和 cpu 去绘制图面。
说明:
ScrollView 中嵌套 List 或 RecyclerView 的做法官方明确禁止。除了开发过程中遇到的各种视觉和交互问题,这种做法对性能也有较大损耗。
ListView 等 UI 组件自身有垂直滚动功能,也没有必要在嵌套一层 ScrollView。
目前为了较好的 UI 体验,更贴近Material Design 的设计,推荐使用 NestedScrollView。
12.【强制】不要在 Android 的 Application 对象中缓存数据。基础组件之间的数据共享请使用 Intent 等机制,也可使用 SharedPreferences 等数据持久化机制。
13.【推荐】使用 Toast 时,建议定义一个全局的 Toast 对象,这样可以避免连续显示 Toast 时不能取消上一次 Toast 消息的情况。即使需要连续弹出 Toast,也应避免直接调用 Toast#makeText。
14.【强制】使用 Adapter 的时候,如果你使用了 ViewHolder 做缓存,在 getView()的方法中无论这项 convertView 的每个子控件是否需要设置属性(比如某个 TextView 设置的文本可能为 null,某个按钮的背景色为透明,某控件的颜色为透明等),都需要为其显式设置属性(Textview 的文本为空也需要设置 setText(“”),背景透明也需要设置),否则在滑动的过程中,因为 adapter item 复用的原因,会出现内容的显示错乱。
五、进程、线程与消息通信
1.【强制】不要通过 Intent 在 Android 基础组件之间传递大数据(binder transaction缓存为 1MB),可能导致 OOM。
2.【强制】在 Application 的业务初始化代码加入进程判断,确保只在自己需要的进程初始化。特别是后台进程减少不必要的业务初始化。
3.【强制】新建线程时,必须通过线程池提供(AsyncTask 或者 ThreadPoolExecutor或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。
说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。另外创建匿名线程不便于后续的资源使用分析,对性能分析等会造成困扰。
4.【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
5.【强制】子线程中不能更新界面,更新界面必须在主线程中进行, 络操作不能在主线程中调用。
6.【推荐】尽量减少不同 APP 之间的进程间通信及拉起行为。拉起导致占用系统资源,影响用户体验。
7.【推荐】新建线程时,定义能识别自己业务的线程名称,便于性能优化和问题排查。
正例:public class MyThread extends Thread {public MyThread(){ super.setName("ThreadName"); …}}
8.【推荐】ThreadPoolExecutor 设置线程存活时间(setKeepAliveTime),确保空闲时线程能被释放。9.【推荐】 禁止在多进程之间用 SharedPreferences 共享数据,虽然可以(MODE_MULTI_PROCESS),但官方已不推荐。
10.【推荐】谨慎使用 Android 的多进程,多进程虽然能够降低主进程的内存压力,但会遇到如下问题:
1)首次进入新启动进程的页面时会有延时的现象(有可能黑屏、白屏几秒,是白屏还是黑屏和新 Activity 的主题有关);
2)应用内多进程时,Application 实例化多次,需要考虑各个模块是否都需要在所有进程中初始化。
六、文件与数据库
1.【强制】任何时候不要硬编码文件路径,请使用 Android 文件系统 API 访问。
说明:Android 应用提供内部和外部存储,分别用于存放应用自身数据以及应用产生的用户数据。可以通过相关 API 接口获取对应的目录,进行文件操作。
2.【强制】当使用外部存储时,必须检查外部存储的可用性。
3.【强制】应用间共享文件时,不要通过放宽文件系统权限的方式去实现,而应使用FileProvider。
4.【推荐】SharedPreference 中只能存储简单数据类型(int、Boolean、String 等),复杂数据类型建议使用文件、数据库等其他方式存储。
5.【推荐】 SharedPreference 提交数据时,尽量使用 Editor#apply() ,而非Editor#commit()。一般来讲,仅当需要确定提交结果,并据此有后续操作时,才使用 Editor#commit()。
6.【强制】数据库 Cursor 必须确保使用完后关闭,以免内存泄漏。
7.【强制】多线程操作写入数据库时,需要使用事务,以免出现同步问题。
8.【推荐】大数据写入数据库时,请使用事务或其他能够提高 I/O 效率的机制,保证执行速度。
9.【强制】执行 SQL 语句时,应使用 SQLiteDatabase#insert()、update()、delete(),不要使用 SQLiteDatabase#execSQL(),以免 SQL 注入风险。
10.【强制】如果 ContentProvider 管理的数据存储在 SQL 数据库中,应该避免将不受信任的外部数据直接拼接在原始 SQL 语句中。
七、Bitmap、Drawable 与动画
1.【强制】加载大图片或者一次性加载多张图片,应该在异步线程中进行。图片的加载,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡顿。
2.【强制】在 ListView,ViewPager,RecyclerView,GirdView 等组件中使用图片时,应做好图片的缓存,避免始终持有图片导致内存溢出,也避免重复创建图片,引起性 能 问 题 。 建 议 使 用 Fresco (
https://github.com/facebook/fresco )、 Glide(
https://github.com/bumptech/glide)等图片库。
3.【强制】png 图片使用 TinyPNG 或者类似工具压缩处理,减少包体积。
4.【推荐】应根据实际展示需要,压缩图片,而不是直接显示原图。手机屏幕比较小,直接显示原图,并不会增加视觉上的收益,但是却会耗费大量宝贵的内存。
5.【强制】使用完毕的图片,应该及时回收,释放宝贵的内存。
6.【强制】在 Activity#onPause()或 Activity#onStop()回调中,关闭当前 activity 正在执行的的动画。
7.【推荐】在动画或者其他异步任务结束时,应该考虑回调时刻的环境是否还支持业务处理。例如
8.【推荐】使用 inBitmap 重复利用内存空间,避免重复开辟新内存。
9.【推荐】使用 RGB_565 代替 RGB_888,在不怎么降低视觉效果的前提下,减少内存占用。说明:
android.graphics.Bitmap.Config 类中关于图片颜色的存储方式定义:
1)ALPHA_8 代表 8 位 Alpha 位图;
2)ARGB_4444 代表 16 位 ARGB 位图;
3)ARGB_8888 代表 32 位 ARGB 位图;
4)RGB_565 代表 8 位 RGB 位图。位图位数越高,存储的颜色信息越多,图像也就越逼真。
10【.推荐】尽量减少 Bitmap(BitmapDrawable)的使用,尽量使用纯色(ColorDrawable)、渐变色(GradientDrawable)、StateSelector(StateListDrawable)等与 Shape 结合的形式构建绘图。
11.【推荐】谨慎使用 gif 图片,注意限制每个页面允许同时播放的 gif 图片,以及单个 gif 图片的大小。
12.【参考】大图片资源不要直接打包到 apk,可以考虑通过文件仓库远程下载,减小包体积。
13.【推荐】根据设备性能,选择性开启复杂动画,以实现一个整体较优的性能和体验;
八、安全
1.【强制】禁止使用常量初始化矢量参数构建 IvParameterSpec,建议 IV 通过随机方式产生。
说明:使用常量初始化向量,密码文本的可预测性会高得多,容易受到字典式攻击。iv 的作用主要是用于产生密文的第一个 block,以使最终生成的密文产生差异(明文相同的情况下),使密码攻击变得更为困难。
2.【强制】将 android:allowbackup 属性必须设置为 false,阻止应用数据被导出。
说明:android:allowBackup 原本是 Android 提供的 adb 调试功能,如果设置为 true,可以导出应用数据备份并在任意设备上恢复。这对应用安全性和用户数据隐私构成极大威胁,所以必须设置为 false,防止数据泄露。
正例:例如使用系统 LruCache 缓存,参考:https://developer.android.com/topic/performance/graphics/cache-bitmap.htmlprivate LruCache<String, Bitmap> mMemoryCache;@Overrideprotected void onCreate(Bundle savedInstanceState) {...//获取可用内存的最大值,使用内存超出这个值将抛出 OutOfMemory 异常。LruCache 通过构造函数传入缓存值,以 KB 为单位。final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);//把最大可用内存的 1/8 作为缓存空间final int cacheSize = maxMemory / 8;mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) { return bitmap.getByteCount() / 1024;}};...}public void addBitmapToMemoryCache(String key, Bitmap bitmap) {if (getBitmapFromMemCache(key) == null) {mMemoryCache.put(key, bitmap);}}public Bitmap getBitmapFromMemCache(String key) {return mMemoryCache.get(key);}public void loadBitmap(int resId, ImageView imageView) {final String imageKey = String.valueOf(resId);final Bitmap bitmap = getBitmapFromMemCache(imageKey);if (bitmap != null) {mImageView.setImageBitmap(bitmap);} else {mImageView.setImageResource(R.drawable.image_placeholder);BitmapWorkerTask task = new BitmapWorkerTask(mImageView);task.execute(resId);}}class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {...//在后台进行图片解码@Overrideprotected Bitmap doInBackground(Integer...params) {final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), params[0], 100, 100));addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);return bitmap;}...}反例:没有存储,每次都需要解码,或者有缓存但是没有合适的淘汰机制,导致缓存效果很差,依然经常需要重新解码。
3.【强制】如果使用自定义 HostnameVerifier 实现类,必须在 verify()方法中校验服务器主机名的合法性,否则可能受到中间人攻击。
说明:在与服务器建立 https 连接时,如果 URL 的主机名和服务器的主机名不匹配,则可通过该回调接口来判断是否应该允许建立连接。如果回调内实现不恰当,没有有效校验主机名,甚至默认接受所有主机名,会大大增加安全风险。
正例:public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {// 首先通过 inJustDecodeBounds=true 获得图片的尺寸final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(res, resId, options);//然后根据图片分辨率以及我们实际需要展示的大小,计算压缩率options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);//设置压缩率,并解码options.inJustDecodeBounds = false;return BitmapFactory.decodeResource(res, resId, options);}反例:不经压缩显示原图。
4.【强制】如果使用自定义 X509TrustManager 实现类,必须在 checkServerTrusted()方法中校验服务端证书的合法性,否则可能受到中间人攻击。
说明:常见误区是 checkServerTrusted()方法根本没有实现,这将导致 X509TrustManager 形同虚设。该方法中需要实现完备的校验逻辑,对于证书错误抛出CertificateException 。
5.【强制】在 SDK 支持的情况下,Android 应用必须使用 V2 签名,这将对 APK 文件的修改做更多的保护。
6.【强制】 所有的 Android 基本组件( Activity、 Service 、BroadcastReceiver、ContentProvider 等)都不应在没有严格权限控制的情况下,将 android:exported 设置为 true。
7.【强制】WebView 应设置 WebView#getSettings()#setAllowFileAccess(false) 、WebView#getSettings()#
setAllowFileAccessFromFileURLs(false) 、WebView#getSettings()#
setAllowUniversalAccessFromFileURLs(false),阻止 file scheme URL 的访问。
8.【强制】不要把敏感信息打印到 log 中。
说明:在开发过程中,为了方便调试,通常会使用 log 函数输出一些关键流程的信息,这些信息中通常会包含敏感内容,让攻击者更加容易了解 APP 内部结构,方便破解和攻击,甚至直接获取到有价值的敏感信息。
9.【强制】确保应用发布版本的 android:debuggable 属性设置为 false。
10.【强制】本地加密秘钥不能硬编码在代码中,更不能使用 SharedPreferences 等本地持久化机制存储。应选择 Android 自身的秘钥库(KeyStore)机制或者其他安全性更高的安全解决方案保存。
说明:应用程序在加解密时,使用硬编码在程序中的密钥,攻击者通过反编译拿到密钥可以轻易解密 APP 通信数据。
11.【建议】addJavascriptInterface() 可以添加 JS 对本地 Java 方法的调用,但这本身会导致恶意代码的攻击。在 Android 4.2(API Level 17)以下,不应再使用这样的调用方式 。 在 Android 4.2 及以上,需要对本地被远程调用的方法显式添加 @JavascriptInterface annotation。
12【.强制】使用 Android 的 AES/DES/DESede 加密算法时,不要使用 ECB 加密模式,应使用 CBC 或 CFB 加密模式。
说明:加密模式有 ECB、CBC、CFB、OFB 等,其中 ECB 的安全性较弱,如果使用固定的密钥,相同的明文将会生成相同的密文,容易受到字典攻击,建议使用 CBC、 CFB 或 OFB 等模式。
1)ECB:Electronic codebook,电子密码本模式
2)CBC:Cipher-block chaining,密码分组链接模式
3)CFB:Cipher feedback,密文反馈模式
4)OFB:Output feedback,输出反馈模式
13.【强制】Android APP 在 HTTPS 通信中,验证策略需要改成严格模式。说明:Android APP 在 HTTPS 通信中,使用
ALLOW_ALL_HOSTNAME_VERIFIER,表示允许和所有的 HOST 建立 SSL 通信,这会存在中间人攻击的风险,最终导致敏感信息可能会被劫持,以及其他形式的攻击。
14【.推荐】在 Android 4.2(API Level 17)及以上,对安全性要求较高的应用可在 Activity中,对 Activity 所关联的 Window 应用
WindowManager.LayoutParams.FLAG_ SECURE,防止被截屏、录屏。但要注意的是,一个 Activity 关联的 Window 可能不止一个,如果使用了 Dialog / DialogFragment 等控件弹出对话框,它们本身也会创建一个新的 Window,也一样需要保护。
15.【推荐】zip 中不要包含 ../../file 这样的路径,可能被篡改目录结构,造成攻击。说明:当zip 压缩包中允许存在”../”的字符串,攻击者可以利用多个”../”在解压时改变 zip 文件存放的位置,当文件已经存在是就会进行覆盖,如果覆盖掉的文件是 so、dex 或者 odex 文件,就有可能造成严重的安全问题。
正例:public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeight, ImageCache cache) {final BitmapFactory.Options options = new BitmapFactory.Options();...BitmapFactory.decodeFile(filename, options);...//如果在 Honeycomb 或更新版本系统中运行,尝试使用 inBitmap if (Utils.hasHoneycomb()) {addInBitmapOptions(options, cache);}...return BitmapFactory.decodeFile(filename, options);}private static void addInBitmapOptions(BitmapFactory.Options options, ImageCache cache) {//inBitmap 只处理可变的位图,所以强制返回可变的位图options.inMutable = true;if (cache != null) {Bitmap inBitmap = cache.getBitmapFromReusableSet(options);if (inBitmap != null) {options.inBitmap = inBitmap;}}}
16.【推荐】MD5 和 SHA-1、SHA-256 等常用算法是 Hash 算法,有一定的安全性,但不能代替加密算法。敏感信息的存储和传输,需要使用专业的加密机制。
九、其他
1.【强制】不能使用 System.out.println 打印 log。
正例:Log.d(TAG, "Some Android Debug info ...");反例:System.out.println("System out println ...");
2.【强制】Log 的 tag 不能是” “。说明:日志的 tag 是空字符串没有任何意义,也不利于过滤日志。
正例:private static String TAG = "LoginActivity";Log.e(TAG, "Login failed!");反例:Log.e("", "Login failed!");
完整版关注我,私信手册可以获取《阿里巴巴Android开发手册》《Java开发手册》华山版,无套路
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!