啊,iOS 8 - 从iOS 7到帐户的许多意想不到的变化!
tl; dr:有没有办法以编程方式确定用于构建应用的iOS SDK版本,在运行时(不是使用预处理器宏)?
我正在努力为我维护的库(作为预构建的静态库分发)进行一些窗口框计算,因为iOS 8改变了屏幕坐标系的工作方式。
两个初步观察结果,运行iOS 7代码,iOS 8无变化:
因此,我们使用[[UIDevice currentDevice] systemVersion]
上的条件更改代码,以便与新坐标系统一起正常工作。现在:
使用iOS 8 SDK构建并在iOS 8上运行时,一切正常。
BUT:
使用 iOS 7 SDK构建,并在iOS 8上运行时,计算结束 - 请记住,使用iOS 7 SDK构建时,一切都在iOS 8之前正常运行特定的代码更改。所以,所做的改变实际上破坏了东西。
现在,通常情况下,我可以通过SDK版本(#ifdef __IPHONE_8_0
等)上的一些宏条件解决这个问题。但我正在分发一个预构建的静态库,使用iOS 7 SDK构建,因此这些条件中的代码永远不会在中生成。这就是为什么这是一个问题:
如果静态库是使用iOS 7 SDK构建的,但链接到使用iOS 8 SDK构建的应用程序,就像静态库是使用iOS 8 SDK构建的那样(因为链接发生在最终的应用程序编译阶段,当然)。这意味着,当使用iOS 8 SDK构建应用程序时,我需要在那里进行iOS 8更改 - 但我不能使用宏条件来确定是否使用它们,因为C预处理器在iOS 7下的静态库构建期间完成了它的工作。
所以,我的问题是这样的:有没有人知道我如何能够确定 app build 是否是在运行时使用iOS 8 SDK从预编译的静态库中完成的?
我确实尝试检查仅支持iOS 8的SDK功能(例如-[UIScreen nativeBounds]
),但这不会飞 - 无论SDK版本如何,该符号都可用。
有人有什么想法吗?
答案 0 :(得分:5)
经验性,无证件的观察如下:
Apple会在密钥DTSDKBuild
和DTSDKName
下的Info.plist中记录您构建的SDK。其中DTSDKName
似乎可以在运行时访问,并以SDK编号结束。所以,得到一个:
- (NSString *)buildVersion
{
// form character set of digits and punctuation
NSMutableCharacterSet *characterSet =
[[NSCharacterSet decimalDigitCharacterSet] mutableCopy];
[characterSet formUnionWithCharacterSet:
[NSCharacterSet punctuationCharacterSet]];
// get only those things in characterSet from the SDK name
NSString *SDKName = [[NSBundle mainBundle] infoDictionary][@"DTSDKName"];
NSArray *components =
[[SDKName componentsSeparatedByCharactersInSet:
[characterSet invertedSet]]
filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:@"length != 0"]];
if([components count]) return components[0];
return nil;
}
BOOL wasBuiltWithiOS8SDK =
[[[NSBundle mainBundle] infoDictionary][@"DTSDKBuild"] compare:@"11D167"]
== NSOrderedDescending;
......有一个重要的警告,我只是根据经验反向设计。所以它是技术上没有文档化的API,并且无法保证未来的稳健性。
然后你可以使用:
BOOL wasBuiltForiOS8 =
[[self buildVersion] compare:@"8.0"] != NSOrderedAscending;
(如果没有找到版本字符串,它具有很好的功能,它将评估为YES
,所以从技术上讲,Apple将来会带走DTSDKBuild
并不重要唯一的问题是他们不会追溯性地从7.x中删除它或某种程度上有一天使用8.0之前按字母顺序排列的版本字符串。
答案 1 :(得分:3)
这是一个临时解决方案 - 但是,hacky;拥有更强大的东西会很高兴。
- (BOOL)hasiOS8ScreenCoordinateBehaviour {
if ( [[[UIDevice currentDevice] systemVersion] floatValue] < 8.0 ) return NO;
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
if ( UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) &&
screenSize.width < screenSize.height ) {
return NO;
}
return YES;
}