読者です 読者をやめる 読者になる 読者になる

IwamotoBlog

俺に付いて来い

Unityで叩くTwitter,Facebook API

Unity

この記事は CAMPHOR- Advent Calendar 2015 8日目の記事です。

「イケてるSNSクライアントアプリを作ろう」と言われた時、皆さんは何で開発しますか?
Swift?Java?それも良いかもしれないですね。ですが、敢えて言わせていただきましょう。それ、学習コスト高くないですか?
言語だけでなく、IDEにさえ高い学習コストが求められるこれらは、多くの場合志半ばでの挫折を招いてしまうでしょう。
ここでの最もNiceな回答をお教えします。「Unity」それが正解です。
学習コストが極めて低いUnityで開発すればSNSクライアント程度、3日もあれば完成するでしょう。
ということで本日は、UnityからTwitterFacebookAPIを叩く方法を皆様に伝授しようと思います。

UnityでTwitter

まず、Twitterのやり方からご説明して行きましょう。

インポート

以下のAssetを使用します。

Let's Tweet In Unity

適当なプロジェクトを作成し、AssetStoreでこのAssetを探してインポートして下さい。
インポートするとこんな感じになるはずです。

f:id:PEPOipod007:20151207143059p:plain

これらのファイルがAssets/直下にあるのが少し気持ち悪いので、Assets/Plugins/LetsTweetInUnity/のようなディレクトリを作り、移動させると良いでしょう。

ライブラリの修正

さて早速このAssetを使っていきたいのですが、Let's Tweet In Unityはインポート直後にエラーを吐くステキ仕様になっております。涙がちょちょぎれますね。
どうも、Let's Tweet In UnityではWWWクラスのコンストラクタ引数headersHashTable型を使用しているようです。これは今まで非推奨として扱われていたのですが、どうやらいつの間にかHashTable型を許容しない仕様になっていたようですね。(各所文献を見た感じでは、割と最近の出来事のようです)

諸行無常。変わってしまったものは仕方ないので、HashTable型のheaderDictionary<string, string>型に変換してあげましょう。
以下のようにTwitter.csを書き換えてください。

136行目, 149行目, 194行目

//var headers = new Hashtable();
Dictionary<string, string> headers = new Dictionary<string, string>();

これでOKです。各行それぞれ同じように書き換えてください。
書き換えて保存すると無事エラーが消えるはずです。

テストシーンの作成

エラーも修正できたところでAPIをテストするためのSceneを作成していきましょう。適当にTwitterAPITestのようなSceneを作成すると良いでしょう。
作成出来たら、GameObjectを配置していきます。このSceneではUIしか使わないので、SceneViewを2D modeにしておくと作業が進めやすいかと思われます。

まず、以下のように要素を配置していきます。

f:id:PEPOipod007:20151207151543p:plain

上から順に説明していきます。

GetPINButton (Button)
PINCode取得用のButton

InputPINField (InputField)
取得したPINCodeを入力するInputField

AuthPINButton (Button)
PINCode認証用のButton

です。

続いて、Tweet用の要素を配置していきます。 Tweet文のInputFieldですが、沢山行数を打てるように広めのものにしたいですよね。ただ、雑にScaleで拡縮すると全てが縦長なだけのInputFiledが完成するので、拡縮する際は、UI拡縮ツールを使うようにしましょう。

f:id:PEPOipod007:20151207150907p:plain

UI拡縮ツールは上の画面で言う、SceneViewの左上にある、選択されている小さいボタンです。 TweetButtonもつけると以下のようになります。

f:id:PEPOipod007:20151207151551p:plain

要素の説明をしていきます。

InputTweetField (InputField)
Tweet文を入力するInputField

TweetButton (Button)
Tweet用のButton

UIの設置はこれで終了です。最後に、TwitterAPIを叩くScriptを付与させたGameObjectを作成しましょう。
Hierarchy -> Create -> Create Emptyで空GameObjectを作成して、名前をTwitterComponentにします。

その後、Assets/Scripts/などのディレクトリを作成し、そこで右クリック、Create-> C# ScriptC#ScriptFileを作成します。名前はTwitterComponentHandlerにします。
ScriptFileが作成できたら、TwitterComponentにアタッチしましょう。

f:id:PEPOipod007:20151207152341p:plain

これでSceneの準備は完了です。

Twitterアプリケーションの作成

続いて、APIをテストするためにTwitterApplicationを作成してください。

Twitter APIの使い方まとめ
この記事が大変分かりやすいかと思われます。Consumer KeyConsumer Secretを使うので、それらが記載されたページを開いておいて下さい。

コードの記述

ではあらかたの準備が出来たので、早速コードを書いていきましょう。TwitterComponentHandler.csを開いて下さい。

using ディレクティブ

まずusing ディレクティブを記述しましょう。デフォルトでUnityEngineSystem.Collectionsが記述されていますが、これに加えて今回はUIクラスの機能を頻繁に使用するので、UnityEngine.UIもここに追記しましょう。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

こうなりますね。

変数宣言

続いて、変数の記述をしていきましょう。ココらへんで脳みそを使いたくないので、Demo.csからいい感じにパクります。健康的なコーディングはパクリによって保証されます。

public class TwitterComponentHandler : MonoBehaviour {

    public GameObject inputPINField;
    public GameObject inputTweetField;

    private const string CONSUMER_KEY = "先ほど作成したTwiiterアプリのConsumer Key";
    private const string CONSUMER_SECRET = "先ほど作成したTwiiterアプリのConsumer Secret";

    Twitter.RequestTokenResponse m_RequestTokenResponse;
    Twitter.AccessTokenResponse m_AccessTokenResponse;

    const string PLAYER_PREFS_TWITTER_USER_ID           = "TwitterUserID";
    const string PLAYER_PREFS_TWITTER_USER_SCREEN_NAME  = "TwitterUserScreenName";
    const string PLAYER_PREFS_TWITTER_USER_TOKEN        = "TwitterUserToken";
    const string PLAYER_PREFS_TWITTER_USER_TOKEN_SECRET = "TwitterUserTokenSecret";

    const string PLAYER_PREFS_TWITTER_TWEETED_IDS       = "TwitterTweetedIDs";

    // Use this for initialization
    void Start () {
    
    }

input接頭辞で始まるものには、それぞれ対応するInputFieldをUnityエディタ上で設定してあげます。

CONSUMER接頭辞で始まるものには、TwitterアプリのConsumerKey, Secretを格納しておきます。

m_RequestTokenResponsem_AccessTokenResponseはそのままです。認証をしていき、それぞれのTokenが格納されていく予定です。

PLAYER_PREFS接頭辞で始まるものは、PlayerPrefsへアクセスするためのkeyが格納されています。Demoでは一度取得したTokenは、PlayerPrefsに格納するように作られています。
毎度PINを入力させてログインさせる、というケースはあまりないと思われるので、そのままDemoに倣いましょう。

OnClickEventの定義

続いて、各ボタンのOnClickEventを定義していきましょう。

void Update(){}以下に記述します。

   // Update is called once per frame
    void Update () {
    
    }


    /* OnClick Event */


    public void OnClickGetPINButon () {
        StartCoroutine(Twitter.API.GetRequestToken(CONSUMER_KEY, CONSUMER_SECRET,
            new Twitter.RequestTokenCallback(this.OnRequestTokenCallback)));
    }

    public void OnClickAuthPINButon () {
        string myPIN = inputPINField.GetComponent<InputField> ().text;

        StartCoroutine(Twitter.API.GetAccessToken(CONSUMER_KEY, CONSUMER_SECRET, m_RequestTokenResponse.Token, myPIN,
            new Twitter.AccessTokenCallback(this.OnAccessTokenCallback)));
    }

    public void OnClickTweetButon () {
        string myTweet = inputTweetField.GetComponent<InputField> ().text;

        StartCoroutine(Twitter.API.PostTweet(myTweet, CONSUMER_KEY, CONSUMER_SECRET, m_AccessTokenResponse,
            new Twitter.PostTweetCallback(this.OnPostTweet)));
    }

ButtonComponentのOnClickにEventを設定するには、publicな関数にしてあげる必要があります。

基本的にTwitter.APIで定義されているコルーチンを呼び出すことで、TwitterAPIを叩けるようになっています。
詳しく知りたい方は、Twitter.csを読む事をオススメします。さほど量もないので、ある程度の知識があればそれほど時間はかからないでしょう。

コールバック関数の定義

さて、先ほどのOnClickEventですが、それぞれ引数にコールバック関数を取っているので、コールバック関数を記述していきましょう。

public void OnClickTweetButon () {}以下に記述していきます。

   /* Callback Event */


    void OnRequestTokenCallback(bool success, Twitter.RequestTokenResponse response) {
        if (success) {
            string log = "OnRequestTokenCallback - succeeded";
            log += "\n    Token : " + response.Token;
            log += "\n    TokenSecret : " + response.TokenSecret;
            print(log);

            m_RequestTokenResponse = response;

            print (response.Token);
            print (response.TokenSecret);

            Twitter.API.OpenAuthorizationPage(response.Token);
        } else {
            print("OnRequestTokenCallback - failed.");
        }
    }

    void OnAccessTokenCallback (bool success, Twitter.AccessTokenResponse response) {
        if (success) {
            string log = "OnAccessTokenCallback - succeeded";
            log += "\n    UserId : " + response.UserId;
            log += "\n    ScreenName : " + response.ScreenName;
            log += "\n    Token : " + response.Token;
            log += "\n    TokenSecret : " + response.TokenSecret;
            print(log);

            m_AccessTokenResponse = response;

            PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_ID, response.UserId);
            PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_SCREEN_NAME, response.ScreenName);
            PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_TOKEN, response.Token);
            PlayerPrefs.SetString(PLAYER_PREFS_TWITTER_USER_TOKEN_SECRET, response.TokenSecret);

        } else {
            print("OnAccessTokenCallback - failed.");
        }
    }

    void OnPostTweet (bool success) {
        print("OnPostTweet - " + (success ? "succedded." : "failed."));
    }

それぞれが、それぞれのコールバック関数として対応しています。
successresponseでそれぞれ結果を受け取れるようになっています。
基本的なコードはこれで完成です。

エディタ上での設定

最後に、エディタ上で各設定を行っていきましょう。

publicなGameObject型変数の値を設定

publicなGameObjectとして宣言した変数に値を設定していきましょう。InputField系ですね。

f:id:PEPOipod007:20151207172907p:plain

これでOKです。

OnClickEventの設定

続いて、ButtonにOnClickEventを設定していきます。
ほぼ同じ作業なので、GetPINButtonを例にあげて説明していきます。

まずHierarchyView上でGetPINButtonをクリックし、Componentを表示させます。
続いて、Button(Script)内にある、OnClickの右下にある+をクリックしてください。

None(Object)という項目が出てくるので、HierarchyView内のTwitterComponentをドラッグして設定しましょう。
設定すると、No Functionと書かれていたところが選択可能になります。そのプルダウンメニュー内から TwitterComponentHandler -> OnClickGetPINButon ()を選択します。
これで、GetPINButtonのOnClickEventとして、OnClickGetPINButon ()が設定されました。

f:id:PEPOipod007:20151207173917p:plain

同じように、AuthPINButtonOnClickAuthPINButon ()TweetButtonOnClickTweetButon ()を設定してあげましょう。

完成

これで、TwitterのPINコード認証が出来、Tweetが出来るSceneが完成しました!

使い方

まず、GetPINCpdeをクリックすると、アプリケーションを認証するかどうかの画面に飛ばされるので、そこで承認をする。
すると、PINコードが表示されるので、Unityに戻り、PINコードを入力し、AuthPINCodeをクリックする。successとprintされたら成功です。
あとは、Tweet文を適当に入力し、Tweetボタンをクリックしましょう。successとprintされたら、無事ツイートが行われているはずです。

これで最低限の機能が実装できました。ここからは、複数のテストケースを元に、実装方法を見ていきましょう。

OnPostTweetでresponseを取得する。

Tweetした後、そのTweetのidを取得したい、という事はよくあるでしょう。しかし、現状OnPostTweetではsuccessしたか否かという情報しか参照出来ません。 もし、OnPostTweetでresponseを受け取りたい場合は、Twitter.csを書き換える必要があります。

まず、PostTweetCallbackの定義部を書き換えましょう。

// public delegate void PostTweetCallback(bool success);
 public delegate void PostTweetCallback(bool success, string response);

こうすることで、callbackにresponseを渡せるようになりました。では実際にPostTweet()内でcallbackにresponseを渡す処理を書きましょう。

       public static IEnumerator PostTweet(string text, string consumerKey, string consumerSecret, AccessTokenResponse response, PostTweetCallback callback)
        {
            if (string.IsNullOrEmpty(text) || text.Length > 140)
            {
                Debug.Log(string.Format("PostTweet - text[{0}] is empty or too long.", text));

                callback(false, "");
            }
            else
            {
                Dictionary<string, string> parameters = new Dictionary<string, string>();
                parameters.Add("status", text);

                // Add data to the form to post.
                WWWForm form = new WWWForm();
                form.AddField("status", text);

                // HTTP header
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers["Authorization"] = GetHeaderWithAccessToken("POST", PostTweetURL, consumerKey, consumerSecret, response, parameters);

                WWW web = new WWW(PostTweetURL, form.data, headers);
                yield return web;

                if (!string.IsNullOrEmpty(web.error))
                {
                    Debug.Log(string.Format("PostTweet - failed. {0}\n{1}", web.error, web.text));
                    callback(false, web.error);
                }
                else
                {
                    string error = Regex.Match(web.text, @"<error>([^&]+)</error>").Groups[1].Value;

                    if (!string.IsNullOrEmpty(error))
                    {
                        Debug.Log(string.Format("PostTweet - failed. {0}", error));
                        callback(false, web.error);
                    }
                    else
                    {
                        callback(true, web.text);
                    }
                }
            }
        }

こうですね。これでPostTweetのコールバック関数にresponseが渡されるようになりました。

ついでに、TwitterComponentHandlerも書き換えましょう。

   void OnPostTweet (bool success, string response) {
        print("OnPostTweet - " + (success ? "succedded." : "failed."));

        if (success) {
            print (response);
        }
    }

この時点でDemo.csが死を迎えることになります。削除するか、上と同じようにOnPostTweetの第二引数にresponseを与えてあげましょう。

これで、ツイート成功時にresponseがprintされるようになりました。
しかし、ただのstringとして渡されてくるので長文のJSONがダダダッとconsoleに表示され、かなり辛いものを感じることになります。

JSONをパースしよう

このままではidの取得も一苦労ですので、responseをJSONとしてパースし、もっと楽に扱えるようにしましょう。

Unityで扱えるJSONパースのライブラリとしてオススメするのはSimpleJSONというものです。

SimpleJSON

以上のリンクにあるDownloadの項からライブラリをダウンロードして下さい。
ダウンロードしたフォルダ内にSimpleJSON.unitypackageというものがあるはずです。これをダブルクリックしてインポートしましょう。
インポートが完了したら、Assets/Plugins/SimpleJSON/などというディレクトリを作成し、そこにインポートして出てきたファイル郡を移動させましょう。

これでインポートは完了です。早速スクリプト内で扱ってみましょう。

まず、usingディレクティブを記述します。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

using SimpleJSON;

これで、このスクリプトファイル内でSimpleJSONライブラリの関数が扱えるようになりました。
JSON.Parse(JSON文字列)JSON文字列をJSONObjectにパース出来ます。
ここでは、responseを渡せば良さそうですね。実際にやってみましょう。

   void OnPostTweet (bool success, string response) {
        print("OnPostTweet - " + (success ? "succedded." : "failed."));

        if (success) {
            var json = JSON.Parse (response);

            print (json ["id"]);
        }
    }

これでresponse内にあるidを無事に取得できました!
SimpleJSONは他にも様々な関数があります。種類や使い方は、SimpleJSON を読むと良いでしょう。

他のAPIを叩く

認証やPostTweetだけではなく、もっと色々なAPIを叩きたいと思うこともあるでしょう。
そこで、GET statuses/user_timelineを叩く処理を実装しながら、他のAPIを叩く処理の実装方法を学んでいきましょう。

基本的にはPostTweet()を真似しつつ、適宜渡すheadersなどを変えると大体いい感じに仕上がります。
なので、まずはPostTweetをコピペして、関数名などを変えましょう。

       private const string GetUserTimelineURL = "https://api.twitter.com/1.1/statuses/user_timeline.json";

        public static IEnumerator GetUserTimeline(string text, string consumerKey, string consumerSecret, AccessTokenResponse response, GetUserTimelineCallback callback)
        {
            if (string.IsNullOrEmpty(text) || text.Length > 140)
            {
                Debug.Log(string.Format("GetUserTimeline - text[{0}] is empty or too long.", text));

                callback(false, "");
            }
            else
            {
                Dictionary<string, string> parameters = new Dictionary<string, string>();
                parameters.Add("status", text);

                // Add data to the form to post.
                WWWForm form = new WWWForm();
                form.AddField("status", text);

                // HTTP header
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers["Authorization"] = GetHeaderWithAccessToken("POST", GetUserTimelineURL, consumerKey, consumerSecret, response, parameters);

                WWW web = new WWW(GetUserTimelineURL, form.data, headers);
                yield return web;

                if (!string.IsNullOrEmpty(web.error))
                {
                    Debug.Log(string.Format("GetUserTimeline - failed. {0}\n{1}", web.error, web.text));
                    callback(false, web.error);
                }
                else
                {
                    string error = Regex.Match(web.text, @"<error>([^&]+)</error>").Groups[1].Value;

                    if (!string.IsNullOrEmpty(error))
                    {
                        Debug.Log(string.Format("GetUserTimeline - failed. {0}", error));
                        callback(false, web.error);
                    }
                    else
                    {
                        callback(true, web.text);
                    }
                }
            }
        }

GetUserTimelineURLはちゃんとそのAPIに対応したURLに変更しています。 その他にも、適宜PostTweetのように書かれているところをGetUserTimelineに置き換えています。

また、GetUserTimeline用のcallback関数を定義しました。以下のように記述して下さい。

   public delegate void RequestTokenCallback(bool success, RequestTokenResponse response);
    public delegate void AccessTokenCallback(bool success, AccessTokenResponse response);
    public delegate void PostTweetCallback(bool success, string response);
    public delegate void GetUserTimelineCallback(bool success, string response);

これで土台が出来上がりましたね。ただ、POSTリクエスト用の関数を持ってきたので少々不具合があります。
まず、WWWFormにparamaterを渡して…という事をしているので、普通にパラメーターをURLとしてビルドしてくれる関数を用意しましょう。

UrlEncode()以下に記述してください。

       private static string BuildURL(string baseURL, Dictionary<string, string> parameters)
        {
            StringBuilder sb = new StringBuilder(baseURL);

            if (parameters != null && parameters.Count > 0)
            {
                sb.Append("?");

                foreach (var pair in parameters)
                {
                    sb.Append(WWW.EscapeURL(pair.Key)).Append("=").Append(WWW.EscapeURL(pair.Value)).Append("&");
                }

                sb.Remove(sb.Length - 1, 1);
            }

            return sb.ToString();
        }

こちらを参考にさせて頂きました。ありがとうございます。 TwitterAPIを利用するためのアセット"Let's Tweet in Unity!"で検索APIを使うための拡張 · GitHub

これでurlとparameterを渡せばGETリクエスト用のURLとしてビルドしてくれる関数が出来上がりました。
これを上手に使ってGetUserTimelineを完成させましょう。

       public static IEnumerator GetUserTimeline(string user_id, string consumerKey, string consumerSecret, AccessTokenResponse response, GetUserTimelineCallback callback)
        {
            // Need to fill body since Unity doesn't like an empty request body.
            byte[] dummmy = null;
            string url = GetUserTimelineURL;

            Dictionary<string, string> parameters = new Dictionary<string, string>();
            parameters.Add("user_id", user_id);
            parameters.Add("count", 30.ToString());
            parameters.Add("include_rts", "false");

            url = BuildURL (url, parameters);

            // HTTP header
            Dictionary<string, string> headers = new Dictionary<string, string>();
            headers["Authorization"] = GetHeaderWithAccessToken("GET", url, consumerKey, consumerSecret, response, parameters);

            WWW web = new WWW(url, dummmy, headers);
            yield return web;

            if (!string.IsNullOrEmpty(web.error))
            {
                Debug.Log(string.Format("GetUserTimeline - failed. {0}\n{1}", web.error, web.text));
                callback(false, web.error);
            }
            else
            {
                string error = Regex.Match(web.text, @"<error>([^&]+)</error>").Groups[1].Value;

                if (!string.IsNullOrEmpty(error))
                {
                    Debug.Log(string.Format("GetUserTimeline - failed. {0}", error));
                    callback(false, web.error);
                }
                else
                {
                    callback(true, web.text);
                }
            }
        }

これで、引数user_idで与えられたUserのツイートを30件(RTは含まない)取得する、というコードになりました。
parametersにリクエストのパラメーターを与えます。今はサンプルなのでここで定義していますが、外側から設定できるようにもう一つ引数を設けてもいいかもしれないですね。

Twitter.cs側の記述は以上です。

最後に呼び出す側のコードを記述して終わりにしましょう。

呼び出し方は

   StartCoroutine(Twitter.API.GetUserTimeline(m_AccessTokenResponse.UserId, CONSUMER_KEY, CONSUMER_SECRET, m_AccessTokenResponse,
        new Twitter.GetUserTimelineCallback(this.OnGetUserTimeline)));

です。コールバック関数は

void OnGetUserTimeline(bool success, string response) {
        print ("GetUserTimeline- " + (success ? "succedded." : "failed."));

        if (success) {
            var json = JSON.Parse (response);
        }
    }

のようにすると良いでしょう。

これでGetUserTimeline ()の実装は完了しました。
その他のGETリクエストを叩く関数を作成する際はGetUserTimeline ()を、POSTリクエストの際はPostTweet ()を参考にするといいでしょう。

Twitterの実装はこんな感じですね。ライブラリがファイルが一つで完結していて軽量かつ改良の加えやすいものになっています。
かなり扱いやすいライブラリだといえるのではないでしょうか。これを参考にしてUnityでTwitterクライアントを作ってみてください!

UnityでFacebook

続いて、UnityでFacebookAPIを叩いてみましょう。こちらは導入が面倒ですが、APIを叩くための関数をライブラリが用意していてくれたりと、親切な設計になっています。(そもそものFacebookAPIがクソだという説もありますが)

インポート

まずはインポートから進めていきましょう。今回は以下のAssetを使用します。

Facebook SDK for Unity (beta)

雑に「Unity Facebook」でググると、何故かバージョンの低いものがサジェストされ、コードの闇に飲まれる事になるので気をつけましょう。
上のAssetをインポートしてください。インポート後、一度Unityを再起動して下さい。

Facebookアプリケーションの作成

続いて、APIをテストするためにTwitter同様、Facebookアプリケーションを作成してください。

Facebook APIを使って、コマンドラインから JSON形式のデータを取得してみる

こちらを参考にするといいでしょう。App NameApp Idを使うので、記述されているページを表示しておいてください。

初期設定

作成が完了したら、上のメニューバーからFacebook -> Edit Settingsに行き、先ほど作成したアプリのApp NameApp Idを設定してあげてください。

テストシーンの作成

続いて、作業用のテストシーンを作成しましょう。
Twitterと似たような作業なので、細かい説明は省きます。

f:id:PEPOipod007:20151207204047p:plain

こんな感じになりました。それぞれの説明をします。

ReadLoginButton (Button)
ReadPermissionでログインするためのButton

PublishLoginButton (Button)
PublishPermissionでログインするためのButton

InputPostField (InputField)
Postを入力するInputField

PostButton (Button)
Post用のButton

FacebookComponent (GameObject)
FacebookComponentHandler.csを当てた、空のGameObject

です。

コードの記述

それではコードを書いていきましょう。FacebookComponentHandler.csを開いてください。

using ディレクティブ

例のごとく、using ディレクティブを記述していきましょう。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Facebook.Unity;

です。

変数定義

続いて変数を定義していきます。以下のように記述してください。

public class FacebookComponentHandler : MonoBehaviour {

    public GameObject inputPostField;

    private string status = "";
    private string lastResponse = "";

やや強引ですが、Example/MainMenuのコードをお借りするために、statuslastResponseを定義しました。

Init処理

このライブラリでは、あらゆる処理をする前に、まずFB.Init()を実行するよう定められています。
Start ()に記述しましょう。

   // Use this for initialization
    void Start () {
        FB.Init (OnInitComplete, OnHideUnity);
    }

です。諸々のコールバックイベントは後ほど定義します。

OnClickEventの定義

続いて、OnClickEventの定義をしていきましょう。

   public void OnClickReadLoginButton () {
        FB.LogInWithReadPermissions(new List<string>() { "public_profile", "email", "user_friends", "user_posts" }, this.HandleResult);
    }

    public void OnClickPublishLoginButton () {
        FB.LogInWithPublishPermissions(new List<string>() { "publish_actions", "user_posts" }, this.HandleResult);
    }

    public void OnClickPostButton () {
        FB.API ("me/posts", HttpMethod.GET, this.HandleResult);
    }

こんな感じです。
Loginには二種類の関数が用意されております。ReadPermissionのScopeを認証させるためにはFB.LogInWithReadPermissions ()、PublishPermissionのScopeを認証させるためにはFB.LogInWithPublishPermissions ()を使います。
それぞれ、一つ目の引数にstringの引数を渡すことでscopeを設定しています。

Postの方はFB.API ()という関数を使っています。他のAPIを使う際もほぼこの関数のお世話になることでしょう。
第一引数に叩くAPI、第二引数にリクエストの種類を渡します。

これでOnClickEventの定義は完了です。

コールバック関数の定義

続いて、コールバック関数の定義をしていきましょう。
以下のように記述します。

   private void OnInitComplete()
    {
        status = "Success - Check log for details";
        lastResponse = "Success Response: OnInitComplete Called\n";
        string logMessage = string.Format(
            "OnInitCompleteCalled IsLoggedIn='{0}' IsInitialized='{1}'",
            FB.IsLoggedIn,
            FB.IsInitialized);
        print ("status = " + status);
        print ("lastResponse = " + lastResponse);
        print (logMessage);
    }

    private void OnHideUnity(bool isGameShown)
    {
        status = "Success - Check log for details";
        lastResponse = string.Format("Success Response: OnHideUnity Called {0}\n", isGameShown);
        print ("status = " + status);
        print ("lastResponse = " + lastResponse);
        print("Is game shown: " + isGameShown);
    }

    void HandleResult(IResult result)
    {
        if (result == null)
        {
            lastResponse = "Null Response\n";
            print (this.lastResponse);
            return;
        }

        // Some platforms return the empty string instead of null.
        if (!string.IsNullOrEmpty(result.Error))
        {
            status = "Error - Check log for details";
            lastResponse = "Error Response:\n" + result.Error;
            print (result.Error);
        }
        else if (result.Cancelled)
        {
            status = "Cancelled - Check log for details";
            lastResponse = "Cancelled Response:\n" + result.RawResult;
            print (result.RawResult);
        }
        else if (!string.IsNullOrEmpty(result.RawResult))
        {
            status = "Success - Check log for details";
            lastResponse = "Success Response:\n" + result.RawResult;
            print (result.RawResult);
        }
        else
        {
            lastResponse = "Empty Response\n";
            print (this.lastResponse);
        }
    }

このように記述します。APIの結果はHandleResult ()をコールバックに渡せば大体の事は分かります。

これでコードの方は完成です。

エディタ上での設定

最後に、エディタ上での設定をしましょう。

publicなGameObject型変数の値を設定

publicなGameObjectとして宣言した変数に値を設定していきましょう。

f:id:PEPOipod007:20151207215115p:plain

これでOKです。

OnClickEventの設定

続いて、OnClickEventを設定していきます。これもTwitterの方で行った手順とほぼ同じなので詳細は割愛させていただきます。
設定先は

ReadLoginButtonOnClickReadLoginButton ()

PublishLoginButtonOnClickPublishLoginButton ()

PostButtonOnClickPostButton ()

です。

完成

これで完成です! 使い方は、ReadLoginをクリックし、出てきたFindAccessTokenをクリック、出てきたUserTokenをコピーし、UnityのUserToken欄にペーストし、SendSuccessをクリックします。
同じことをPublishLoginのボタンでもやりましょう。

両方完了したら、InputPostFieldに適当な文章を打ち込み、PostButtonをクリックしてみてください。無事成功していれば、あなたのタイムラインにPostが表示されているはずです。

これでFacebookの実装は完了ですね。折角なのでFacebookでも他のAPIを叩いてみる、という事をしてみましょう。

他のAPIを叩いてみる

今回はGET me/feedを叩いて、これまでの自分の投稿を取得してみましょう。

必要なscopeは、ReadPermissionsのuser_postsです。このように、APIによって様々なscopeが求められるので注意しましょう。
実装する前にGraph API エクスプローラーを使うと、必要なscopeが足りているか、などが分かるのでそちらも使ってみると良いでしょう。

それでは実装してみます。
Init完了後でないと不具合が起きるので、InitのcallbackであるOnInitComplete ()内で呼び出します。

   private void OnInitComplete()
    {
        status = "Success - Check log for details";
        lastResponse = "Success Response: OnInitComplete Called\n";
        string logMessage = string.Format(
            "OnInitCompleteCalled IsLoggedIn='{0}' IsInitialized='{1}'",
            FB.IsLoggedIn,
            FB.IsInitialized);
        print ("status = " + status);
        print ("lastResponse = " + lastResponse);
        print (logMessage);

        if (FB.IsLoggedIn) {
            var aToken = Facebook.Unity.AccessToken.CurrentAccessToken.Permissions;

            if (aToken.Contains("user_posts")) {
                FB.API ("me/feed", HttpMethod.GET, this.OnGetAllPosts);
            } 
        }
    }

こんな感じです。万全を期して、既にログインしているかどうかという判定と、認証したscope内にuser_postsが含まれているかどうか、という判定を取ります。
APIを叩いている処理自体はFB.API ("me/feed", HttpMethod.GET, this.OnGetAllPosts);です。こんな感じで大体のAPIが叩けるので、このライブラリはいいですね。

コールバックの処理も書いていきます。今回はTwitter同様、responseをまたJSONにパースするという事をしたいので、独自のコールバック関数を設定しました。例のごとく他のusingが書かれている項にusing SimpleJSONを追記しておいてください。

コールバック関数は以下のように記述します。

   void OnGetAllPosts (IResult result) {
        if (!string.IsNullOrEmpty(result.RawResult)) {

            var allPostJson = JSON.Parse (result.RawResult);

            foreach (JSONNode post in allPostJson.Childs) {
                print (post ["id"]);
            }
        }
    }

result.RawResultTwitterの方でいうresponseです。こいつをパースすればレスポンスのJSONObjectになりますね。
と、こんな感じでFacebookで他のAPIを実装するのは比較的楽です。あっという間でしたね。

これらを参考に、皆さんもUnityでFacebookのクライアントを作ってみてください!

おわりに

相当な長文となりましたが如何だったでしょうか。UnityでこれらのAPIを叩く知見が纏まった記事が見当たらなかったので書いてみました。

実際Unityで作成すると凝ったビジュアルやアニメーションが簡単に実装出来るので、ビジュアル重視のSNSクライアントを作成する選択肢として、Unityはそんなに悪くないんじゃないかなあとか個人的には思います。
皆さんもSNSクライアントを作成する際には、是非Unityを採用してみて下さい!(自己責任でお願いします)

明日は@ymyzkです!お楽しみに!