iOS SDK中API版本的检测

由于编辑器并未对高于最低支持版本的API进行异常提示,所以要自行实现一下提示,以避免使用了高版本的API

2016-03-30 | 阅读

XCode 检测代码使用API版本

前期项目未对API版本控制做过多的设计,后期代码过多,而Xcode也无法对使用API版本进行检测,需要使用一种方法来检测当前代码使用API的版本,以控制项目最低支持系统版本.

进入Foudation库中的NSObjCRuntime.h头文件,可以发现宏:

#define NS_CLASS_AVAILABLE(_mac, _ios)
#define NS_CLASS_DEPRECATED(_mac, _macDep, _ios, _iosDep, ...)

所有的SDK中的API都会使用该宏来表明,添加API的时间,和当前API是否被弃用.而我们检测API版本,也是通过重新定义该宏来实现的.而要重新定义该宏,之前尝试在预编译头.pch文件中添加一段代码来实现,效果不好,最终还是选择来修改SDK的源文件,也就是这个NSObjCRuntime.h头文件.

首先,要获得修改该文件的权限.但

然后再该宏后,一般我选择在@class NSString, Protocol;这行代码之前,添加以下代码:

//// 这里,我检测的是高于7.0版本的所有SDK,而且,当时SDK只到8.3,现在时ios9了,随着SDK的增加,还要自行进行补充
#define APICHECK_2_0( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_2_1( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_2_2( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_3_0( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_3_1( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_3_2( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_4_0( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_4_1( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_4_2( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_4_3( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_5_0( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_5_1( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_6_0( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_6_1( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
#define APICHECK_7_0( _ios ) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)
// 之前的是低于ios7的API,全部不做修改,后面是高于7.0的API,通过使用宏deprecated来进行提示
#define APICHECK_7_1( _ios ) __attribute__((deprecated("当前API是7.1的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_8_0( _ios ) __attribute__((deprecated("当前API是8.0的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_8_1( _ios ) __attribute__((deprecated("当前API是8.1的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_8_2( _ios ) __attribute__((deprecated("当前API是8.2的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_8_3( _ios ) __attribute__((deprecated("当前API是8.3的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_8_4( _ios ) __attribute__((deprecated("当前API是8.4的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_9_0( _ios ) __attribute__((deprecated("当前API是9.0的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_9_1( _ios ) __attribute__((deprecated("当前API是9.1的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_9_2( _ios ) __attribute__((deprecated("当前API是9.2的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK_NA( _ios )  __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios)

#undef NS_AVAILABLE_IOS
#define NS_AVAILABLE_IOS(_ios) APICHECK_ ## _ios( _ios )
#undef NS_AVAILABLE
#define NS_AVAILABLE(_mac, _ios) APICHECK_ ## _ios( _ios )
#undef NS_ENUM_AVAILABLE
#define NS_ENUM_AVAILABLE(_mac, _ios) APICHECK_ ## _ios( _ios )

修改完后,在Xcode重新编译项目,就可以清楚的对项目内使用的API版本进行控制.所有使用了高于7的API都会爆出警告,而这个警告是使用宏deprecated创建的警告,也就是API弃用的警告.

之后发现系统SDK中对版本的控制,不只会使用这个NS_AVAILABLE_IOS,有时候还会使用__OSX_AVAILABLE_STARTING,所以也需要重新定义这个宏.这个宏位于iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/文件夹下的Availability.h文件中,修改include文件夹和这个文件的权限,就可以解锁并修改这个文件,这个文件中如此定义宏:

#define __OSX_AVAILABLE_STARTING(_osx, _ios) __AVAILABILITY_INTERNAL##_ios

所以我们相应的修改形式为 :

#define APICHECK__IPHONE_2_0( _ios ) __AVAILABILITY_INTERNAL__IPHONE_2_0
#define APICHECK__IPHONE_2_1( _ios ) __AVAILABILITY_INTERNAL__IPHONE_2_1
#define APICHECK__IPHONE_2_2( _ios ) __AVAILABILITY_INTERNAL__IPHONE_2_2
#define APICHECK__IPHONE_3_0( _ios ) __AVAILABILITY_INTERNAL__IPHONE_3_0
#define APICHECK__IPHONE_3_1( _ios ) __AVAILABILITY_INTERNAL__IPHONE_3_1
#define APICHECK__IPHONE_3_2( _ios ) __AVAILABILITY_INTERNAL__IPHONE_3_2
#define APICHECK__IPHONE_4_0( _ios ) __AVAILABILITY_INTERNAL__IPHONE_4_0
#define APICHECK__IPHONE_4_1( _ios ) __AVAILABILITY_INTERNAL__IPHONE_4_1
#define APICHECK__IPHONE_4_2( _ios ) __AVAILABILITY_INTERNAL__IPHONE_4_2
#define APICHECK__IPHONE_4_3( _ios ) __AVAILABILITY_INTERNAL__IPHONE_4_3
#define APICHECK__IPHONE_5_0( _ios ) __AVAILABILITY_INTERNAL__IPHONE_5_0
#define APICHECK__IPHONE_5_1( _ios ) __AVAILABILITY_INTERNAL__IPHONE_5_1
#define APICHECK__IPHONE_6_0( _ios ) __AVAILABILITY_INTERNAL__IPHONE_6_0
#define APICHECK__IPHONE_6_1( _ios ) __AVAILABILITY_INTERNAL__IPHONE_6_1
#define APICHECK__IPHONE_7_0( _ios ) __AVAILABILITY_INTERNAL__IPHONE_7_0
// 之前的是低于ios7的API,全部不做修改,后面是高于7.0的API,通过使用宏deprecated来进行提示
#define APICHECK__IPHONE_7_1( _ios ) __attribute__((deprecated("当前API是7.1的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_8_0( _ios ) __attribute__((deprecated("当前API是8.0的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_8_1( _ios ) __attribute__((deprecated("当前API是8.1的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_8_2( _ios ) __attribute__((deprecated("当前API是8.2的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_8_3( _ios ) __attribute__((deprecated("当前API是8.3的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_8_4( _ios ) __attribute__((deprecated("当前API是8.4的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_9_0( _ios ) __attribute__((deprecated("当前API是9.0的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_9_1( _ios ) __attribute__((deprecated("当前API是9.1的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_9_2( _ios ) __attribute__((deprecated("当前API是9.2的,超过了当前最低兼容版本7.0,请进行版本控制")))
#define APICHECK__IPHONE_NA( _ios )  __AVAILABILITY_INTERNAL__IPHONE_NA
#undef __OSX_AVAILABLE_STARTING
#define __OSX_AVAILABLE_STARTING(_osx, _ios) APICHECK##_ios(_ios)

这两个地方修改好后,应该所有的版本检测处都进行判断了吧,如果以后发现新的地方有进行宏的检测,再进行补充吧.