絵文字を LinqToTwitter で送るための方法

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 です。

20140903_02

動作確認用のサンプルコードとしては、先の「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 を送っておきます。

カテゴリー: C#, WinRT パーマリンク