Как определить, что профиль обеспечения предназначен для разработки или распространения программно

Я хотел бы определить, является ли данный профиль обеспечения профилем разработки или профилем распространения (adhoc или app store). Мне нужно сделать это чисто программно.

Я уже понимаю, как обнаружить adhoc vs appstore. И особенно заинтересован в разработке и распространении.

Я проверил списки внутренних компонентов для каждого типа профиля и не могу найти заметную разницу (через security cms -D -i #{@profilePath}). Я также посмотрел в openssl API и я использую это для некоторых манипуляций с сертификатами.

Это для пользовательской системы автоматической сборки xcode. В рамках проверки перед сборкой я должен убедиться, что указанный профиль не предназначен для разработки.

Это вообще возможно? Если так, как я могу программно различать два?

Заранее спасибо за любые идеи!

4 ответа

Решение

Это было чем-то, что я использовал в одной из моих собственных систем сборки для той же цели... давайте вернемся назад во время первого дня тогдашней "Программы для разработчиков iPhone". Если вы были в то время в сообществе, вы можете помнить, что набор инструментов был... скажем так, менее дружелюбным... чем сегодня.

Когда вы хотели создать сборку для AppStore или AdHoc, вам нужно было создать этот любопытный файл authorlements.plist, а затем вставить большой кусок XML в тело этого файла. Затем вы запустили сборку, и в это время произошло то, что казалось волшебным, и само присутствие этого файла сделало работу по сборке, позволила вам вручную создать свой IPA и продолжить работу в обычном режиме. Теперь, когда мы на несколько лет старше и, надеюсь, немного мудрее, чем в те ранние дни SDK, мы осознали, что магический блоб XML на самом деле вовсе не был таким волшебным - "get-task-allow" Ключ - это параметр, указывающий, должен ли двоичный файл позволять другим процессам (например, отладчику) подключаться к двоичному файлу. При подписывании приложений с использованием профиля обеспечения разработки этот ключ будет иметь значение "истина" (и, таким образом, LLDB будет подключаться и взаимодействовать с вашим приложением)... и, естественно, при подписании приложений с использованием профиля обеспечения распространения этот ключ будет установлен на "ложь".

Apple предоставила некоторые обновления в Технической ноте TN2250 о чтении XML (и, соответственно, прав) из профилей обеспечения:

CMS безопасности -D -i /path/to/the.app/embedded.mobileprovision

Это вернет XML в профиле Provisioning - оттуда вы можете проанализировать пару ключ-значение для 'get-task-allow' и использовать это значение, чтобы определить, является ли профиль Provisioning Profile разработкой или распространением.

Я абсолютно согласен, что было бы неплохо иметь инструмент, который бы сообщал нам об этом напрямую, чтобы нам не приходилось перебирать профиль для подсказок, но в то же время, по крайней мере, у нас есть очень надежный, хотя и окольный способ сделайте это различие, прежде чем убегать и делать сборку, которую мы не сможем использовать.

Удачи и дайте мне знать, если вам нужно больше разъяснений или есть другие вопросы.

Я построил более краткую и эффективную версию кода Toom:

Я буду поддерживать подобные фрагменты кода в гисте, вы можете найти более свежую версию здесь: 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
}

Основываясь на отличном ответе Брайана Мюзиала, я написал код, позволяющий проверять "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;
}

Вот версия для 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 это флаг, который использует сборка, чтобы определить, сможете ли вы подключить отладчик и другие подобные процессы, поэтому он достаточно точен, независимо от того, является ли это сборкой dev или нет.

Другие вопросы по тегам