はじめに
Titanium SDK 3.1以降、Titianium.Facebookモジュールではなく、Modules.Facebookに変更になってます。(詳しくは公式サイトを)
モジュールの導入時のセットアップで多少異なる点があるけど基本的な使い方としては大きな変更は無くその点での戸惑いはなかったのですが、Modules.Facebookを利用してACSへのユーザーログインでFacebookアカウントを利用する処理方法について情報がまとまっておらず、仕事で必要だったので調べたものをまとめることにしました。
想定する方
一応以下のような方を想定してまとめてみました。
- Titanium Mobileでサンプルコードを書いたことはある
- ACSという言葉は聞いたことがある
- OAuthの概念はなんとなく知ってる
やりたいことはシンプルなのですがそれに関連するベースの知識が色々問われてくるため関連情報を以下簡単にまとめておきます
OAuthがわかりづらい人向けに
昔まとめたスライドがあってそのキャプチャー貼っておきます
ACSについて補足情報
- ACSというのはTitanium Mobileの開発元であるAppceleratorが提供してるMBaaS(Mobile Backend as a Service)です。
- MBaaSとしてはFacebookが買収したParseが最も有名なサービスです
- Parseの解説記事ですがQiitaのこちらのものを読むと、MBaaSが何なのか、どんなことが出来るのか概要がつかめると思います。
- AppceleratorCloudServicesの頭文字を取ってACSという言い方がよくされてます。ただ大分まえに名称がTitanium Cloud Servicesになってるので、TCSという言い方のほうが正しいのかな??
- ACSの詳細は、英語ですが公式サイトをご覧ください
開発環境
- Mac OS X 10.9.5
- Titanium SDK 3.3.0.GA
- XCode 5.1.1
- alloy 1.4.1
開発前に必要な準備
プロジェクト設定
今回、ACSを利用するのでそれに合わせてプロジェクト設定を行います。
TitaniumのFacebookモジュールの読み込み設定
プロジェクト設定完了後にtiapp.xmlを以下のように編集します
編集前
<modules>
<module platform="commonjs">ti.cloud</module>
</modules>
編集後
<modules>
<module platform="commonjs">ti.cloud</module>
<module platform="iphone">facebook</module>
</modules>
Alloy用の ACS Sync Adapter の配置
- PROJECT_FOLDER/app/assets配下に、alloyフォルダを作成して、その中にsyncフォルダを作成します
- 上記フォルダ配下にacs.jsというファイルを作成します
- aaronksaunders さんが作ったacs.jsのソースコードを上記2.で作成したacs.jsにコピペします
Facebook アプリID
これはTitaniumでの開発固有の話ではないのですが、Facebookと連携するアプリ開発をする場合にこの作業が必須になります。
開発者ページに行きます
今回はiOS向けアプリなのでこちらを選択
右上のリンクをクリックします
AppID登録に必要な内容を入力します
登録時に必要なセキュリティチェックの文字を入力します
登録完了
画面キャプチャーでは消去してますがここにAppIDが数字で記載されてるのでそれを控えておきます
ソースコードの概要
このページの最後にソースコード全体を記載しておきましたがAlloyのModelの処理とControllerの処理でちょっとハマり所があったのでその辺りちょっとだけ書いておきます
Modelの処理
Cloud.SocialIntegrations.externalAccountLoginを利用できるアダプターを準備します。
ソースコード全体は後述しますがポイントになる所の処理を抜粋します
// 省略
extendModel: function(Model) {
_.extend(Model.prototype, {
fbLogin: function(token, email, birthday){
this.config.Cloud.SocialIntegrations.externalAccountLogin({
type: 'facebook',
token: token,
email: email, // (1)
custom_fields: {
birthday: birthday // (2)
}
}, function (e) {
// 省略
});
}
});
return Model;
}
- Web上で見かけるサンプルコードでは見かけなかったのですが、こういう感じでemailプロパティに、設定したいメールアドレスの情報を指定してあげることで、SocialIntegrations.externalAccountLoginの情報に対してメールアドレスの設定を行うことが出来ます。
- ACSのUserオブジェクトにはメールアドレスの設定項目が元々有るのですが、例えば誕生日のような項目は存在していません。その場合にはカスタムフィールドという仕組みを通じ独自の項目を設定することが出来ます。このような記述をしてあげることでカスタムフィールドに、birthdayという項目を設定して、任意の値を設定できます
Controllerの処理
Facebookアカウントを利用した認可処理のサンプルコードはWeb上にいくつもあったのですが、
- Facebookアカウントでのユーザー認証処理
- ユーザー認証が終わったあとに、このアプリがあなたのxxにアクセスしますがよろしいでしょうか?というよくみる認可のポップアップ処理
という処理の区分けをどこでどのようにしてるのかがわからずに大分苦労しました。
しかも、TitaniumのModules.Facebookの仕組みを通じて、login/logoutのイベントがあるようだったので、ログインという言葉の印象から、その段階でFacebookのアカウントの属性情報をすべて取得してるのかとおもったらそれはまた別処理になるようでこの辺りがかなりハマり所かなと個人的には思いました。
Facebookの情報にアクセスするために必要な各種設定を行う
var fb = require('facebook');
fb.appid = Ti.App.Properties.getString('ti.facebook.appid') // (1);
fb.permissions = ['publish_stream','email','user_birthday']// (2);
fb.forceDialogAuth = false;
- 今回のサンプルでは取得したFacebookのappidをtiapp.xml内にti.facebook.appidというプロパティ名で記述してます。
- 今回作成するアプリから、Facebookアカウントの情報へのアクセスする時に、publish_streamだけだと、氏名程度しか取得できないため、permissionsの項目にemailとuser_birthdayという項目を追加します
ログインイベント発火した時の処理を書く
fb.addEventListener('login', function(e) {
if (e.success) {
fb.requestWithGraphPath('me',{},"GET",function(e) {
// 省略
);
} else if (e.error) {
Ti.API.info(e.error);
} else if (e.cancelled) {
Ti.API.info("Canceled");
}
});
ログインボタン的なものを準備
iconというID属性を付与したButton要素を配置しておき、クリックイベントで、Facebookの認可処理を開始する処理を呼び出します
$.icon.addEventListener('click', function(e) {
fb.authorize();
});
ソースコード全体
controllers/index.js
var fb = require('facebook');
fb.appid = Ti.App.Properties.getString('ti.facebook.appid');
fb.permissions = ['publish_stream','email','user_birthday'];
fb.forceDialogAuth = false;
fb.addEventListener('login', function(e) {
if (e.success) {
fb.requestWithGraphPath('me',{},"GET",function(e) {
if (e.success) {
var obj = JSON.parse(e.result),
moment = require('alloy/moment'),
token, user, email, birthday;
email = obj.email;
birthday = moment(obj.birthday, "MM/DD/YYYY");
token = fb.accessToken;
Ti.API.info("Success: " +
"email" + email +
"birthday" + birthday +
"token" + token
);
user = Alloy.createModel('social');
user.fbLogin(token,email, birthday);
}
}
);
} else if (e.error) {
Ti.API.info(e.error);
} else if (e.cancelled) {
Ti.API.info("Canceled");
}
});
$.fbloginLabel.addEventListener('click', function(e) {
fb.authorize();
});
$.index.open();
models/social.js
exports.definition = {
config: {
columns: {
active: "boolean"
},
adapter: {
type: "acs",
collection_name: "socialIntegrations"
},
settings: {
object_name: "socialIntegrations",
object_method: "socialIntegrations"
}
},
extendModel: function(Model) {
_.extend(Model.prototype, {
fbLogin: function(token, email, birthday){
this.config.Cloud.SocialIntegrations.externalAccountLogin({
type: 'facebook',
token: token,
email: email,
custom_fields: {
birthday: birthday
}
}, function (e) {
if (e.success) {
var user = e.users[0];
Ti.API.info('Success:\n' +
'id: ' + user.id + '\n' +
'first name: ' + user.first_name + '\n' +
'last name: ' + user.last_name);
} else {
Ti.API.info('Error:\n' +
((e.error && e.message) || JSON.stringify(e)));
}
});
}
});
return Model;
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {});
return Collection;
}
};
index.xml
<Alloy>
<Window class="container">
<Label id="fbloginLabel">Facebookでログイン</Label>
</Window>
</Alloy>
index.tss
".container": {
backgroundColor:"white"
},
"#fbloginLabel": {
top:"40%",
left:"30%",
width:"60%",
height:"10%"
}
"#icon" :{
top:"40%",
left:"5%",
image: "facebook-icon.png"
}
tiapp.xml
tiapp.xmlの中にFacebookのappidを記載しておきます
<property name="ti.ui.defaultunit" type="string">dp</property>
<!-- ここから追加箇所 -->
<property name="ti.facebook.appid">xxxxxxxxxxx</property>
<!-- ここまで追加箇所 -->
終わりに
OAuthについての理解&それをTitaniumのモジュールを使った場合にどのように実装するのかという所について何かの参考になればと思ってまとめてみました。
自分自身でOAuthの概念は理解してるつもりなのですが、文章にまとめて気づいたこととして、Module.Facebookの機能が自分の想像してるものと一部異なる印象があるためどうもこの辺りが要因になってなかなか理解が進まないのかなとふと思いました