2012-07-30 55 views
36

如何以編程方式訪問Bundle種子ID /團隊ID /應用標識符前綴字符串? (據我所知,這些都是一樣的東西)。以編程方式訪問應用標識符前綴

我正在使用UICKeychainStore鑰匙串包裝將數據保存在多個應用程序中。這些應用程序中的每個應用程序在其授權plists中都有一個共享密鑰鏈訪問組,並共享相同的供應配置文件。默認情況下,鑰匙串服務使用plist中的第一個訪問組作爲將數據保存到的訪問組。當我調試UICKeychainStore時,這看起來像「AS234SDG.com.myCompany.SpecificApp」。我想將訪問組設置爲「AS234SDG.com.myCompany.SharedStuff」,但我似乎無法找到如何以編程方式獲取訪問組的「AS234SDG」字符串,並且希望避免對其進行硬編碼如果可能的話。

+0

我不知道如果我理解你,但它是這樣的NSString * bundleIDStr = [[[一個NSBundle mainBundle] infoDictionary] objectForKey:@ 「CFBundleIdentifier」];你在找什麼? – msk 2012-07-30 17:42:09

+1

這將返回「com.myCompany.SpecificApp」 - 我正在查找「AS234SDG」前綴。 – 2012-07-30 17:52:16

+0

哦,我有你現在問的問題... – msk 2012-07-30 17:55:01

回答

50

您可以通過查看現有KeyChain項目的訪問組屬性(即kSecAttrAccessGroup)以編程方式檢索Bundle Seed ID。在下面的代碼中,我查找現有的KeyChain條目並創建一個,如果它不存在。一旦我有一個KeyChain條目,我從它提取訪問組信息並返回由「。」分隔的訪問組的第一個組件。 (期間)作爲捆綁種子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

這工作完美,謝謝。 – 2012-08-07 16:42:34

+0

只是好奇,你怎麼知道使用「bundleSeedID」作爲kSecAttrAccount? – RajPara 2012-10-30 16:18:04

+2

@RajPara:這只是我挑選的一個隨機值。如果需要,您可以將其更改爲「com.acme.bundleSeedID」。重點是在KeyChain中創建一個條目,並將其讀回並從訪問組信息中提取捆綁種子ID。 – 2012-10-31 18:46:12

4

這可是達到你的目的是要怎麼做一個很好的問題,有可能是一個解決方案 不需要檢索捆綁種子ID。

從這個article,差不多鑰匙扣包裝你使用:

默認情況下它會挑你的 Entitlements.plist指定的第一個訪問組書寫時,將在所有 訪問搜索當沒有指定任何組時。

然後,將在授予訪問權限的所有組中搜索密鑰。 因此,爲了解決您的問題,您可以將所有捆綁包應用程序的訪問組添加到您的entitlements.plist中,而不是使用「共享資料」組,將$(CFBundleIdentifier)作爲您的第一個鑰匙串組(您的鑰匙串包裝器將寫入這個組),並且你全部設置了

61

Info.plist可以有你自己的信息,如果你寫了一個值$(AppIdentifierPrefix),它將在構建階段被替換爲真正的應用程序標識符前綴。

所以,試試這個:

在你的Info.plist,添加有關應用標識符前綴的信息。

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

然後,您可以以編程方式檢索它。

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

請注意,appIdentifierPrefix以句點結尾;例如AS234SDG.

+2

這似乎是最好的辦法。您甚至可以存儲完整的值,就像它出現在授權中一樣,例如'$(AppIdentifierPrefix)com.MyCompany.MyApp',並且直接使用它,而不需要進一步修改。 – 2015-04-02 22:17:30

+0

同意這是首選。標記爲答案的編程方法在2012年可能已經很好,但是我看到代碼在iOS 8中2015年在這裏運行不穩定。 – 2015-04-29 17:53:27

+0

非常棒的人,謝謝! – kernix 2015-05-13 08:56:09

4

在swift3:(基於@Hiron溶液)

簡單的一行:

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

鑑於在你的信息。plist中,添加以下鍵值屬性:

鍵:AppIdentifierPrefix

字符串值:$(AppIdentifierPrefix)

0

這裏是@大衛^ h答案的斯威夫特版本:

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