Facebookログインが必要なiPhoneアプリはたくさんあり、大抵のアプリケーションはFacebookのiPhoneアプリと連携してパスワード入力無しでログインを済ませてくれるのでユーザーとしてはとても楽だ。
だけど、Facebookアプリを使わずに自アプリ内でWebViewを開いて、そこでメールとパスワードを入力しなければいけないフローになっているアプリもそれなりに見かける。
僕の場合は各種サービスのパスワードは管理ツールで自動生成していて覚えていない。Macの場合は管理ツールが常時立ち上がっているのですぐに参照できるが、iPhoneの場合は、管理アプリを立ちあげる→マスターパスワードを入力→目的のサイトを選択→パスワードをコピー→元のアプリに戻る、という手順を踏まなければならないため、非常に使い勝手が悪い。
というか、Facebookアプリが認証の仕組みを提供しているのにそれを実装してないアプリはろくなもんじゃない。実装自体そんなに難しいものでもないはずなので、開発者の怠慢でしかないと僕は思う。
やったことないけど。
Facebookアプリを使った認証機能を実装する
やったことない、じゃダメだと思うのでやってみた。
きちんとした公式ドキュメントがあるのでこちらを参照すれば十分だが、せっかくなので試したプロセスを記録しておく。
Facebook側での事前準備
アプリケーションを登録する
Facebookの開発者用ページに飛んでアプリケーションを作る。今から作ろうとしているiPhoneアプリのためのIDみたいなものだ。
開発者ページのナビゲーションからCreate a New App
のリンクをクリックする。
次のようなフォームが出てくるので適当に入力する。今回はDisplay NameをLoginTest
、Namespaceをfblogintest
とした。
Is this a test version of another app?
はいいえ
のまま、カテゴリは今から作ろうとしているアプリケーションに合ったものにすればいいが、今回はとりあえずユーティリティを選んでおいた。
アプリ作成が終わるとDashboardが表示される。
アプリケーションの設定
↑で作ったアプリケーションに対して、少しだけ設定が必要。
管理画面の左側Settings
メニューを選び、その先でAdd Platform
をクリックし、iOSを選ぶ。
新しく現れたフォームでは、これから作るiPhoneアプリのバンドルIDのところと、Single Sign On
のところを変更する。他の欄は当面は空白で良さそう。
Xcodeプロジェクトを作る
プロジェクトを新規作成し、SDKの導入やplistの設定を行う。
Facebook SDKの導入
開発者向けサイトからダウンロードする方法もあるが、今はCocoaPodsが便利。
# Podfile
pod 'Facebook-iOS-SDK'
% pod install
plistを編集する
{プロジェクト名}-Info.plist
にいくつか追記する必要がある。この情報が間違っていると正しく動かなかったり、アプリケーションがクラッシュしたりする。
FacebookAppID
→ アプリケーション管理画面のAppIDFacebookDisplayName
→ アプリケーション作成時に入力したDisplayNameURL types
URL Schemes
→ “fb” + AppID
アプリを実装する
開発者向けドキュメントにあるようなログインしてユーザー名を表示する程度のサンプルを実装してみる。
Storyboardでコントロールを配置する
次の図のようにコントロールを配置した。UILabelを2つとUIViewが2つ。ラベルは現在の状態やユーザー名を表示するためのもので、UIViewはSDKのFBLoginViewやFBProfilePictureViewをカスタムクラスとして使う。
ちなみにカスタムクラスはstoryboardのインスペクタで指定することができる。
コードからも呼びたいのでプロパティとも紐付けておく。
bjc
#import <UIKit/UIKit.h>
#import <FacebookSDK.h>
@interface ViewController : UIViewController<FBLoginViewDelegate>
@property (weak, nonatomic) IBOutlet FBLoginView *loginView;
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet FBProfilePictureView *profilePictureView;
@end
追記
StoryboardでFBLoginView
などのクラスを参照すると、実行時にクラスが見つからないという警告が出てしまう場合がある。そういう場合は起動時に対象のクラスを一度ロードさせてやると良いらしい。
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[FBLoginView class];
...
return YES;
}
追記ここまで
今回はStoryboardを使ったが、コードでUIを定義することももちろん可能。
パーミッションの設定
機能に応じて今から作るアプリがどんな権限を持つかを指定する必要がある。連携確認画面でこのアプリにはコレとアレとソレを許可しますみたいなリストは見たことがあるはず。
パーミッションは初期化のときに指定するのがいい。今回はViewController.mのviewDidLoad
あたりで書いておく。
- (void)viewDidLoad
{
[super viewDidLoad];
self.loginView.readPermissions = @[@"public_profile", @"email", @"user_friends"];
}
↑の例では、公開プロフィール、メールアドレス、友達一覧へのアクセス権を要求している。
URLスキームの処理を書く
URLスキームを使ってFacebookの公式アプリと連携することになるため、連携のためのコードを書く必要がある。これはドキュメントに書いてるコードをそのまま貼り付ければ良い。
// AppDelegate.m
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// Call FBAppCall's handleOpenURL:sourceApplication to handle Facebook app responses
BOOL wasHandled = [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
// You can add your app-specific url handling code here if needed
return wasHandled;
}
連携時のDelegateを実装する
続いてログイン成功時や、ログアウト時、エラー時などの処理を担当するDelegateメソッドを実装していく。
実装するメソッドは次の4つ。
loginViewFetchedUserInfo:user:
公開プロフィールを取ってきたときloginViewShowingLoggedInUser:
ログイン中の表示をするときloginViewShowingLoggedOutUser:
ログアウト中の表示するときloginView:handleError:
エラーが起こったとき
まず、ViewController.hでFBLoginViewDelegateプロトコルを継承する。
// ViewController.h
#import <FacebookSDK.h>
@interface ViewController : UIViewController<FBLoginViewDelegate>
@end
次に、ViewController.mにDelegateの実装を書く。
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user
{
self.profilePictureView.profileID = [user objectID];
self.nameLabel.text = user.name;
}
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView
{
self.statusLabel.text = @"You're logged in as";
}
- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView
{
self.statusLabel.text = @"You're not logged in!";
self.profilePictureView.profileID = nil;
self.nameLabel.text = @"";
}
// loginView:handleError: は長いので省略
やってみた感想
とまあこんな具合で実装できた。
図入りで書くと長くなったが、やってみた感じはだいぶ楽だった。冒頭に書いたとおり、WebViewでログインさせようとするアプリの開発者は怠慢だと言っていいと思う。