xcode 如何以编程方式检测配置文件是用于开发还是分发

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16243855/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 03:17:11  来源:igfitidea点击:

How to detect that a provisioning profile is for development or distribution, programmatically

xcodeopensslxcodebuildprovisioning-profile

提问by Alfie Hanssen

I would like to detect if a given provisioning profile is a development profile or a distribution (adhoc or app store) profile. I need to do this purely programmatically.

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

I already understand how to detect adhoc vs appstore. And am specifically interested in dev vs. distribution.

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

I've examined the plists internal to each type of profile and cannot find a discernable difference (via security cms -D -i #{@profilePath}). I've also looked into the opensslapi and am using this for some certificate manipulation.

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

This is for a custom xcode automated build system. As part of pre-build validation I need to ensure that the specified profile is not for development.

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

Is this even possible? If so, how can I programmatically differentiate between the two?

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

Thanks in advance for any ideas!

提前感谢您的任何想法!

采纳答案by Bryan Musial

This was something I tackled in one of my own build systems for much the same purpose...let's take a trip back in time to Day 1 of the then 'iPhone Developer Program'. If you were around the community at that time, you may remember that the toolchain was...shall we say less friendly...than it is today.

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

When you wanted to build for the AppStore or for AdHoc builds you had to make this curious entitlements.plist file, then paste a blob of XML into the body of that file. You then ran the build and at that time what appeared to be magic occurred and the sheer presence of that file made the build work, allowed you to manually construct your IPA, and carry on with business as usual. Now that we are a few years older and hopefully a bit wiser than in those early days of the SDK, we have come to recognize that the magic XML blob wasn't actually so magical at all -- the 'get-task-allow' key is a setting to indicate if the binary should allow other processes (like perhaps a debugger) to attach to the binary. When signing apps using a Development Provisioning Profile, this key will be set to 'true' (and thus allow LLDB to attach and interact with your app)...and naturally when signing apps using a Distribution Provisioning Profile, this key will be set to 'false'.

当您想要为 AppStore 或 AdHoc 构建构建时,您必须制作这个奇怪的 entitlements.plist 文件,然后将 XML 的 blob 粘贴到该文件的正文中。然后你运行了构建,在那个时候发生了看起来很神奇的事情,并且该文件的存在使构建工作,允许你手动构建你的 IPA,并像往常一样继续业务。现在,我们比 SDK 的早期时代大了几岁,希望比 SDK 的早期更聪明一点,我们开始认识到神奇的 XML blob 实际上根本没有那么神奇——“get-task-allow” key 是一个设置,用于指示二进制文件是否应允许其他进程(例如调试器)附加到二进制文件。使用开发配置文件签署应用程序时,此密钥将设置为“true”

Apple has provided some updates in Tech Note TN2250about reading the XML (and by extension the entitlements) out of Provisioning Profiles:

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

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

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

This will return the XML in the Provisioning profile -- from there you can parse out the key value pair for 'get-task-allow' and use that value to determine if the Provisioning Profile is Development or Distribution.

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

I absolutely agree that it would be nice to have a tool that would tell us that directly so we don't have to sniff through the profile for clues, but at the same time, at least we have a highly reliable, albeit roundabout way to make that distinction before running off and making a build we can't use.

我绝对同意,如果有一个工具可以直接告诉我们,这样我们就不必通过嗅探来寻找线索,但同时,至少我们有一种高度可靠的,尽管迂回的方式在跑掉并进行我们无法使用的构建之前进行区分。

Good luck and let me know if you need any more clarification or have other questions.

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

回答by steipete

I've build a more concise and efficient version of Toom's code:

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

I'll maintain code snippets like this in a gist, you might find a more up to date version here: https://gist.github.com/steipete/7668246

我将在一个要点中维护这样的代码片段,您可能会在此处找到更新的版本: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
}

回答by Toom

Based on Bryan Musial great answer I wrote some code that allow you to check "get-task-allow" directly from application at runtime. In my case I'm using this boolean to only log in debug apps :

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

回答by Hannele

Here is a version for Swift 3, based on @steipete's answer:

这是 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
}

If curious, get-task-allowis a flag that the build uses to determine whether you should be able to hook up a debugger and other processes like that- so it's quite accurate for whether it is a dev build or no.

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