【Unity】Let’s Tweet In UnityでTwitterクライアントをつくる

calendar

reload

//読み返してみたらソースコードめっちゃ読みにくかったです。コピペしてIDE上でご覧ください。//
//さっさとソースコード見せろって方はリンクへどうぞ。//

☆もくじ☆

クソみたいな前置き

準備

画像ツイート

タイムライン(未実装)

 

はじめに

Unity勉強会に参加してきたで話した「ペイント機能付きTwitterクライアント」で自分はTwitterクライアントの部分を担当してました。

TwitterAPIどころかGUIアプリ開発したことないんだけど???みたいなノリで始めたけど、案外作れるもんです。

TwitterAPIを操作するための神Asset「Let’s Tweet In Unity」(以下LTIU)のお世話になりながらですけどね。

 

LTUS初期状態だと文字ツイートしか出来ません。しかもインポート直後はエラーが3つ。

で、HowToサイトを参考にぽちぽちすると、

・画像ツイート

・ユーザーのツイートを表示

が、できるようになります。

この時点で帰ってきたデータをJSON形式に直しているのでデータを読めるようになってます。

 

この記事は以上の作業をした前提で

・画像ツイート

・タイムラインの取得

を出来るようにするものです。

画像ツイートに関してはかなり苦労しました。(タイムラインに関しては別の人の書いたプログラムを読み解いた形です)

 

準備

最初に今回使うAssetを用意します。

AssetStoreからLTIUをimportしておきましょう。

Demoやreadomeなどがありますが必要なのはTwitter.csのみです。

 

画像ツイート実装

まずは適当にツイートボタンを作っておきましょう。

スクリプトも書きます


 public void OnClickTweetButon()
 {
    //ここではUserDataというクラスを作ってますが、
    //LTIUで定義されているAccessTokenResponse型変数responseがユーザーの認証データ。
    //CONSUMER_KEYとCONSUMER_SECRETはそれぞれ自分のTwitterアプリケーションのものを入力してください。
    Twitter.AccessTokenResponse response = userData.getUserData ();
    CONSUMER_KEY = userData.getConsumer_key();
    CONSUMER_SECRET = userData.getConsumer_secret();

    //今回はScreenShot.pngの画像をツイートするものとします。
    string filename = "ScreenShot.png";

    //ツイートしたい文章です。上の画像のテキストフィールドのテキストが入ります。
    string myTweet = inputTweetField.text.ToString();


    //まず ツイート文章がからでない かつ 空白文字のみでない場合のみツイートメソッドを呼び出します。
    if(!(string.IsNullOrEmpty(myTweet)) && !(myTweet.Trim() == "")){

       //ScreenShot.pngが存在しなければ、文字列のみのツイートメソッド、存在すれば画像付きツイートメソッドを呼び出します。
       if (!File.Exists(filename)) {
          //文字のみツイートメソッドを呼び出しています。
          StartCoroutine (Twitter.API.PostTweet (myTweet, CONSUMER_KEY, CONSUMER_SECRET, response,
          new Twitter.PostTweetCallback (this.OnPostTweet)));
       } else {
          //画像用ツイートメソッドを呼び出していま。
          StartCoroutine (Twitter.API.UploadPic (myTweet, filename, CONSUMER_KEY, CONSUMER_SECRET, response,
          new Twitter.UploadPicCallback (this.OnUploadPic)));
          //ツイートが終わったらScreenShot.pngを削除しています。
          //これがないと毎回この画像と一緒にツイートしてしまいます。
          System.IO.File.Delete(@"ScreenShot.png");
    }

    } else { 
    //空文字か空白文字のみだったら何も入力されていない状態に戻す
    inputTweetField.text = "";
    }    
}

これでボタンを押したときの処理は完成です。
ついでにコールバックメソッドも書きましょう。

 void OnUploadPic(bool success, string response)
 {
    print ("OnUploadPic - " + (success ? "succedded. " : "failed"));
    if(success){
    //同じくJsonにパース。
    var json = JSON.Parse(response);
    //デバッグ用に画像IDを表示しておきます。
    print("PicID:" + json["media_id_string"]);
    }
 }

正直コールバック関数はOnPostTweet一つでいいと思いますが念のためです。

 

Twitter.csにUploadPicを書きましょう。

めっちゃ長いですが頑張りましょう。

まず説明しておくと、

・ヘッダー

・データ

この二つが必要で、それをアップロード用APIのURLに送ると画像がアップロードされて画像IDが返ってきます。

その画像IDとツイートしたい文字列を一緒にツイート用APIのURLに送るとツイートされてツイートIDが返ってきます。

//50行目ほどでdelegateを追加しておきましょう。
 public delegate void UploadPicCallback(bool success, string reponse);

//で、PostTwetのメソッドの下あたりに
//まずはTwitterAPIの画像投稿用APIのURLを定義しておきます。

private const string UploadPicURL = "https://upload.twitter.com/1.1/media/upload.json";

public static IEnumerator UploadPic(string text, string filename, string consumerKey, string consumerSecret, AccessTokenResponse response, UploadPicCallback callback)
 {
    //引数はtext:ツイート文字列,filename:画像ファイルパス,consumerKey,consumerSecret:この二つがTwitterアプリケーション,response:ユーザー認証データ,callback:コールバック関数

    //画像ファイルをBase64Stringというものに変換します。

    //Base64Stringに変換するんだ~くらいの認識で大丈夫でした

     FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
     BinaryReader bin = new BinaryReader(fileStream);
     byte[] bytes = bin.ReadBytes((int)bin.BaseStream.Length);
     var bs64 = Convert.ToBase64String(bytes);
     bin.Close();

    //Dictionaryという型でヘッダーの素を作っていきます。mediaParametersを定義しましょう。

    Dictionary<string, string> mediaParameters = new Dictionary<string, string>();

    //ヘッダーにmedia_dataはさっき変換した文字列ですよ~ってのを追加します。
     mediaParameters.Add("media_data", bs64);

    //次に送信用のデータを作ります。WWWForm型でmediaFormを定義します。

    WWWForm mediaForm = new WWWForm();
 

    //データにも同じくmedia_dataはさっき変換した文字列です~って追加します。

    mediaForm.AddField("media_data", bs64);

    //次にヘッダー本体を作っていきます。

    //同じくdictionary型でmediaHeadersを定義しましょう。
 
    var mediaHeaders = new Dictionary<string, string>();

    //で、少し謎なここで、ヘッダー本体に情報を入れて(あとで説明します)
     mediaHeaders.Add("Authorization", GetHeaderWithAccessToken("POST", UploadPicURL, consumerKey, consumerSecret, response, mediaParameters));
     foreach(KeyValuePair<string,string> x in mediaHeaders)


    //WWW型で送信します。
     WWW mediaWeb = new WWW(UploadPicURL, mediaForm.data, mediaHeaders);

    //yield return とかCoroutineについてよくわかってないんですが、おそらく送り終わるまで待って受け取るよってことなんでしょうか??
     yield return mediaWeb;

    //ツイートするときに使うための画像IDを格納するための変数を用意しておきます。

    string media_id_string = "";

    //エラーメッセージがからだったら成功で画像IDをmedia_id_stringに格納して次へ。
     if (!string.IsNullOrEmpty(mediaWeb.error))
     {
         Debug.Log(string.Format("PostMedia - failed. {0}\n{1}", mediaWeb.error, mediaWeb.text));
         callback(false, mediaWeb.error);
         yield break;
     }
     else
     {
         string error = Regex.Match(mediaWeb.text, @"<error>([^&]+)</error>").Groups[1].Value;

        if (!string.IsNullOrEmpty(error))
         {
             Debug.Log(string.Format("PostTweet - failed. {0}", error));
             callback(false, mediaWeb.error);
             yield break;
         }
         else
         {
         var res = JsonUtility.FromJson<mediaResponse>(mediaWeb.text);
         media_id_string = res.media_id_string;
         }
      }
 

    //ここからはPostTweetメソッドとほぼ同じなので追加要素だけコメントつけておきます。
    Dictionary<string, string> parameters = new Dictionary<string, string>();
    parameters.Add("status", text);

    //パラメータにmedia_idsは画像IDですよ~って追加しておきます。
    parameters.Add("media_ids", media_id_string);
    WWWForm form = new WWWForm();
    form.AddField("status", text);

    //ここも同じく
    form.AddField("media_ids", media_id_string);

    // HTTP header
    var headers = new Dictionary<string, string>();
    headers.Add("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);
         }
     }
 }

 

これで肝心のメソッドはかけました。

で、これでツイートできればいいのですが、そう簡単にはいきません。

砕いて説明すると

このアセットにはヘッダーの素からヘッダーを作る際にURLエンコード、という処理をしていて、各文字列をぶっこむのですが

URLエンコードメソッドは入ってくる文字数が多いとエラーを吐いてしまいます!!!(32766文字以上らしい)

画像を文字列に直すとふつうに3万文字超えます。というか50万文字とか100万文字とかざら。

 

で、解決策はいろいろあってそもそもURLエンコードいらないらしい(実際にURLエンコードなしでできた人もいる)けど、自分はURLエンコードありの方で解決しちゃったので今回はそっちを上げます。

 

それじゃUrlEncode(string value)メソッドを改造します。

</pre>

    //value = Url.EscapeDataStinrg(value);をコメントアウトして以下を書きます。

    //一時変数を用意してコピーし、valueをからにした後どんどん+=していく感じです。

    string tmp = string.Copy(value);
    value = "";
    if(!(tmp.Length >= 10000))
    {
        // Debug.Log(Uri.EscapeDataString(tmp).Length);
        value += Uri.EscapeDataString(tmp);
    }
    else
    {
        int count = 0;
        for (int i =0; i < tmp.Length; i+=10000)
    {
    if(i+10000 >= tmp.Length)
    {
        value += Uri.EscapeDataString(tmp.Substring(i));
        Debug.Log(count+"times");
        break;
    }
    value += Uri.EscapeDataString(tmp.Substring(i, 10000));
    count++;
    }
}
<pre>

これで、文字列のエンコードも無事終わります。

 

お疲れ様でした、これで画像ツイートができるようになります。

タイムライン実装

 

//やる気の問題上タイムラインの記事はまだ実装されていません。

//しばらくお待ちください。

 

この記事をシェアする

コメント

コメントはありません。

down コメントを残す