一个好的APP最好支持90%设备,由于不同版本系统提供的API可能不同,所以了解不同版本间系统差异很重要,这样才能更好的适配更多的智能设备。你的应用足不足够健壮要看你的应用在主流版本运行是否流畅。这篇文章记录开发过程中遇到的相对重要以及常用的适配方案,希望对读者有所帮助。
Android 版本号及对应的版本名
版本号 | 版本名 | 中文名 |
---|---|---|
API R | android R | |
API Q | android Q | |
API 28 | android 9.0 Pie | 馅饼 |
API 27 | android 8.1 Oreo | 奥利奥 |
API 26 | android 8.0 Oreo | 奥利奥 |
API 25 | android 7.1 Nougat | 牛轧糖 |
API 24 | android 7.0 Nougat | 牛轧糖 |
API 23 | android 6.0 Marshmallow | 棉花糖 |
API 22 | android 5.1 Lollipop | 棒棒糖 |
API 21 | android 5.0 Lollipop | 棒棒糖 |
API 20 | android 4.4W KitKat | 奇巧巧克力棒 |
API 19 | android 4.4 KitKat | 奇巧巧克力棒 |
API 18 | android 4.3 Jelly Bean | 果冻豆 |
API 17 | android 4.2 Jelly Bean | 果冻豆 |
API 16 | android 4.1 Jelly Bean | 果冻豆 |
API 15 | android 4.0.3 ~4.0.4 Ice Cream Sandwich | 冰淇淋三明治 |
API 14 | android 4.0 ~ 4.0.2 Ice Cream Sandwich | 冰淇淋三明治 |
API 13 | android 3.2 Honeycomb | 蜂巢 |
API 12 | android 3.1 Honeycomb | 蜂巢 |
API 11 | android 3.0 Honeycomb | 蜂巢 |
API 10 | android 2.3.3 ~ 2.3.7 Gingerbread | 姜饼 |
API 9 | android 2.3~ 2.3.2 Gingerbread | 姜饼 |
API 8 | android 2.2~ 2.2.3 Froyo | 冻酸奶 |
API 7 | android 2.1 Éclair | 闪电泡芙 |
API 6 | android 2.0.1 Éclair | 闪电泡芙 |
API 5 | android2.0 Éclair | 闪电泡芙 |
API 4 | android 1.6 Donut | 甜甜圈 |
API 3 | android 1.5 ICupcake | 纸杯蛋糕 |
API 2 | android 1.1 | |
API 1 | android 1.0 |
Android5.0
1、Android Runtime (ART)
Android运行时由Android核心库集和Dalvike虚拟机改成Android核心库集和ART(Android Runtime)模式。两者的区别就是Dalvike虚拟机采用了一种被称为JIT(just-in-time)的解释器进行动态编译,而ART模式则在用户安装App是进行预编译AOT(Ahead-of-time),将android5.X的运行速度提高了3倍左右。
ART的特性:
1: 用户安装应用时就进行预编译操作,将原本在程序运行中时的编译动作提前到应用安装时。在省去解释代码这一过程之后,应用的运行效率会更高。
缺点:(1) 安装时间增加 (2) 安装后的文件占用更多空间?(外存储器)
2: 解决垃圾回收 (GC) 问题
在 Dalvik 中,应用常常发现显式调用 System.gc() 非常有用,可促进垃圾回收 (GC)。对 ART 而言这种做法的必要性低得多,尤其是当您需要通过垃圾回收来预防出现 GC_FOR_ALLOC 类型或减少碎片时。
而且,Android 开源项目 (AOSP) 中正在开发一种紧凑型垃圾回收器,以改善内存管理。
3:预防 JNI 问题
ART 的 JNI 比 Dalvik 的 JNI 更为严格一些。使用 CheckJNI 模式来捕获常见问题是一种特别实用的方法。
1): 检查 JNI 代码中的垃圾回收问题
2): 错误处理 ART 的 JNI 会在多种情况下引发错误,而 Dalvik 则不然。(同样地,您可以通过使用 CheckJNI 执行测试来捕获大量此种情况)
3): 预防堆栈大小问题 Dalvik 具有单独的原生代码堆栈和 Java 代码堆栈,并且默认的 Java 堆栈大小为 32KB,默认的原生堆栈大小为 1MB。
2、Button将总是位于最上层
从5.0开始,在同一个layout下,就算你在Button上覆盖了相应的View,Button将总是位于最上层。产生原因:stateListAnimator属性。谷歌在Material Design中推出,是一个非常简单的方法用来实现在可视状态之间平滑过渡。这个属性可以通过android:stateListAnimator进行设置,可以使控件在点击时产生不同的交互。对于Button,点击时默认有个阴影的效果用于表示按下的状态(5.0以前就是简单的变色)。 解决方法:可以使用 android:stateListAnimator="@null" 去掉阴影效果而使Button可以被正常的覆盖。
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stateListAnimator="@null"/>
Android6.0
1、动态权限
动态权限适配是 Android 6.0 最先开始的,也是 Android 系统对开发者影响最大的改动之一。系统权限主要分为两类,正常权限和危险权限。不管哪个版本的android,你应用中所用到的所有权限,不管是正常权限还是危险权限,都需要在应用Manifest中申明。你的目标SDK(targetSdkVersion)是23以及23以上版本:应用必须在Manifest中罗列出所有的权限,并且在程序运行时,它必须请求用户授予每一个危险权限,此时用户可以授予或者拒绝每一个权限,并且应用程序可以继续运行有限的功能,即使用户拒绝了权限请。在 Android 6.0 ~ Android 8.0中,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用,即对于同一组内的权限,只要有一个被同意,其他的都会被同意。在 Android 8.0 之后,此行为已被纠正。系统只会授予应用明确请求的权限。然而一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准,但是若没有请求相应的权限而进行操作的话就会出现应用 crash 的情况。
危险权限分组说明
权限组 | 权限名称 |
---|---|
CALENDAR | android.permission.READ_CALENDAR |
android.permission.WRITE_CALENDAR | |
CAMERA | android.permission.CAMERA |
CALENDAR | android.permission.READ_CALENDAR |
android.permission.WRITE_CALENDAR | |
CONTACTS | android.permission.READ_CONTACTS |
android.permission.WRITE_CONTACTS | |
android.permission.GET_ACCOUNTS | |
LOCATION | android.permission.ACCESS_FINE_LOCATION |
android.permission.ACCESS_COARSE_LOCATION | |
MICROPHONE | android.permission.RECORD_AUDIO |
PHONE | android.permission.READ_PHONE_STATE |
android.permission.CALL_PHONE | |
android.permission.READ_CALL_LOG | |
android.permission.ADD_VOICEMAIL | |
android.permission.WRITE_CALL_LOG | |
android.permission.USE_SIP | |
android.permission.PROCESS_OUTGOING_CALLS | |
android.permission.ANSWER_PHONE_CALLS(8.0新增) | |
android.permission.READ_PHONE_NUMBERS(8.0新增) | |
SENSORS | android.permission.BODY_SENSORS |
SMS | android.permission.SEND_SMS |
android.permission.RECEIVE_SMS | |
android.permission.READ_SMS | |
android.permission.RECEIVE_WAP_PUSH | |
android.permission.RECEIVE_MMS | |
STORAGE | android.permission.READ_EXTERNAL_STORAGE |
android.permission.WRITE_EXTERNAL_STORAGE |
对应在清单文件中的展示
<!--CALENDAR-->
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<!--CAMERA-->
<uses-permission android:name="android.permission.CAMERA"/>
<!--CONTACTS-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!--LOCATION-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!--MICROPHONE-->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--PHONE-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.USE_SIP"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>
<!--SENSORS-->
<uses-permission android:name="android.permission.BODY_SENSORS"/>
<!--SMS-->
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/