【问题标题】:How to detect that a provisioning profile is for development or distribution, programmatically如何以编程方式检测配置文件是否用于开发或分发
【发布时间】:2013-04-26 19:30:08
【问题描述】:

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

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

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

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

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

提前感谢您的任何想法!

【问题讨论】:

  • 这是一个有趣的问题,+1。
  • 显然testflightapp.com 的人正在为 .ipa 文件执行此操作,但我什至不知道如何区分您正在执行的 adhoc/appstore。我认为 XCode 的命令行工具应该包括一个“provisioning profile lint tool”,这应该为我们完成。这只是用户困惑的一个丰富来源。谢谢苹果。
  • 嗨 Warren P,仅供参考,我为检测 adhoc vs appstore 配置文件所做的一切是检查配置文件 plist 中是否存在 ProvisionedDevices 键,因为 appstore 配置文件不会有任何配置的设备。可能不是万无一失的,但对于我在其中工作的系统而言,它可以达到目的。希望这很有用。

标签: xcode openssl xcodebuild provisioning-profile


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    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。

    我绝对同意,如果有一个工具可以直接告诉我们,这样我们就不必从个人资料中寻找线索,但与此同时,至少我们有一个高度可靠的工具,尽管在运行和构建我们无法使用的构建之前,采用迂回的方式来区分。

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

    【讨论】:

    • 很好的答案,正是我想要的,谢谢你的详细解释!
    • 不客气! ProvisionedDevices 密钥仍然是一个很好的辅助验证措施;我没有在我的系统中使用它,但你当然可以。
    【解决方案3】:

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

    【讨论】:

    • 感谢关于没有配置文件的 App Store 构建的评论。帮我调试了一个神秘的崩溃!
    • 我在 iOS 13 beta 3 中遇到此代码问题
    【解决方案4】:

    这是 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-allowa flag that the build uses to determine whether you should be able to hook up a debugger and other processes like that - 所以它是否是开发版本非常准确。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-10
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 2012-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多