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

时间:2014-08-28 03:14:08

标签: 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上运行时,它已被破坏:需要对帧计算进行一些更改才能获得正确的定位。
  3. 因此,我们使用[[UIDevice currentDevice] systemVersion]上的条件更改代码,以便与新坐标系统一起正常工作。现在:

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

      BUT:

    3. 使用 iOS 7 SDK构建,并在iOS 8上运行时,计算结束 - 请记住,使用iOS 7 SDK构建时,一切都在iOS 8之前正常运行特定的代码更改。所以,所做的改变实际上破坏了东西。

    4. 现在,通常情况下,我可以通过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版本如何,该符号都可用。

      有人有什么想法吗?

2 个答案:

答案 0 :(得分:5)

经验性,无证件的观察如下:

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,并且无法保证未来的稳健性。

然后你可以使用:

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;
}