UnityからTwitter APIを叩くライブラリをつくっている

Unity C#でTwitter APIを叩くライブラリを作ってみています。完全に作成中ですが、ひとまず人の目に触れる場所にアップしてみることにしてみました。

Twitter for Unity (beta)
https://github.com/toofu37/twitter-for-unity

### 2017/5/2 追記
namespaceの名前を変えたりStreaming APIに一部対応したりしたので記事修正しました。

### 2017/12/23 追記
Twitter公式のTwitter-Kit-for-Unityと名前が類似してるのはよくなさそうだったのでリポジトリ名とnamespace名を再変更しました。新しい名前は「Twity」です。かわいがってあげてください。
https://github.com/toofusan/Twity


# なんで？
- Oculus Riftを買ったので、VR上でTwitterをやりたい
-  [Let's Tweet In Unity](https://www.assetstore.unity3d.com/jp/#!/content/536) というAssetがあるけれど、これはPOST statuses/update のみのライブラリなので、もっと汎用的に使えるライブラリがほしい
-  上記AssetはWWWクラスを使っているけど、UnityWebRequestとJsonUtilityでもうちょっと使いやすくなるかなと思った
- Node.jsの [twit](https://github.com/ttezel/twit) みたいな感じで、適当にパラメータ入れて叩けるようにしたい
- API叩く勉強

# 使っている様子

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">2Bの尻を眺めていた影響で今週ほぼ進捗ないけど、いいねとリツイートはできるようになった。オブジェクトの位置関係の処理ができてない <a href="https://twitter.com/hashtag/VR%E3%81%A7Twitter?src=hash">#VRでTwitter</a> <a href="https://t.co/Vto1Cl04GN">pic.twitter.com/Vto1Cl04GN</a></p>&mdash; 人生 😇 (@toofu__) <a href="https://twitter.com/toofu__/status/840937211763675136">2017年3月12日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">複数画像つきツイートや動画付きツイートを表示できるようにした。楽しくなってきた <a href="https://twitter.com/hashtag/VR%E3%81%A7Twitter?src=hash">#VRでTwitter</a> <a href="https://t.co/8w9dDHiZCu">pic.twitter.com/8w9dDHiZCu</a></p>&mdash; 人類 😇 (@toofu__) <a href="https://twitter.com/toofu__/status/853583711190765568">2017年4月16日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">わかりづらいけど、Streaming APIで流れてきたツイートを表示できた。これは&quot;statuses/filter&quot;で「Unity」を含むツイートがpostされたら表示する感じ <a href="https://twitter.com/hashtag/VR%E3%81%A7Twitter?src=hash">#VRでTwitter</a> <a href="https://t.co/Wk8XAgQwYT">pic.twitter.com/Wk8XAgQwYT</a></p>&mdash; 人類 😇 (@toofu__) <a href="https://twitter.com/toofu__/status/859345948576686080">2017年5月2日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

# 現状

- きちんとしたテストはしてないけど、だいたいのREST APIは叩けそう。
- 画像のアップロードは実装済み。(chunked POSTは未実装)
- Streaming API：FilterとUserStreamはいける


# 使い方
GitHubに書いてるとおりですが、以下のような感じです。
投げるパラメータはそれぞれ https://dev.twitter.com/rest/reference などをご確認ください。

## 初期化
https://dev.twitter.com でAppを作成して、各種アクセスキーを取得して以下のように記載してください。

```C#
public class EventHandler : MonoBehaviour {
  void Start () {
    Twity.Oauth.consumerKey       = "...";
    Twity.Oauth.consumerSecret    = "...";
    Twity.Oauth.accessToken       = "...";
    Twity.Oauth.accessTokenSecret = "...";
  }  
}
```

## 使用例
### GET search/tweets
特定のキーワード(q)でツイートを検索する。

```C#
void Start() {
  Dictionary<string, string> parameters = new Dictionary<string, string>();
  parameters ["q"] = "search word";       // 検索ワード
  parameters ["count"] = 30.ToString();   // 取得するツイート数
  StartCoroutine (Twity.Client.Get ("search/tweets", parameters, this.Callback));
}

void Callback(bool success, string response) {
  if (success) {
    Twity.SearchTweetsResponse Response = JsonUtility.FromJson<Twity.SearchTweetsResponse> (response);
  } else {
    Debug.Log (response);
  }
}
```

### GET statuses/home_timeline
自分のタイムラインの最新ツイートを取得する。

```C#
void Start() {
  Dictionary<string, string> parameters = new Dictionary<string, string>();
  parameters ["count"] = 30.ToString();   // 取得するツイート数
  StartCoroutine (Twity.Client.Get ("statuses/home_timeline", parameters, this.Callback));
}

void Callback(bool success, string response) {
  if (success) {
    Twity.StatusesHomeTimelineResponse Response = JsonUtility.FromJson<Twity.StatusesHomeTimelineResponse> (response);
  } else {
    Debug.Log (response);
  }
}
```

### POST statuses/update
ツイートする。

```C#
void Start() {
  Dictionary<string, string> parameters = new Dictionary<string, string>();
  parameters ["status"] = "Tweet from Unity";  // ツイートするテキスト
  StartCoroutine (Twity.Client.Post ("statuses/update", parameters, this.Callback));
}

void Callback(bool success, string response) {
  if (success) {
    Twity.Tweet tweet = JsonUtility.FromJson<Twity.Tweet> (response); // 投稿したツイートが返ってくる
  } else {
    Debug.Log (response);
  }
}
```


### POST statuses/retweet/:id
リツイートする。

```C#
// 「Unity」で検索してヒットしたツイート5件をリツイートする

void Start() {
  Dictionary<string, string> parameters = new Dictionary<string, string>();
  parameters ["q"] = "Unity";       // 検索ワード
  parameters ["count"] = 5.ToString();   // 取得するツイート数
  StartCoroutine (Twity.Client.Get ("search/tweets", parameters, this.Callback));
}

void Callback(bool success, string response) {
  if (success) {
    Twity.SearchTweetsResponse Response = JsonUtility.FromJson<Twity.SearchTweetsResponse> (response);
    foreach (Twity.Tweet tweet in Response.statuses) { Retweet (tweet); }
  } else {
    Debug.Log (response);
  }
}

void Retweet(Tweet tweet) {
  Dictionary<string, string> parameters = new Dictionary<string, string>();
  parameters ["id"] = tweet.id_str; // リツイートするツイートのID
  StartCoroutine (Twity.Client.Post ("statuses/retweet/" + tweet.id_str, parameters, this.RetweetCallback));
}

void RetweetCallback(bool success, string response) {
  if (success) {
    Debug.Log ("Retweet Done");
  } else {
    Debug.Log (response);
  }
}
```

### Streaming API POST statuses/filter
「iPhone」を含むツイートがpostされるたびに反応する。

```C#
Twity.Stream stream;

void Start() {
  stream = new Stream(Twity.StreamType.PublicFilter);
  Dictionary<string, string> streamParameters = new Dictionary<string, string>();
  streamParameters.Add("track", "iPhone");
  StartCoroutine(stream.On(streamParameters, this.OnStream));
}

void OnStream(string response) {
  try
    {
      Twity.Tweet Response = JsonUtility.FromJson<Twity.Tweet>(response));
  } catch (System.ArgumentException e)
  {
    Debug.Log("Invalid Response");
  }
}
```

## レスポンスの処理
`TwitterJson.cs`にJsonUtilityでオブジェクト化するためのクラスが記載しています。REST APIを叩く場合は、どんなResponseが返ってくるかを https://dev.twitter.com/rest/reference から確認して、それに対応したクラスをつくる必要があります。ここを拡充すればもっとほしい内容がとれるはず。ただ返ってくるJSONの構造が入れ子になってたりループになってたり？複雑なので現状はこのようになっています。
リツイート、リプライ関連の情報がきちんととれていないので、アップデート予定です。

# まとめ
趣味プログラミングの素人がつくったものなのでガバガバだと思いますが、これからアップデートしていくつもりなので、ご意見などあればいただけるとうれしいです。