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版などクラスの名前が変わっているので、ネット上ではサンプルを探すのが苦労するのですが、本家のデモコードを見るとあっさり書いてあります。
using LinqToTwitter.WindowsStore; using LinqToTwitter;
LinqToTwitter が便利なのは、最初の認証部分も受け持ってくれるところです。認証部分をブラウザに渡したり、WebView で作ったりするのが面倒なので、あらかじめ用意してあるものを使ったのが次のコードです。
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のソリューションを開きます。
□通常版
namespace LinqToTwitter { public class BuildUrlHelper { ... public static string UrlEncode(string value) { return Uri.EscapeDataString(value); } } }
□PCL 版
namespace LinqToTwitter.Net { public class Url { ... public static string PercentEncode(string value) { return Uri.EscapeDataString(value); } } }
それぞれをビルドして NuGet から取ってきたものと摩り替えておけば ok です。こうすると無事、絵文字のツイートも可能になります。
後で、codeplex への pull request を送っておきます。