ChuPad を製作している途中で、ツイッターに経過を表示させようと思いつきました。ひとりで作成しているとつまらないで、コピペするよりも直接ツイートできると面白いかと。ChuPad 自体は、Windows ストアアプリで作っているので(内部的にはユニバーサルアプリなので、お次は Windows Phone アプリになります)、People あたりに共有コントラクト…と考えたのですが、People に対しては URL しか共有できないのですね orz なんだかなー。どうやら、公式 Twitter アプリへの共有もできないらしいので、自前で実装することにしました。
で、いくつか探したなかで、LINQ To Twitter を使おうかなと、
LINQ to Twitter – Home
http://linqtotwitter.codeplex.com/
自前のツールは、デスクトップ環境でしか動かないのと、PCL で試してみたかったので、これを使うことに決まました。実際はツイートしかしないので、機能的にはオーバーなんですけどね。
■LinqToTwitterのPCL版を使う
PCL版は NuGet でダウンロードができます。「LinqToTwitter」で検索すれば ok です。
動作確認用のサンプルコードとしては、先の「LINQ to Twitter – Home」にはデモ用のコードがあるので、それを使うといいでしょう。Twitter API ひとつひとつにデモをつけているので、目的のものを探すのに苦労はするのですが。
ストア版の場合は、以下のように「LinqToTwitter.WindowsStore」を使います。なんか、ストア版、WPF版などクラスの名前が変わっているので、ネット上ではサンプルを探すのが苦労するのですが、本家のデモコードを見るとあっさり書いてあります。
1 2 | using LinqToTwitter.WindowsStore; using LinqToTwitter; |
LinqToTwitter が便利なのは、最初の認証部分も受け持ってくれるところです。認証部分をブラウザに渡したり、WebView で作ったりするのが面倒なので、あらかじめ用意してあるものを使ったのが次のコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | private string API_KEY = "" ; private string API_SECRET = "" ; private string API_CALLBACK = "" ; // @chu_lang へ投稿 private string OAUTH_KEY = "" ; private string OAUTH_SECRET = "" ; /// <summary> /// ツイッター投稿 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> async void kTwi_Tapped( object sender, TappedRoutedEventArgs e) { WindowsStoreAuthorizer auth; if (OAUTH_KEY == "" ) { auth = new WindowsStoreAuthorizer() { CredentialStore = new InMemoryCredentialStore { ConsumerKey = API_KEY, ConsumerSecret = API_SECRET }, Callback = API_CALLBACK }; } else { auth = new WindowsStoreAuthorizer() { CredentialStore = new InMemoryCredentialStore { ConsumerKey = API_KEY, ConsumerSecret = API_SECRET, OAuthToken = OAUTH_KEY, OAuthTokenSecret = OAUTH_SECRET }, Callback = API_CALLBACK }; } await auth.AuthorizeAsync(); // int count = auth.Parameters.Count; // string oauth_token = auth.CredentialStore.OAuthToken; // string oauth_sercret = auth.CredentialStore.OAuthTokenSecret; var context = new TwitterContext(auth); var msg = text1.Text + "n" + DateTime.Now.ToString(); await context.TweetAsync(msg); } |
Twitte のデベロッパで取得した API のコードを API_KEY と API_SECRET にいれておきます。まだ認証が終わっていないときには、OAUTH_KEY と OAUTH_SECRET が空なので、Twitter 認証ページを開いてユーザーに認証してもらえます。2回目以降は、OAUTH_KEY と OAUTH_SECRET を保存しておけば ok です。ここでは、ChuPad 専用のために直書きになっていますが、アプリフォルダに適当なフォーマットで保存しておけば ok でしょう。
末尾に DateTime をつけているのは実験用ので外しても ok です。同じツイートをすると、Twitter のほうで弾かれるのでそれを防ぐためです。実験していてあれー、となったので念のために。
■そのままでは絵文字コードが送れない
さて、この組み込みをして、さっくりと動かてみようと思ったのですが、絵文字を送ろうとすると実行エラーになります。Twitter のほうでエラーを返している訳ではなくて、LinqToTwitter の内部でエラーになるのです。自前で作っている投稿専用ツールのほうは絵文字が送れるので、LinqToTwitter の内部で何か変なことをやっているようです。
結論から言うと、Url#PercentEncode メソッドのロジックが未対応でした。このメソッドは、URLエンコードをするために%xxに変換するのですが、絵文字のサロゲートペアは内部的に何か変なことになっているみたいですね。これは、通常版の LinqToTwitter でも同じで、BuildUrlHelper#UrlEncode メソッドの中身が未対応です。
LinqToTwitter は通常版とPCL版とでコードが共有していないので、2箇所直す(しかもメソッド名もクラス名も異なる)のですが、これは .NET Framework 3.5 の頃に対応しようとした名残りなんでしょうね。
■エンコード部分を直す
仕方がないので、エンコード部分を直します。LinqToTwitter 自体は .NET 3.5 から対応しているのですが、これを奥深く入って直すのはしんどいので、.NET 4.5 の関数を使ってしまいます。
Uri.EscapeDataString メソッド (System)
http://msdn.microsoft.com/ja-jp/library/ms131567(v=vs.110).aspx
これ自体は 3.5 にもあるようなのですが、面倒なのでプロジェクト自体も 4.5 にしてしまいます。
本家の LinqToTiwtter からソースコードをダウンロードして、通常版とPCLのソリューションを開きます。
□通常版
1 2 3 4 5 6 7 8 9 10 11 | namespace LinqToTwitter { public class BuildUrlHelper { ... public static string UrlEncode( string value) { return Uri.EscapeDataString(value); } } } |
□PCL 版
1 2 3 4 5 6 7 8 9 10 11 | namespace LinqToTwitter.Net { public class Url { ... public static string PercentEncode( string value) { return Uri.EscapeDataString(value); } } } |
それぞれをビルドして NuGet から取ってきたものと摩り替えておけば ok です。こうすると無事、絵文字のツイートも可能になります。
後で、codeplex への pull request を送っておきます。