Upload
takaaki-tanaka
View
1.763
Download
1
Embed Size (px)
Citation preview
AddressBook to Contacts
クラスメソッド株式会社 モバイルアプリサービス部
田中 孝明
自己紹介
名前 田中 孝明
出身 岡山県
iOS 開発歴 2011 ~ (ブランクあり)
入社歴 14
9月27日に福岡から来ました
閑話休題
AddressBook
Contacts
Reference• What's New in iOS 9.0
• Introducing the Contacts Framework for iOS and OS X
• Address Book Framework Reference for iOS
• Contacts Framework Reference
• http://qiita.com/koogawa/items/44ce2e1fb127b884d835
Agenda
• 1. 連絡先について
• 2. AddressBookとContactsについて
• 3. Privacyについて
• 4. Fetchの違いについて
• 5. 連絡先の編集の違いについて
1. 連絡先について
連絡先について• 連絡先に登録されているユーザーのデータベースを管理
連絡先について• 名前
• 電話番号
• 所属
• 住所
• 誕生日
• …etc
連絡先にアクセスするアプリ
• ユーザーの検索
• 友人の招待
• ユーザーの登録
活躍の場の例
• サポートデスクの連絡先を追加する
• 社員の連絡先を追加する
• 指定された連絡先のみを削除する
2. AddressBookとContactsについて
AddressBookとContactsについて
• どちらにもUIとsuffixが付いているフレームワークがあり、連絡先の追加、参照、削除をする画面を提供している
• CNContactPickerViewControllerを生成し、presentViewControllerをするだけで簡単に使用できる
ContactsUI
let contactPickerViewController = CNContactPickerViewController() contactPickerViewController.delegate = self self.presentViewController( contactPickerViewController, animated: true, completion: nil)
• 一覧表示
• グループ
•詳細表示
•複数選択
地味…
What's New in iOS 9.0• AddressBookフレームワークがiOS 9からdeprecatedに
• AddressBookUIの方もdeprecatedに
• 現時点ではiOS 9でも使えないこともない…
What's New in iOS 9.0
• iOS 9でContactsフレームワークが追加された
• iOS 9からしか使用できない
• iOS 8以下もサポートする場合はAddressBookと共存させなければならない
AddressBookでは⚪⚪だったものが Contactsではxxになる、
といった観点で説明いたします。
AddressBook
• iOS専用の連絡先アクセスAPI
• Mac用は別に存在する
• Objective-C / Swift両方使用可能
• You must ensure that an instance of ABAddressBookRef is used by only one thread.
AddressBook
• CoreFoundation…
メモリリーク怖い…
Contacts
• iOS / Macの連絡先アクセスAPI
• watchOS 2に対応
• Objective-C / Swift両方使用可能
• thread-safe(fetch & save)
Contacts
3. Privacyについて
Privacy
連絡先アクセス許可状態を取得
let status = CNContactStore.authorizationStatusForEntityType(.Contacts)
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
• AddressBook
• Contacts
AddressBook Contacts ステータス
CNAuthorizationStatusNotDetermined NotDetermined 許可/不許可問い合わ
せ前
CNAuthorizationStatusRestricted Restricted
管理者より機能制限 (ユーザー、アプリによる変更は不可)
CNAuthorizationStatusDenied Denied ユーザーによって不許
可
CNAuthorizationStatusAuthorized Authorized ユーザーによって許可
されている
AddressBook• 連絡先アクセスの許可をユーザーに問い合わせる
CFErrorRef cfError = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &cfError); ABAddressBookRequestAccessWithCompletion( addressBook, ^(bool inGranted, CFErrorRef inCfError) { NSLog(@"inGranted: %d", inGranted); });
Contacts
• 連絡先アクセスの許可をユーザーに問い合わせる
let store = CNContactStore() store.requestAccessForEntityType( .Contacts, completionHandler:{ (granted: Bool, error: NSError?) -> Void in print("granted: \(granted)") })
確認用のアラート
• 許可は設定>プライバシー>連絡先で変更可能
4. Fetchの違いについて
AddressBook• RecordIDを指定して取得
• 名前から検索(ABAddressBookCopyPeopleWithName)
Contacts• CNContact.identifierを指定して取得
• 名前から検索(unifiedContactsMatchingPredicate)
連絡先データベースの作成
Contacts
AddressBookCFErrorRef cfError = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &cfError);
let store = CNContactStore()
AddressBook• RecordIDを指定して取得
• RecordIDはAddressBookデータベースに書き込まれた一意の値
• 型はint 32
int32_t recordId = (int32_t)recordIdNumber.intValue; ABRecordRef person = ABAddressBookGetPersonWithRecordID( addressBook, recordId);
Contacts• CNContact.identifierを使用して取得
• String型
• AddressBookのRecordIDと互換性がない
let identifier = "035218FA-1E6E-4D1C-9708-76FBC0E55F28"
let contact = try store.unifiedContactWithIdentifier( identifier, keysToFetch:[ CNContactGivenNameKey, CNContactFamilyNameKey])
AddressBook• 名前から検索
• 「姓」「姓読み」「名」「名読み」のどれか該当するものをFetchする
• 戻り値はCFArrayRef…
NSString *name = @"Appleseed";
CFArrayRef contacts = ABAddressBookCopyPeopleWithName( addressBook, (__bridge CFStringRef)name);
Contacts• 名前から検索(unifiedContactsMatchingPredicate)
• keysToFetchにはFetchしてきたいプロパティのキーを指定
let predicate = CNContact.predicateForContactsMatchingName( “Appleseed") let contacts = try store.unifiedContactsMatchingPredicate( predicate, keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey])
Contacts• keysToFetchに指定していないプロパティへはアクセスできない
let predicate = CNContact.predicateForContactsMatchingName( "Appleseed") let contacts = try store.unifiedContactsMatchingPredicate( predicate, keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey]) let contact = contacts.first print("\(contact!.identifier) \(contact!.givenName) \(contact!.familyName) \(contact!.phoneNumbers)")
Contacts
• アクセスする前にキーが指定されているかをチェックする
if contact!.isKeyAvailable( CNContactPhoneNumbersKey) {
Contacts• フルネームを取得する際KeysToFetchに全て指定しない
let contacts = try store.unifiedContactsMatchingPredicate( predicate, keysToFetch:[ CNContactGivenNameKey, CNContactFamilyNameKey, CNContactNamePrefixKey, CNContactMiddleNameKey, CNContactNameSuffixKey, CNContactPhoneNumbersKey])
Contacts
• CNContactFommatterを使用する
let contacts = try store.unifiedContactsMatchingPredicate( predicate, keysToFetch[ CNContactFormatter. descriptorForRequiredKeysForStyle(.FullName), CNContactPhoneNumbersKey])
比較
AddressBook Contacts
データベース ABAddressBookRef CNContactStore
連絡先 ABRecordRef CNContact
グループ ABRecordRef CNGroup
各プロパティ対応AddressBook Contacts
FirstName(Takaaki) kABPersonFirstNameProperty givenName
LastName(Tanaka) kABPersonLastNameProperty familyName
MiddleName(F) kABPersonMiddle NameProperty middleName
Prefix(Mr.) kABPersonPrefix Property namePrefix
Suffix(Jr.) kABPersonSuffix Property nameSuffix
Nickname kABPersonNicknameProperty nickname
• Conctacs.frameworkからはFetchしてくる必要があるプロパティはキーを指定しなければならない
• AddressBookでIDから検索するロジックを実装している場合はマイグレーション処理等でContact.identifierに置き換える必要がある
5. 連絡先の編集の違い
AddressBook• 新規追加の場合(全体)
CFErrorRef cfError = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &cfError); if (!addressBook) { NSError *error = (__bridge_transfer NSError *)cfError; NSLog(@"%s: %@", __PRETTY_FUNCTION__, error); } ABRecordRef person = ABPersonCreate();
ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFTypeRef)@"John", &cfError); ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFTypeRef)@"Appleseed", &cfError); ABAddressBookAddRecord(addressBook, person, &cfError);
ABAddressBookSave(addressBook, &cfError);
AddressBook
• ABAddressBookRefを作成する
CFErrorRef cfError = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions( NULL, &cfError); if (!addressBook) { NSError *error = (__bridge_transfer NSError *)cfError; NSLog(@"%s: %@", __PRETTY_FUNCTION__, error); }
AddressBook
• ABRecordRefを取得する
ABRecordRef person = ABPersonCreate();
ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFTypeRef)@"John", &cfError); ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFTypeRef)@"Appleseed", &cfError);
• 必要なプロパティをセットする
AddressBook• MultiValueを追加する場合
CFErrorRef cfError = NULL; ABMultiValueIdentifier identifier; ABMultiValueRef multiTel = ABMultiValueCreateMutable(kABMultiStringPropertyType);
CFStringRef label1 = kABPersonPhoneMainLabel; NSString *value1 = @"012-345-6789"; ABMultiValueAddValueAndLabel( multiTel, (__bridge CFTypeRef)(value1), label1, &identifier); CFStringRef label2 = kABPersonPhoneIPhoneLabel; NSString *value2 = @"111-222-3333"; ABMultiValueAddValueAndLabel( multiTel, (__bridge CFTypeRef)(value2), label2, &identifier); ABRecordSetValue( person, kABPersonPhoneProperty, multiTel, &cfError); CFRelease(multiTel);
AddressBook
• AddressBookに対する操作を指定する
• AddressBookに対するセーブを実施する
ABAddressBookAddRecord( addressBook, person, &cfError);
ABAddressBookSave(addressBook, &cfError);
Contacts
• 新規追加の場合(全体)
let store = CNContactStore()
let contact = CNMutableContact() contact.givenName = "John" contact.familyName = "Appleseed"
let saveRequest = CNSaveRequest() saveRequest.addContact(contact, toContainerWithIdentifier:nil) do { try store.executeSaveRequest(saveRequest) } catch { abort() }
Contacts• CNContactStoreを取得
• CNMutableContactを取得する
let store = CNContactStore()
let contact = CNMutableContact()
Contacts
• 必要なプロパティをセットする
contact.givenName = "John" contact.familyName = "Appleseed"
Contacts• MultiValueを追加する場合
let mainNumber = CNLabeledValue( label:CNLabelPhoneNumberMain, value:"012-345-6789")
let iPhoneNumber = CNLabeledValue( label:CNLabelPhoneNumberiPhone, value:"111-222-3333") contact.phoneNumbers = [mainNumber, iPhoneNumber]
Contacts
• CNSaveRequestへデータベースへの操作を指定する
• CNContactStoreに対してセーブを実施する
let saveRequest = CNSaveRequest() saveRequest.addContact( contact, toContainerWithIdentifier:nil)
try store.executeSaveRequest(saveRequest)
Contacts Changed Notifications
• CNContactStoreDidChangeNotification
• CNContactStoreに変更があった際にNSNotificationCenterから通知を受ける
まとめ
• 新規作成、編集、削除ロジック部分はあまり変更はない
• Fetchのしかたに変更はあるが、大幅な変更はない
• RecordIDとIdentifierに互換性がない
• Contacts.frameworkはiOS 9以降でしか使用できない
• AddressBookを使用している場合はContactsでも同じロジックで実装し、iOS 8のサポート切れのタイミングで切り離せるようにするほうが良い
if #available(iOS 9.0, *) {
ありがとうございました