ユーザー情報を保存するために第三者のデータベースを使用していますか?iOSプラットフォーム向けだけに開発しているなら、"CloudKit" を "Sign in with Apple" と一緒に使用することを検討してはいかがでしょう。
短時間で77行のコードを使って、ユーザーログイン/登録の機能をiOSアプリに追加できます。
何ができるでしょうか?
- ユーザーは、“Sign in with Apple” を使ってあなたのアプリに登録できます。
- 登録後、ユーザーはどのデバイス(同じApple IDでサインインされている物)からでもサインインできて、あなたは氏名、Eメール、その他保存したユーザー情報を取得することが可能です。
早速始めてみましょう
ステップ1. Xcodeプロジェクト設定で必要な機能をオンにする。“iCloud”の"CloudKit”をオンにする。
「CloudKit」をオンにします
既存の"Containers"のトグルボタンをどれかひとつクリックするか、プラスアイコンをクリックして新規"Container"を加える。
新規"Container"を加える:
追加ボタンをクリックします
新しい「Container」の名前を入力してください

ステップ2. ユーザー情報を保存するため、CloudKitのデータ構造を設定する。
-
次に"CloudKit Dashboard"ボタンをクリックするか、http://icloud.developer.apple.com へ行く。
-
パネル左側にある自分のアプリケーション名をクリックする。
-
"Schema" をクリックします
"New Type" をクリックします
タイプに「userInfo」という名前を付けて選択します
右側の[Add field button]ボタンをクリックして、次の新しいフィールドを追加します
「emailAddress」と「name」はどちらも「String」です

ステップ 3. “Sign in with Apple” 機能を追加する (Appleでサインイン)
“Capabilities” タブは次のようになります:
コードはこのページの下部にあります
ステップ 4. 新しいloginViewControllerを作成します
import Foundation
import UIKit
class loginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
必要なフレームワークをインポートする
import AuthenticationServices
import CloudKit
“Sign in with Apple button”(Appleでサインインのボタン)に、プログラム上の参照を追加しましょう。
@IBOutlet weak var signInBtnView: UIView!
var authorizationButton: ASAuthorizationAppleIDButton!
ここでは、"signInBtnView" という既存ビューにサインインボタンを加えます。ここでは "UIStoryBoard" を使ってAを追加しています。
このボタンをあなたのプログラムのビューに加えましょう("UIView")。
override func viewDidLoad() {
super.viewDidLoad()
authorizationButton = ASAuthorizationAppleIDButton(type: .default, style: .whiteOutline)
authorizationButton.frame = CGRect(origin: .zero, size: signInBtnView.frame.size)
authorizationButton.addTarget(self, action: #selector(handleAppleIdRequest), for: .touchUpInside)
signInBtnView.addSubview(authorizationButton)
}
ボタンがクリックされた際に実行するアクションを処理する
@objc func handleAppleIdRequest(){
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.performRequests()
}
結果やエラーメッセージを受け取るには "delegate"(デリゲート)を設定しましょう。
extension loginViewController: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
//成功
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
//失敗した
print(error.localizedDescription)
}
これで「Sign in with Apple」の運用が開始されたはずです。手元のシミュレータで試して下さい!
ただし、まだ以下の手続きが必要です:
- サインインでユーザー情報を取得する。
- 「iCloud」への情報のアップロードと
- 「iCloud」からの情報の取得。
サインインからの情報取得
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userID = appleIDCredential.user
let name = appleIDCredential.fullName?.givenName
let emailAddr = appleIDCredential.email
}
}
ここで重要な情報です:
-
ユーザーがあなたのアプリで初めて"A"を使った場合、あなたはそのユーザーID、氏名、Eメールアドレスを受け取ります。その情報を保存する"B"については、この記事の後の方で扱います。
-
ユーザーが戻ってきた場合(登録ではなくサインインしている場合)、あなたは"userID"だけを受け取ります。"A"についてはこの記事の後の方で扱い、userIDを使って氏名とEメールを取得する方法を学びます。
-
ひとりのユーザーの"userID"は、常に同じです。
ユーザーが登録(新規ユーザー)するのか、サインインするのか、確認しましょう。
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userID = appleIDCredential.user
if let name = appleIDCredential.fullName?.givenName,
let emailAddr = appleIDCredential.email {
//新規ユーザー(登録)
//この情報を「CloudKit」に保存
} else {
//既存ユーザー(サインイン)
//ユーザー名/メールアドレスの取得
}
}
}
ステップ 5. CloudKit (iCloud)
データベースには3種類あることに注意してください。本記事では「privateDatabase(プライベートデータベース)」を使っているので、ユーザーのデータにアクセスできるのはユーザー本人のみとなります。
//TODO: アプリiCloudコンテナーの名前 (ステップ 1)
let privateDatabase = CKContainer(identifier: "iCloud.com.[アプリiCloudコンテナーの名前]").privateCloudDatabase
氏名とEメールを受け取った場合(ユーザーが登録しているということ)、新しい"CloudKit"記録を作成できます:
「recordID」は「Appleでサインイン」から取得した「userID」と同じになるように割り当てているため、後でユーザーのCloudKitレコードを取得できます。
//新規ユーザー(登録)
//この情報を「CloudKit」に保存
let record = CKRecord(recordType: "UserInfo", recordID: CKRecord.ID(recordName: userID))
record["name"] = name
record["emailAddress"] = emailAddr
//保存する他の情報を追加できます
privateDatabase.save(record) { (_, _) in
UserDefaults.standard.set(record.recordID.recordName, forKey: "userProfileID")
リピートユーザーの場合、"CloudKit" から名前とメールアドレスを取得します:
//既存ユーザー(サインイン)
//ユーザー名/メールアドレスの取得
privateDatabase.fetch(withRecordID: CKRecord.ID(recordName: userID)) { (record, error) in
if let fetchedInfo = record {
let name = fetchedInfo["name"] as? String
let userEmailAddr = fetchedInfo["emailAddress"] as? String
//読むべきその他の情報: fetchedInfo[その他の情報] as? String
//TODO: ユーザー名とメールアドレスを使用できるようになりました(例:ローカルに保存)
print("名前: \(name) 電子メールアドレス: \(userEmailAddr)")
UserDefaults.standard.set(name, forKey: "userName")
}
完成したコードはこのリンクの先にあります: https://github.com/mszopensource/CloudKitAppleSignInExample/blob/master/loginViewController.swift
import Foundation
import UIKit
import AuthenticationServices
import CloudKit
class loginViewController: UIViewController {
@IBOutlet var signInBtnView: UIView!
var authorizationButton: ASAuthorizationAppleIDButton!
override func viewDidLoad() {
super.viewDidLoad()
authorizationButton = ASAuthorizationAppleIDButton(type: .default, style: .whiteOutline)
authorizationButton.frame = CGRect(origin: .zero, size: signInBtnView.frame.size)
authorizationButton.addTarget(self, action: #selector(handleAppleIdRequest), for: .touchUpInside)
signInBtnView.addSubview(authorizationButton)
}
@objc func handleAppleIdRequest(){
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.performRequests()
}
}
extension loginViewController: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
//TODO: アプリiCloudコンテナーの名前
let privateDatabase = CKContainer(identifier: "iCloud.com.[アプリiCloudコンテナーの名前]").privateCloudDatabase
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userID = appleIDCredential.user
if let name = appleIDCredential.fullName?.givenName,
let emailAddr = appleIDCredential.email {
//新規ユーザー(登録)
//この情報を「CloudKit」に保存
let record = CKRecord(recordType: "UserInfo", recordID: CKRecord.ID(recordName: userID))
record["name"] = name
record["emailAddress"] = emailAddr
privateDatabase.save(record) { (_, _) in
UserDefaults.standard.set(record.recordID.recordName, forKey: "userProfileID")
}
} else {
//既存ユーザー(サインイン)
//ユーザー名/メールアドレスの取得
privateDatabase.fetch(withRecordID: CKRecord.ID(recordName: userID)) { (record, error) in
if let fetchedInfo = record {
let name = fetchedInfo["name"] as? String
let userEmailAddr = fetchedInfo["emailAddress"] as? String
//TODO: ユーザー名とメールアドレスを使用できるようになりました(例:ローカルに保存)
print("名前: \(name) 電子メールアドレス: \(userEmailAddr)")
UserDefaults.standard.set(userID, forKey: "userProfileID")
}
}
}
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
print(error.localizedDescription)
}
}
これでうまくいくはずです!
その他のタイプのユーザー情報の保存
データベースにはその他の情報も保存できます。例えば、ユーザーが好きな動物一覧を保存することができます。
まず、データベースの「スキーム」に「フィールド」を追加する必要があります。本記事の序盤ですでにその方法を解説しました。例として「likedAnimals(好きな動物)」というフィールドを新規追加したいことにしましょう。


ユーザーのIDをローカルストレージに保存している場合、このコードでユーザーが好きな動物を取得できます。
func getUserLikedAnimals() {
let privateDatabase = CKContainer(identifier: "iCloud.com.[アプリiCloudコンテナーの名前]").privateCloudDatabase
if let userCloudID = UserDefaults.standard.string(forKey: "userProfileID") {
let recordID = CKRecord.ID(recordName: userCloudID)
privateDatabase.fetch(withRecordID: recordID) { (fetchedRecord, error) in
if error == nil {
let likedAnimals = fetchedRecord?.value(forKey: "likedAnimals") as? [String]
//TODO
} else {
print(error?.localizedDescription)
}
}
}
}
データベース上のユーザーの記録に動物名を新規追加する場合は、このコードを使用します。
func updateUserLikedAnimals(newAnimal: String) {
let privateDatabase = CKContainer(identifier: "iCloud.com.[アプリiCloudコンテナーの名前]").privateCloudDatabase
if let userCloudID = UserDefaults.standard.string(forKey: "userProfileID") {
let recordID = CKRecord.ID(recordName: userCloudID)
privateDatabase.fetch(withRecordID: recordID) { (record, error) in
guard let fetchedRecord = record else { return }
if error == nil {
var likedAnimals = fetchedRecord.value(forKey: "likedAnimals") as? [String] ?? []
likedAnimals.append(newAnimal)
//更新記録
privateDatabase.save(fetchedRecord) { (modifiedRecord, error) in
if error != nil {
//失敗
print(error?.localizedDescription)
} else {
//成功
}
}
} else {
print(error?.localizedDescription)
}
}
}
}
最後にはiCloudの開発用データベースを本番環境にデプロイする必要があります。
