21

アプリ グループを有効にし、NSUserDefaults を使用することで、共有拡張機能とそれを含むアプリの間でデータを共有できることを理解しています (「iOS 8 共有拡張機能とメイン アプリの間でデータを共有する」を参照)。

ただし、保存しているデータは機密情報であるため、キーチェーンを使用したいと考えていました。したがって、ユーザーは含まれているアプリにアカウント情報を入力すると、共有拡張機能がそのデータを読み取って、意図した共有アクションを実行します。

これが可能かどうか誰にもわかりますか?私の最初の亀裂は、拡張機能とそれを含むアプリが別々のキーチェーンを持っていることを示唆しています (拡張機能でそのキーのデータを返そうとすると、含まれているアプリでキーを使用してデータを保存すると null が返されます)。

ありがとう!

PSキーチェーンアクセスにロックボックスを使用していますが、抽象化が多すぎて機能しない場合は捨てることができます。 https://github.com/granoff/Lockbox

4

5 に答える 5

22

Xcode 8 でキーチェーンを共有するには。

1) Capabilities の App ターゲットで、「キーチェーン共有」を見つけてオンにし、キーチェーン グループ キー (com.myappdomain.myappname のような逆ドメイン スタイルの文字列) を追加します。

2) 拡張ターゲットについてもまったく同じことを行います。キーチェーン グループ キーが、アプリと拡張機能の両方で同じであることを確認してください。

通常の方法でキーチェーンからデータを追加および取得します。コードに特別な変更は必要ありません。たとえば、メイン アプリのキーチェーンにデータを入れる方法を次に示します (少し古風ですが、Swift 3 でも動作します)。

let login = loginString
let domain = domainString
let passwordData: Data = passwordString.data(using: String.Encoding.utf8, allowLossyConversion: false)!
let keychainQuery: [NSString: NSObject] = [
    kSecClass: kSecClassGenericPassword,
    kSecAttrAccount: login as NSObject,  // login and domain strings help identify
    kSecAttrService: domain as NSObject, // the required record in the Keychain
    kSecValueData: passwordData as NSObject]
SecItemDelete(keychainQuery as CFDictionary) //Deletes the item just in case it already exists
let keychainSaveStatus: OSStatus = SecItemAdd(keychainQuery as CFDictionary, nil)

そして、拡張機能でそれを取得します。

let keychainQuery: [NSString: NSObject] = [
    kSecClass: kSecClassGenericPassword,
    kSecAttrAccount: login as NSObject,
    kSecAttrService: domain as NSObject,
    kSecReturnData: kCFBooleanTrue,
    kSecMatchLimit: kSecMatchLimitOne]
var rawResult: AnyObject?
let keychain_get_status: OSStatus = SecItemCopyMatching(keychainQuery as CFDictionary, &rawResult)

if (keychain_get_status == errSecSuccess) {
    if let retrievedData = rawResult as? Data,
        let password = String(data: retrievedData, encoding: String.Encoding.utf8) {
       // "password" contains the password string now
    }
}

正しいレコードを識別するために、「login」と「domain」を拡張機能に渡す必要があることに注意してください。これは NSUserDefaults を介して行うことができます。これを行う方法については、この回答を参照してください。

于 2017-01-11T10:26:24.887 に答える
9

これは可能です。これは、キーチェーン アクセスを行うためのフレームワークを作成し、[機能] の下で [キーチェーン共有を有効にする] をオンにする組み合わせです。このリンクは、私が知る必要があることを教えてくれました: http://swiftandpainless.com/ios8-share-extension-with-a-shared-keychain/

于 2014-11-02T06:06:03.227 に答える
1

アプリと共有拡張機能のターゲットの両方に対してアプリ グループ機能を有効にしました。

Singing&Capabilities に移動し、両方のターゲットに「App Group」機能を追加するだけです。次に、グループ ID 識別子 (「新しいコンテナーの作成」と呼ばれます) を一度作成する必要があります。たとえば、 create を作成しますgroup.lolrandomname。次に、両方のターゲットでこのアプリ グループ ID を選択/有効にする必要があります。

コードでは、共有キーチェーンを使用するたびにこの属性を追加する必要があります。 kSecAttrAccessGroup: "group.lolrandomname",

そして、それは正しく機能します: アプリと共有拡張機能から同じ保存されたアイテムにアクセスできます:)

共有キーチェーンに何かを格納する例を次に示します (クエリ内の 1 つの属性を除いてすべて同じです)。

let myAwesomeString = "hello world"

let query = [kSecClass: kSecClassGenericPassword,
             kSecAttrAccount: "com.myapp.an-awesome-string",
             kSecAttrAccessGroup: "group.lolrandomname",  // <<-- this!
             kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked,
             kSecValueData: myAwesomeString.data(using: .utf8)!] as [String: Any]

let status = SecItemAdd(query as CFDictionary, nil)

guard status == errSecSuccess else {
    print(status.humanReadable)
    throw KeyStoreError("Unable to store item: \(status.humanReadable)")
}

読み取りと削除については、 と を参照SecItemCopyMatchingしてくださいSecItemDelete。ただし、前述したように、kSecAttrAccessGroupキーをquery!

于 2021-07-15T17:22:56.617 に答える
0

標準の Objective-C KeychainItemWrapper クラスを使用し、ブリッジ ヘッダーに #import "KeychainItemWrapper.h" のエントリを追加します。

    func btnSaveAction() {

    let appGroupID = "group.com.yourcompany.appid"
    let keychain = KeychainItemWrapper(identifier: "Password", accessGroup:appGroupID)
    keychain.setObject(self.txtfldPassword.text!, forKey:kSecValueData)
    keychain.setObject(self.txtfldEmail.text!, forKey:kSecAttrAccount)

    }

Watch 拡張機能側 (Swift):

override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)

    let appGroupID = "group.com.yourcompany.appid"
    let keychain = KeychainItemWrapper(identifier: "Password", accessGroup:appGroupID)
    println(keychain.objectForKey(kSecAttrAccount))
    println(keychain.objectForKey(kSecValueData))

}

Objective C では、watchkit 拡張機能:

NSString *appGroupID = @"group.com.yourcompany.appid";
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"Password" accessGroup:appGroupID];
[keychain setObject:(__bridge id)(kSecAttrAccessibleWhenUnlocked) forKey:(__bridge id)(kSecAttrAccessible)];
NSLog(@"account = %@", [keychain objectForKey:(__bridge id)(kSecAttrAccount)]);
NSLog(@"password =%@", [keychain objectForKey:(__bridge id)(kSecValueData)]);

同じキーチェーン グループ「group.com.yourcompany.appid」の電話アプリとウォッチ キット拡張機能の両方で、[機能] の下の [キーチェーン共有] をオンにすることを忘れないでください。

于 2015-06-09T11:16:07.080 に答える
-1

次のリンクから KeychainItemWrapper クラスを使用し、グループ識別子を accessgroup として渡します。

https://developer.apple.com/library/ios/samplecode/GenericKeychain/Listings/Classes_KeychainItemWrapper_m.html

于 2015-04-07T13:16:13.943 に答える