[iOS] 複数アプリケーション間でのデータ共有 〜 Keychain Services を使った第三の方法
2011年2月7日月曜日 | Published in iOS 4.2, Keychain Services, サンプルあり | 1 コメント
※タイトルはあまり深い意味は無い。なんとなく「第三の〜」の響きが良かったので。。
前回紹介した Keychain Services を使えば制限付きながら iOS 上の複数のアプリケーションでデータ共有ができることがわかったのでそれを解説する。
[前回] Cocoaの日々: [iOS] Keychain Services とは
Keychain Services に格納されるアイテム(パスワードなど)のアクセス制御は Keychain Access Group(グループ)を元に行われる。アイテムにはこのグループ属性があり、同じグループに所属しているアプリケーションからのみアクセスが許可される。
アプリケーションは複数のグループに所属することができるので、データの共有を目的したグループを用意しておき、複数のアプリケーションでこのグループに所属すれば、このグループに所属するアイテムへそれら複数のアプリケーションがアクセスすることができる。
Keychain Services のアイテムはパスワード、秘密鍵、証明書を格納するようになっているが、CFData(NSData)型 であればパスワードである必要はない。格納したい値を CFData(NSData)へ変換すれば Keychain Services へ格納することができるので任意の値を共有することができる。
Keychain Access Group の詳細は前回の「3. アクセス制御」を参照のこと。
プロジェクトを2つ(KeyChainApp-1と KeyChainApp-2)用意し、それぞれのアプリケーションから同じアイテムへアクセスできるかを検証してみた。
Entitlements.plist
application-identifier: GFDZH8PXXX.com.yourcompany.KeyChainApp-1
アイテム登録コード
※サンプルコードを自分の環境でビルドする場合は "GFDZH8PXX" の箇所を自分のプロビジョニングファイルの app-identifier に書き換えること。
Entitlements.plist
application-identifier: GFDZH8PXXX.com.yourcompany.KeyChainApp-2
アクセス可能なアイテムをすべてデバッグコンソールへ表示。
まず KeyChainApp-1 を立ち上げてアカウント/パスワードを登録(Add new item)する。
Dump items で登録内容を確認しておく。
すると
更新はどうだろうか。KeyChainApp-1 で登録したこのデータ(パスワード)を KeyChainApp-2 で書き換えてみる。
すると
GitHub からどうぞ。
KeyChainApp-1 at 2011年02月07日 from xcatsan/iOS-Sample-Code - GitHub
KeyChainApp-2 at 2011年02月07日 from xcatsan/iOS-Sample-Code - GitHub
複数アプリケーション間でのデータ共有方法として使えることがわかった Keychain Services だが重大な制限もある。
シミュレータの場合、Entitlements.plist は無視されるので今回のように kSecAttrAccessGroup を設定すると登録はエラーとなる(-25243)。シミュレータの場合、前回説明したように Keychain Access Group は常に "test"(固定)となる。
前回紹介した Keychain Services を使えば制限付きながら iOS 上の複数のアプリケーションでデータ共有ができることがわかったのでそれを解説する。
[前回] Cocoaの日々: [iOS] Keychain Services とは
仕組み
Keychain Services に格納されるアイテム(パスワードなど)のアクセス制御は Keychain Access Group(グループ)を元に行われる。アイテムにはこのグループ属性があり、同じグループに所属しているアプリケーションからのみアクセスが許可される。
アプリケーションは複数のグループに所属することができるので、データの共有を目的したグループを用意しておき、複数のアプリケーションでこのグループに所属すれば、このグループに所属するアイテムへそれら複数のアプリケーションがアクセスすることができる。
Keychain Services のアイテムはパスワード、秘密鍵、証明書を格納するようになっているが、CFData(NSData)型 であればパスワードである必要はない。格納したい値を CFData(NSData)へ変換すれば Keychain Services へ格納することができるので任意の値を共有することができる。
Keychain Access Group の詳細は前回の「3. アクセス制御」を参照のこと。
サンプル
プロジェクトを2つ(KeyChainApp-1と KeyChainApp-2)用意し、それぞれのアプリケーションから同じアイテムへアクセスできるかを検証してみた。
KeyChainApp-1
Entitlements.plist
application-identifier: GFDZH8PXXX.com.yourcompany.KeyChainApp-1
アイテム登録コード
- (IBAction)addNewItem
{
NSData* passwordData = [self.password.text dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
[attributes setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[attributes setObject:(id)self.account.text forKey:(id)kSecAttrAccount];
[attributes setObject:passwordData forKey:(id)kSecValueData];
[attributes setObject:@"GFDZH8PXXX.share" forKey:(id)kSecAttrAccessGroup];
OSStatus err = SecItemAdd((CFDictionaryRef)attributes, NULL);
if (err == noErr) {
NSLog(@"SecItemAdd: noErr");
} else {
NSLog(@"SecItemAdd: error(%d)", err);
}
}登録するアイテムの Keychain Access Group (kSecAttrAccessGroup)に "GFDZH8PXXX.share" を指定している。※サンプルコードを自分の環境でビルドする場合は "GFDZH8PXX" の箇所を自分のプロビジョニングファイルの app-identifier に書き換えること。
KeyChainApp-2
Entitlements.plist
application-identifier: GFDZH8PXXX.com.yourcompany.KeyChainApp-2
アクセス可能なアイテムをすべてデバッグコンソールへ表示。
- (IBAction)dumpItems
{
NSMutableDictionary* query = [NSMutableDictionary dictionary];
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[query setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit];
CFArrayRef result = nil;
OSStatus err = SecItemCopyMatching((CFDictionaryRef)query,(CFTypeRef*)&result);
if (err == noErr) {
NSLog(@"SecItemCopyMatching: noErr");
NSLog(@"%@", result);
} else if(err = errSecItemNotFound) {
NSLog(@"SecItemCopyMatching: errSecItemNotFound");
} else {
NSLog(@"SecItemCopyMatching: error(%d)", err);
}
}パスワードを更新。- (IBAction)updateItem
{
NSMutableDictionary* attributes = nil;
NSMutableDictionary* query = [NSMutableDictionary dictionary];
NSData* passwordData = [self.password.text dataUsingEncoding:NSUTF8StringEncoding];
[query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
[query setObject:(id)self.account.text forKey:(id)kSecAttrAccount];
OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, NULL);
if (err == noErr) {
// update item
NSLog(@"SecItemCopyMatching: noErr");
attributes = [NSMutableDictionary dictionary];
[attributes setObject:passwordData forKey:(id)kSecValueData];
err = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributes);
if (err == noErr) {
NSLog(@"SecItemUpdate: noErr");
} else {
NSLog(@"SecItemUpdate: error(%d)", err);
}
} else if (err = errSecItemNotFound) {
// add new item
NSLog(@"SecItemCopyMatching: errSecItemNotFound");
} else {
NSLog(@"SecItemCopyMatching: error(%d)", err);
}
}結果
まず KeyChainApp-1 を立ち上げてアカウント/パスワードを登録(Add new item)する。
Dump items で登録内容を確認しておく。
{
acct = hashiguchi;
agrp = "GFDZH8PCUM.share";
pdmn = ak;
svce = "";
"v_Data" = <70617373 3030>;
}続いて KeyChainApp-2 を立ち上げ、登録アイテムを表示する(Dump items)。すると
{
acct = hashiguchi;
agrp = "GFDZH8PCUM.share";
pdmn = ak;
svce = "";
"v_Data" = <70617373 3030>;
}出た。KeyChainApp-1 で登録したデータをまったく別のアプリ KeyChainApp-2 で読み出すことができた。更新はどうだろうか。KeyChainApp-1 で登録したこのデータ(パスワード)を KeyChainApp-2 で書き換えてみる。
すると
{
acct = hashiguchi;
agrp = "GFDZH8PCUM.share";
pdmn = ak;
svce = "";
"v_Data" = <70617373 3131>;
}書き換わった。ソースコード
GitHub からどうぞ。
KeyChainApp-1 at 2011年02月07日 from xcatsan/iOS-Sample-Code - GitHub
KeyChainApp-2 at 2011年02月07日 from xcatsan/iOS-Sample-Code - GitHub
制限
複数アプリケーション間でのデータ共有方法として使えることがわかった Keychain Services だが重大な制限もある。
同じプロビジョニングファイルから作成されたアプリケーション間でしか Keychain Services を介したデータ共有は行えないこれは Keychain Access Group の指定方法の制約による。詳細は前回の「3. アクセス制御」を参照のこと。この為、残念ながら他社の作成したアプリとデータ交換を自由に行えるわけではない。
補足
シミュレータの場合、Entitlements.plist は無視されるので今回のように kSecAttrAccessGroup を設定すると登録はエラーとなる(-25243)。シミュレータの場合、前回説明したように Keychain Access Group は常に "test"(固定)となる。
登録:
コメントの投稿 (Atom)
人気の投稿(過去 30日間)
-
公式リファレンスの Q&A に解説がある。 Technical Q&A QA1551: Detecting the start and end edit sessions of a cell in NSTableView. 方法は Delegate と Not...
-
2011年06月09日 追記 UITableViewCell の Identifier 設定を忘れてたので追記しました。 UINib を使うと簡単に Nib で定義した UITableViewCell が使える。 今回のサンプル: [関連] Cocoaの日々: [iO...
-
Asset Catalogには画像以外のデータも置ける。サウンドファイル(.aif)を置いてみた。 取り出すには NSDataAsset を使う。 let sound = NSDataAsset(name: name) // use sound.data 取り出したサウ...
-
パスワードを暗号化して安全に iPhone/iPad へ保管したい。iOS はこの用途の為に Keychain Services を提供している。今回は Keychain Services について調べてみた。リファレンスの内容に加え、独自に調査・検証した結果をまとめてある。動作...
-
Core Data を使ったアプリケーションで下のような検索機能を実装している。 設定された値を元に NSPredicate を作成し、Core Data に対して検索をかけるのだが、こういう場合に NSCompoundPredicate が役に立つ。 NSCompound...
コメント
nishi
2013年7月28日 0:52
>同じプロビジョニングファイルから作成されたアプリケーション間でしか
>Keychain Services を介したデータ共有は行えない
同じAppIdentifierPrefixでなければデータ共有は行えないの間違いではないでしょうか。
AppIdentifierPrefixが同じであれば、別のプロビジョニングファイルでもよいと思います。
nishi
2013年7月28日 0:52
>同じプロビジョニングファイルから作成されたアプリケーション間でしか
>Keychain Services を介したデータ共有は行えない
同じAppIdentifierPrefixでなければデータ共有は行えないの間違いではないでしょうか。
AppIdentifierPrefixが同じであれば、別のプロビジョニングファイルでもよいと思います。
Leave a Response
[フレーム]