兼容性
向后兼容和向前兼容
我们常常会见到关于向后/向前兼容性的描述,但是讨论兼容性的时候一定要明确谁是兼容性的主体,是说系统兼容性还是应用软件的兼容性,大部分时候讨论兼容性都是以系统为主体的,但是为了避免理解歧义也要对应用软件的兼容性有定义。这里的前 和 后 要理解成前进
和后退
,而不是从前和以后。
- 向后兼容性(Backwards compatibility)
向后兼容,又名向下兼容、回溯兼容。顾名思义是向过去兼容,是新系统兼容过去的软件(注意当针对软件讨论时是新软件兼容过去的系统)。为了维持原有的应用生态,大部分系统现在更新时都能够做到向后兼容,也比较容易做到,例如最新版的Windows10仍可以运行面向Windows7的x86应用程序。 - 向前兼容性(Forward compatibility)
向前兼容,又名向上兼容、前瞻兼容。顾名思义是向未来兼容,是旧系统兼容未来的软件(注意当针对软件讨论时是旧软件兼容未来的系统)。系统的向前兼容一般都是受约束的和有限的,当系统发行方声称停止对某系统版本的支持时,一般即表明该版本的系统已无法做到向前兼容,也表明系统发行方推出的针对最新系统版本的程序开发套件中已将对该旧版本的兼容考虑排除在外,针对最新版本系统构建的应用程序可能无法在旧版系统中正常运行。例如Android5.0仍可以运行面向Android10.0的大部分应用程序,而已停止支持的Android4.0可能无法运行最新构建的Android应用。
兼容性相关的Version设置
(下面介绍主要以Android平台为例,但是处理方式在各种平台的app开发中是基本一致的)
- targetsdkversion:Android应用的targetsdkversion是给相对新版Android系统实现
向后兼容性
的依据。理论上只要新版操作系统中的api保证和旧版api行为一致,如果需要变更行为推出新api即可,这样根本不需要什么targetsdkversion,因为任何sdkversion同名api的行为都是一致的。但是这毕竟是理想情况,实际情况是有时候对于新的行为会直接修改同名api的内容,但是其内部会保留之前sdk版本的行为,当判断目标应用程序的targetversion匹配之前的sdk版本时,api会保持对应sdk版本的行为。所以targetsdkversion是真正 影响应用外观和行为 的version,也就是高于targetsdkversion的Android系统会在源码中保证其系统的api行为和targetsdkversion时的系统一致,但是低于targetsdkversion的Android系统的api表现却只能和当前系统一致了。 - minsdkversion:minsdkversion是应用程序正常运行被动需要(或者说主观承诺)的最低版本,它包含了应用正常运行的 必需Api集合,应用商店会据此判断低于minsdkversion的设备将无法安装该应用。开发阶段要注意调用任何超过minsdkversion版本以上的api时都必须判断当前系统的版本是否低于该api需要的版本,并在低于时使用替代方案(禁用或使用阉割版的功能和体验),直接调用的话可能会在较低版本的设备上闪退。当应用的核心功能需要调用过多新版本api以至于无法(或开发者认为性价比很低而不值得)为低版本安卓实现替代方案时,此时认为当前应用场景无法支持该版本的安卓系统应当放弃兼容。另外需要注意minsdkversion不仅需要适配不存在的api,也需要注意适配行为和targetsdkversion不一致的api,需要在不一致时在源码中进行判断并处理。也就是targetsdkversion设置的很高也不是没有坏处,这会造成targetsdkversion以上的设备和minsdkversion的api行为差异过大,无形中增加适配成本。
- compilesdkversion: compilesdkversion是Android编译和build使用的版本,它决定了应用 可调用的Api集合,这是Android比较特殊的一个版本设置(UWP和iOS开发均只提供了min和target版本两个选项,编译时默认使用target版本的sdk),而android编译的sdk版本和target版本是不一致的。 compilesdkversion不会被编译到apk中,也就不会改变apk的运行时的行为,仅仅是为IDE提供编译警告和错误的依据,一般都是设置为最新版。额外设置一个compilesdkversion的一个作用是警示不要调用过时或将要废弃的api便于日后维护(尽管在发布targetsdkversion时该api并没过时);另一个作用是可以在较新版本的系统中调用高于targetsdkversion的新api,但我觉得尽量不要这么做,因为其它所有api的行为都是targetsdkversion时的,只有新api的行为是新的,可能会由于行为的版本不一致而造成一些问题,这也是UWP和iOS没有设置compilesdkversion的考虑原因之一。
- 理论上几个版本的关系是earliestversion<=minsdkversion<=targetsdkversion<=compilesdkversion<=lattestversion,其中earliestversion是当前仍然支持的最早版本,lattestversion是当前推出的最新版本,总体来说就是用较低的minSdkVersion来覆盖最大的人群,用最新的compileSdkVersion和较新的targetsdkversion来获得最好的外观和行为。而我觉得是这样来决定版本:minsdkVersion应当包含实现该应用核心功能必不可少的api,targetsdkversion应当包含实现该应用所有预期完整功能的api且和minsdkversion的行为差异不至于过大,如果有compliesdkversion设置则直接无脑设置成当前最高sdk版本。
Android Support Library
Android Support Library兼容包 提供 了旧版Android系统对新开发的Android应用的向前兼容性
,而且这种兼容性不仅仅是能够运行,还能使用部分(注意不是全部)新版本的api和feature。本身这些library应当是作为安卓操作系统更新集成在系统里给用户的,但是有些用户不更新或硬件无法支持更新操作系统,所以才有了这种扩展库的形式。要注意v4、v7等library是有对应sdk版本的,也就是它们会随着Android系统的更新而不断更新,他们对应的sdk版本即扩展库所支持的最高版本的api,所以程序添加兼容包依赖可以大大提高应用程序的兼容性。随着Android系统不断更新,在API Level 24的时候移除了Android2.3(API level 9)以下版本的支持,在API Level 26的时候移除了Android4.0(API level 14)以下版本的支持,所以目前最新的兼容包最低只支持到Api level 14了,也就是目前的新项目设置minsdkversion至少为14,当然如果你的项目minsdkversion仍希望支持更早的Android设备(尽管这不被推荐),可以使用旧版本的Supprot Library,然后将minsdkversion设置为9甚至是4。
- android-support-v4:该库最初支持的最低版本是Api Level 4的库,所以称其为V4。它包含了Fragment,NotificationCompat, LoadBroadcastManager, ViewPager,PageTabAtrip,Loader,FileProvider等库和控件
- android-support-v7:该库最初支持的最低版本是API Level 7的库,所以称其为V7。v7兼容包依赖于v4包并额外提供了一些api,是v4的超集,额外功能包括新的Theme,value,布局,新的控件,新的动画实现方式等等
- Androidx: 从android9.0(API Level 28)开始,android的support库进行了更新,未来新的特性和改进都会进入Androidx包来取代v4和v7兼容包,v4和v7的版本的support库都停留在了28版本。因为support库的命名令人迷惑并且包越来越臃肿(历史包袱沉重), Androidx包括目前v4和v7的所有内容但是部分命名空间有所改,如果你的项目引入的部分三方库依赖v4或v7则只能继续使用v4和v7,如果没有的话则应当只使用Androidx