29

我想检测给定的配置文件是开发配置文件还是分发(临时或应用商店)配置文件。我需要纯粹以编程方式执行此操作。

我已经了解如何检测 adhoc vs appstore。我对开发与分发特别感兴趣。

我检查了每种类型的配置文件内部的 plist 并且找不到可辨别的差异(通过security cms -D -i #{@profilePath})。我还研究了opensslapi 并将其用于一些证书操作。

这是一个自定义的 xcode 自动构建系统。作为预构建验证的一部分,我需要确保指定的配置文件不用于开发。

这甚至可能吗?如果是这样,我如何以编程方式区分两者?

提前感谢您的任何想法!

4

4 回答 4

23

我已经构建了一个更简洁高效的 Tom 代码版本:

我将在要点中维护这样的代码片段,您可能会在这里找到更新的版本:https ://gist.github.com/steipete/7668246

static BOOL PSPDFIsDevelopmentBuild(void) {
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
static BOOL isDevelopment = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // There is no provisioning profile in AppStore Apps.
    NSData *data = [NSData dataWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"embedded" ofType:@"mobileprovision"]];
    if (data) {
        const char *bytes = [data bytes];
        NSMutableString *profile = [[NSMutableString alloc] initWithCapacity:data.length];
        for (NSUInteger i = 0; i < data.length; i++) {
            [profile appendFormat:@"%c", bytes[i]];
        }
        // Look for debug value, if detected we're a development build.
        NSString *cleared = [[profile componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] componentsJoinedByString:@""];
        isDevelopment = [cleared rangeOfString:@"<key>get-task-allow</key><true/>"].length > 0;
    }
});
return isDevelopment;
#endif
}
于 2013-11-26T23:35:22.633 回答
21

这是我在我自己的一个构建系统中解决的问题,目的大致相同……让我们回到当时的“iPhone 开发人员计划”的第一天。如果您当时在社区中,您可能还记得工具链......我们应该说不那么友好......不如今天。

当您想要为 AppStore 或 AdHoc 构建构建时,您必须创建这个奇怪的 entitlements.plist 文件,然后将一个 XML 块粘贴到该文件的主体中。然后您运行构建,当时似乎发生了一些神奇的事情,并且该文件的存在使构建工作,允许您手动构建您的 IPA,并照常进行业务。现在我们已经老了几年,希望比 SDK 的早期更聪明一点,我们已经认识到神奇的 XML blob 实际上并没有那么神奇——“get-task-allow” key 是一个设置,用于指示二进制文件是否应该允许其他进程(比如调试器)附加到二进制文件。使用开发配置文件签署应用程序时,此密钥将设置为“真”

Apple 在Tech Note TN2250中提供了一些关于从 Provisioning Profiles 中读取 XML(以及扩展权利)的更新:

安全 cms -D -i /path/to/the.app/embedded.mobileprovision

这将在 Provisioning Profile 中返回 XML——您可以从那里解析出“get-task-allow”的键值对,并使用该值来确定 Provisioning Profile 是 Development 还是 Distribution。

我绝对同意,如果有一个工具可以直接告诉我们,这样我们就不必通过配置文件来寻找线索,但与此同时,至少我们有一个高度可靠的,虽然迂回的方式在运行和构建我们无法使用的构建之前做出区分。

祝你好运,如果您需要更多说明或有其他问题,请告诉我。

于 2013-04-28T22:54:27.640 回答
10

基于 Bryan Musial 的精彩回答,我编写了一些代码,允许您在运行时直接从应用程序中检查“get-task-allow”。就我而言,我使用此布尔值仅登录调试应用程序:

+ (BOOL)isDevelopmentApp
{
    // Special case of simulator
    if (isSimulator)
    {
        return YES;
    }

    // There is no provisioning profile in AppStore Apps
    NSString *profilePath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];

    // Check provisioning profile existence
    if (profilePath)
    {
        // Get hex representation
        NSData *profileData = [NSData dataWithContentsOfFile:profilePath];
        NSString *profileString = [NSString stringWithFormat:@"%@", profileData];

        // Remove brackets at beginning and end
        profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""];
        profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(profileString.length - 1, 1) withString:@""];

        // Remove spaces
        profileString = [profileString stringByReplacingOccurrencesOfString:@" " withString:@""];

        // Convert hex values to readable characters
        NSMutableString *profileText = [NSMutableString new];
        for (int i = 0; i < profileString.length; i += 2)
        {
            NSString *hexChar = [profileString substringWithRange:NSMakeRange(i, 2)];
            int value = 0;
            sscanf([hexChar cStringUsingEncoding:NSASCIIStringEncoding], "%x", &value);
            [profileText appendFormat:@"%c", (char)value];
        }

        // Remove whitespaces and new lines characters
        NSArray *profileWords = [profileText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSString *profileClearText = [profileWords componentsJoinedByString:@""];

        // Look for debug value
        NSRange debugRange = [profileClearText rangeOfString:@"<key>get-task-allow</key><true/>"];
        if (debugRange.location != NSNotFound)
        {
            return YES;
        }
    }

    // Return NO by default to avoid security leaks
    return NO;
}
于 2013-07-29T17:18:04.207 回答
7

这是 Swift 3 的一个版本,基于@steipete 的回答:

static func isDevelopmentProvisioningProfile() -> Bool {
#if IOS_SIMULATOR
    return true
#else
    // there will be no provisioning profile in AppStore Apps
    guard let fileName = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision") else {
        return false
    }

    let fileURL = URL(fileURLWithPath: fileName)
    // the documentation says this file is in UTF-8, but that failed
    // on my machine. ASCII encoding worked ¯\_(ツ)_/¯
    guard let data = try? String(contentsOf: fileURL, encoding: .ascii) else {
        return false
    }

    let cleared: String = data.components(separatedBy: .whitespacesAndNewlines).joined()
    return cleared.contains("<key>get-task-allow</key><true/>")
#endif
}

如果好奇,这get-task-allow构建用来确定您是否应该能够连接调试器和其他类似进程的标志- 所以它是否是开发构建非常准确。

于 2017-11-21T22:41:56.597 回答