PIYO - Tech & Life -

iOSでFacebook連携ログインするアプリを作る手順まとめ

Facebookログインが必要なiPhoneアプリはたくさんあり、大抵のアプリケーションはFacebookのiPhoneアプリと連携してパスワード入力無しでログインを済ませてくれるのでユーザーとしてはとても楽だ。

だけど、Facebookアプリを使わずに自アプリ内でWebViewを開いて、そこでメールとパスワードを入力しなければいけないフローになっているアプリもそれなりに見かける。

僕の場合は各種サービスのパスワードは管理ツールで自動生成していて覚えていない。Macの場合は管理ツールが常時立ち上がっているのですぐに参照できるが、iPhoneの場合は、管理アプリを立ちあげる→マスターパスワードを入力→目的のサイトを選択→パスワードをコピー→元のアプリに戻る、という手順を踏まなければならないため、非常に使い勝手が悪い。

というか、Facebookアプリが認証の仕組みを提供しているのにそれを実装してないアプリはろくなもんじゃない。実装自体そんなに難しいものでもないはずなので、開発者の怠慢でしかないと僕は思う。

やったことないけど。

Facebookアプリを使った認証機能を実装する

やったことない、じゃダメだと思うのでやってみた。

きちんとした公式ドキュメントがあるのでこちらを参照すれば十分だが、せっかくなので試したプロセスを記録しておく。

Facebook側での事前準備

アプリケーションを登録する


Facebookの開発者用ページに飛んでアプリケーションを作る。今から作ろうとしているiPhoneアプリのためのIDみたいなものだ。

Facebook Developers

開発者ページのナビゲーションから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 → アプリケーション管理画面のAppID
  • FacebookDisplayName → アプリケーション作成時に入力したDisplayName
  • URL 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でログインさせようとするアプリの開発者は怠慢だと言っていいと思う。