ios - 能否在运行时以编程方式确定用于构建二进制文件的 iOS SDK 版本?

标签 ios objective-c xcode sdk ios8

啊,iOS 8 - 考虑到 iOS 7 的许多意想不到的变化!

tl;dr:有没有办法在运行时以编程方式确定用于构建应用程序的 iOS SDK 版本(不使用预处理器宏)?

由于 iOS 8 改变了屏幕坐标系的工作方式,我正在努力为我维护的库(作为预构建的静态库分发)进行一些窗口框架计算。

两个初步观察,针对 iOS 7 运行代码,没有针对 iOS 8 进行任何更改:

  1. 当使用 iOS 7 SDK 构建并在 iOS 8 上运行时,一切正常,无需更改。
  2. 当使用 iOS 8 SDK 构建并在 iOS 8 上运行时,它出现问题:需要对帧计算进行一些更改才能获得正确的定位。

因此,我们更改代码,使用 [[UIDevice currentDevice] systemVersion] 上的条件,以在新坐标系下正常工作。现在:

  1. 使用 iOS 7 SDK 构建并在 iOS 7 上运行时,一切正常。
  2. 使用 iOS 8 SDK 构建并在 iOS 8 上运行时,一切正常。

    但是:

  3. 当使用 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 下的静态库构建期间完成了它的工作。

所以,我的问题是:有谁知道我如何能够在运行时从预编译的静态库中确定应用程序构建是否是使用 iOS 8 SDK 制作的?

我确实尝试过检查仅适用于 iOS 8 的 SDK 功能(例如,-[UIScreen nativeBounds]),但这并没有成功——无论 SDK 版本如何,该符号都可用。

有人有什么想法吗?

最佳答案

经验性的、未记录的观察结果如下:

Apple 在 DTSDKBuildDTSDKName 键下的 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,并且无法保证 future 的稳健性。

然后你就可以使用:

BOOL wasBuiltForiOS8 = 
    [[self buildVersion] compare:@"8.0"] != NSOrderedAscending;

(它有一个很好的特性,如果没有找到版本字符串,它会评估为 YES,所以从技术上讲,Apple 是否带走 DTSDKBuild 在未来,唯一重要的是他们不会从 7.x 中追溯删除它,或者有一天以某种方式使用按字母顺序排列在 8.0 之前的版本字符串)

关于ios - 能否在运行时以编程方式确定用于构建二进制文件的 iOS SDK 版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25540140/

相关文章:

ios - 陀螺仪滚动图像有问题

objective-c - ios中存档取消存档,如何处理错误?

objective-c - iPhone 应用程序的设置包

ios - 如何在 iOS 中编写饮食提醒?

xcode - 在 Xcode 中自动生成方法注释

ios - 我们可以在 2 个不同的配置文件中添加 iOS 设备的单个 UDID

ios - Xcode在制作表单时将默认按钮设置为输入

ios - 如何从单个 json 值中获取字符串并将其快速附加到我的标签(使用 alamofire)

ios - 使用 Swift 的位置 BLE GPS 解码 location_and_speed

ios - 如何确定 QuickType 聊天是否已关闭?