2012-07-30 3 views
36

Wie kann ich programmgesteuert auf die Paket Seed ID/Team ID/App Identifier Prefix Zeichenfolge zugreifen? (Soweit ich das beurteilen kann, sind das alles die gleichen).Access App Identifier Präfix programmgesteuert

Ich verwende den UCKeychainStore keychain Wrapper, um Daten über mehrere Anwendungen hinweg zu erhalten. Jede dieser Anwendungen verfügt über eine gemeinsame Schlüsselbundzugriffsgruppe in ihren Berechtigungsplattformen und teilt dasselbe Bereitstellungsprofil. Standardmäßig verwenden die Schlüsselbunddienste die erste Zugriffsgruppe in der Gruppe als Zugriffsgruppe, in der Daten gespeichert werden. Das sieht wie "AS234SDG.com.myCompany.SpecificApp" aus, wenn ich UICKeychainStore debugge. Ich möchte die Zugriffsgruppe auf "AS234SDG.com.myCompany.SharedStuff" einstellen, aber ich kann nicht finden, wie man die "AS234SDG" Zeichenkette der Zugangsgruppe programmatisch erhält, und würde es vermeiden wollen, sie hart zu kodieren wenn möglich.

+0

Ich weiß nicht, ob ich dich verstanden habe, aber ist es dieser NSString * bundleIDstr = [[[NSBundle mainBundle] infoDictionary] objectForKey: @ "CFBundleIdentifier"]; du suchst nach ? – msk

+1

Das wird "com.myCompany.SpecificApp" zurückgeben - Ich suche nach dem Präfix "AS234SDG". –

+0

oh ich habe, was Sie jetzt fragen ... – msk

Antwort

50

Sie können die Bundle-Seed-ID programmgesteuert abrufen, indem Sie sich das Zugriffsgruppenattribut (d. H. kSecAttrAccessGroup) eines vorhandenen KeyChain-Elements ansehen. Im folgenden Code suche ich nach einem vorhandenen KeyChain-Eintrag und erzeuge einen, wenn dieser nicht existiert. Sobald ich einen KeyChain-Eintrag habe, entpacke ich die Informationen der Zugriffsgruppe und gebe die erste Komponente der Zugriffsgruppe durch "." (Punkt) als Bundle Seed ID.

+ (NSString *)bundleSeedID { 
    NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys: 
          (__bridge NSString *)kSecClassGenericPassword, (__bridge NSString *)kSecClass, 
          @"bundleSeedID", kSecAttrAccount, 
          @"", kSecAttrService, 
          (id)kCFBooleanTrue, kSecReturnAttributes, 
          nil]; 
    CFDictionaryRef result = nil; 
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); 
    if (status == errSecItemNotFound) 
     status = SecItemAdd((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); 
    if (status != errSecSuccess) 
     return nil; 
    NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:(__bridge NSString *)kSecAttrAccessGroup]; 
    NSArray *components = [accessGroup componentsSeparatedByString:@"."]; 
    NSString *bundleSeedID = [[components objectEnumerator] nextObject]; 
    CFRelease(result); 
    return bundleSeedID; 
} 
+1

Das hat perfekt funktioniert, danke. –

+0

Nur neugierig, wie haben Sie herausgefunden, "bundleSeedID" als kSecAttrAccount zu verwenden? – RajPara

+2

@RajPara: Das ist nur ein zufälliger Wert, den ich ausgewählt habe. Sie können es in "com.acme.bundleSeedID" ändern, wenn Sie möchten. Der Punkt besteht darin, einen Eintrag in KeyChain zu erstellen und ihn zurückzulesen und die Paket-ID aus den Zugriffsgruppeninformationen zu extrahieren. –

4

Dies ist eine gute Frage, aber zu erreichen, was Sie zu tun, waren dazu bestimmt, es könnte eine Lösung gewesen , die erfordert nicht die Bundle Seed-ID abzurufen.

Von diesen article, etwa der gleichen Schlüsselanhänger-Wrapper Sie verwenden:

Standardmäßig wird es die erste Zugriffsgruppe in Ihrem Entitlements.plist angegeben holen beim Schreiben und wird in alle Zugang suchen -groups, wenn keine angegeben ist.

Der Schlüssel wird dann in allen Gruppen gesucht, in denen der Zugriff gewährt wird. Um Ihr Problem zu lösen, können Sie die Zugriffsgruppe für alle Ihre Bundle-Apps in Ihrer Datei "aneignements.plist" hinzufügen, anstatt eine "shared stuff" -Gruppe zu verwenden. Fügen Sie $ (CFBundleIdentifier) ​​als erste Schlüsselbundgruppe ein (Ihr Schlüsselbund-Wrapper schreibt dann) Diese Gruppe) und Sie sind alle gesetzt

61

Info.plist kann Ihre eigenen Informationen haben und wenn Sie einen Wert mit $(AppIdentifierPrefix) schreiben, wird es in der Bauphase zu der tatsächlichen App-Kennung Präfix ersetzt.

Also, versuchen Sie dies:

In Ihrem Info.plist, eine Info über App-Identifikator hinzuzufügen.

<key>AppIdentifierPrefix</key> 
<string>$(AppIdentifierPrefix)</string> 

Sie können es dann programmgesteuert abrufen.

NSString *appIdentifierPrefix = 
    [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppIdentifierPrefix"]; 

anzumerken, dass appIdentifierPrefix mit einem Punkt endet; z.B. AS234SDG.

+2

Dies scheint der beste Weg, es zu tun. Sie können den vollständigen Wert sogar so speichern, wie er in den Berechtigungen angezeigt wird, z. B. "$ (AppIdentifierPrefix) com.MyCompany.MyApp", und diesen direkt ohne weitere Änderungen verwenden. –

+0

Vereinbart, das ist bevorzugt. Die programmatische Methode, die als die Antwort markiert wurde, mag 2012 gut gewesen sein, aber ich sehe, dass der Code hier 2015 uneinheitlich auf iOS 8 läuft. –

+0

Awesome man, thanks! – kernix

4

In swift3: (Basierend auf @Hiron Lösung)

einfach eine Zeile:

var appIdentifierPrefix = Bundle.main.infoDictionary!["AppIdentifierPrefix"] as! String 

Da in Ihrem Info.plist, fügen Sie den folgenden Schlüssel-Wert-Eigenschaft:

Schlüssel: AppIdentifierPrefix

String-Wert: $ (AppIdentifierPrefix)

0

Hier ist die Swift-Version @ David H Antwort:

static func bundleSeedID() -> String? { 
     let queryLoad: [String: AnyObject] = [ 
      kSecClass as String: kSecClassGenericPassword, 
      kSecAttrAccount as String: "bundleSeedID" as AnyObject, 
      kSecAttrService as String: "" as AnyObject, 
      kSecReturnAttributes as String: kCFBooleanTrue 
     ] 

     var result : AnyObject? 
     var status = withUnsafeMutablePointer(to: &result) { 
      SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0)) 
     } 

     if status == errSecItemNotFound { 
      status = withUnsafeMutablePointer(to: &result) { 
       SecItemAdd(queryLoad as CFDictionary, UnsafeMutablePointer($0)) 
      } 
     } 

     if status == noErr { 
      if let resultDict = result as? Dictionary<String, Any>, let accessGroup = resultDict[kSecAttrAccessGroup as String] as? String { 
       let components = accessGroup.components(separatedBy: ".") 
       return components.first 
      }else { 
       return nil 
      } 
     } else { 
      print("Error getting bundleSeedID to Keychain") 
      return nil 
     } 
    }