Как определить, что профиль обеспечения предназначен для разработки или распространения программно
Я хотел бы определить, является ли данный профиль обеспечения профилем разработки или профилем распространения (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 или нет.