Android
Twitter
fabric

Fabric from Android で写真を Tweet する。

More than 3 years have passed since last update.


Fabric

introducing-fabric-homepage.png

Fabric.io

Fabric は Twiter が提供しているツールで、アプリ開発時にアプリケーションをチームへスキームすることが可能です。

また、クラッシュログやアプリの配布に、Twitter ログインなど様々な機能が備わっています。


Fabric Kits

Fabric の中にはとても優れている Framework が存在します。

そんな中、今回お伝えするのは、Fabric の機能のでもある、Twitter Kit で画像データーを Tweet する処理を作ったので、その時の覚書にはなりますが、お伝えしたいと思います。


Twitter Kit

twitter_kit-2bb33c7ef570f985b3ce40cbef3f04e4.png

Twitter Kit


主な機能


  • Authentication

  • Use OAuth Echo

  • Request a User's Email Address

  • Access Twitter's REST API

  • Show Tweets

  • Show Timelines

  • Compose Tweets

目立った機能はここら辺です。

それぞれの機能の簡単な説明です。


Authentication


  • Log in with Twitter


    • 標準のログインボタンが用意され簡単にTwitter Log in が実装できる

    • ゲストログインが可能で、アカウントのないユーザーでもTwitterの機能の一部分を利用することができる。




Use OAuth Echo


  • OAuth 処理を簡単に実装できる


    • リクエストへ必要な Auth 情報を利用できる。




Request a User's Email Address


  • Email アドレスの要請


Access Twitter's REST API


  • サポートされている Twitter API を簡単に実装できる

  • 拡張し標準でサポートされていない Twitter API も作成可能


Show Tweets


  • 公式標準の TweetUI を開発者のアプリケーションに簡単に埋め込むことが可能

  • リスト表示にも対応

  • ダークモードに対応

  • デザインのカスタマイズに対応

  • Tweet Action に対応


Show Timelines


  • タイムラインを検索し一覧表示することができる


Compose Tweets


  • Tweet 機能を開発者のアプリケーションに簡単に組み込むことが可能

  • メッセージと画像投稿に対応


Access Twitter’s REST API

今回のメインはこちらになります。

Fabric の機能で REST API が利用可能なので、こちらの機能を使って対応を進めていくことにします。

まず、標準で対応してれば、標準で対応したいと思います。

(対応していれば苦労しなかったんですけどねw)


標準対応している API


  • Statuses (Tweets)


    • mentionsTimeline

    • userTimeline

    • homeTimeline

    • retweetsOfMe

    • show

    • lookup

    • update

    • retweet

    • unretweet

    • destroy



  • Favorites


    • list

    • create

    • destroy



  • Search


    • tweets



  • Lists


    • statuses



  • Collections


    • entries



この一覧が何を示しているかよくわからない人のために!

こちらは、Twitter API の URL Path になり、それぞれ Path ごとで機能が分かれています。

具体的な内容については、REST APIs をご覧ください。


Statuses (Tweet)

ざっくりとですが、Tweet関連の機能がまとめられている API 群です。


POST statuses/update_with_media

POST statuses/update_with_media


Tweet 投稿と一緒にメディアを投稿するためのAPIになります。

今までのうる覚えで使おうと思っていたのですが、Twitter Kit では標準対応されていません。

また、お気付きの方がいると思いますが、こちらの API は deprecated になっていました。

こちらの API は非推奨なので利用するのはやめましょう。

ということは、別の対応方法が存在します。


POST media/upload

POST media/upload


Twitter へメディアを登録するAPIになります。

60分間サーバーに保持してくれる?ので、その間にアップロードした画像を Tweet へ反映させなければいけません。


POST statuses/update

POST statuses/update


Tweet を投稿するAPIになります。

Tweet する際に MediaID を同梱することで、メディア付きな Tweet を投稿することが可能です。

この二つのAPI を利用することで画像投稿が可能になります。


実装編

※実際に実装したソースコードを抜粋しているため、導入する際は、よしなにしてください!


Twitter Login

Twitter ログインを行う。

Twitter ログインページを表示しアカウント情報を入力する画面が表示される。

TwitterCore twitterCore = TwitterCore.getInstance();

twitterCore.logIn(activity, new Callback<TwitterSession>() {
@Override
public void success(Result<TwitterSession> result) {
// ログイン処理に成功
}

@Override
public void failure(TwitterException e) {
// ログイン処理に失敗
}
})


Twitter Tweet (POST statuses/update)

Twitte Kit 標準で用意されている、Twitter へ Tweet する処理。

※ユーザーログイン処理がが完了していること!

TwitterSession twitterSession = TwitterCore.getInstance().getSessionManager().getActiveSession();

StatusesService statusesService = new TwitterApiClient(twitterSession).getStatusesService();
statusesService.update("Tweet Message.", null, false, null, null, null, false, false, new Callback<Tweet>() {
@Override
public void success(Result<Tweet> result) {
// 投稿処理成功
}

@Override
public void failure(TwitterException e) {
// 投稿処理失敗
}
});

Tweet ですが、こちらの標準だと、メディアを追加することができません。

ということから、こちらの処理を自前実装します。


StatusesService の拡張

標準で用意されている'StatusesService#update'に'media_ids'が対応していませんでしたので、

再定義し自身のinterfaceクラスを定義します。

Twitter Kit の通信処理では、Square の Retrofit を利用しています。

public interface SKNStatusesService {

...
@FormUrlEncoded
@POST("/1.1/statuses/update.json")
void update(
@Field("status") String status,
@Field("in_reply_to_status_id") Long inReplyToStatusId,
@Field("possibly_sensitive") Boolean possiblySensitive,
@Field("lat") Double lat,
@Field("long") Double longDouble,
@Field("place_id") String placeId,
@Field("display_cooridnates") Boolean displayCooridnates,
@Field("trim_user") Boolean trimUser,
@Field("media_ids") String mediaIds,
Callback<Tweet> cb);


TwitterApiClient の拡張

実際に先ほど作った、SKNStatusesService.class を生成する処理を実装します。

SKNStatusesServiceを使うときは必ず、このメソッドを利用します。

public class SKNTwitterApiClient extends TwitterApiClient {

...
public SKNStatusesService getfalStatusesService() {
return (SKNLStatusesService)this.getService(SKNStatusesService.class);
}


Twitter Tweet with MediaID (POST statuses/update)

#extensions

先ほど作った、SKNStatusesService と SKNTwitterApiClient を使うぐらいで、あとは標準のと変わりありませんね!

案外簡単に拡張することが可能なのがわかります。

TwitterSession twitterSession = TwitterCore.getInstance().getSessionManager().getActiveSession();

SKNStatusesService statusesService = new SKNTwitterApiClient(twitterSession).getfalStatusesService();
statusesService.update("Tweet Message.", null, false, null, null, null, false, false, "media_id_string1,media_id_string2,media_id_string3,media_id_string4", new Callback<Tweet>() {
@Override
public void success(Result<Tweet> result) {
// 投稿処理成功
}

@Override
public void failure(TwitterException e) {
// 投稿処理失敗
}
});

ここまですんなりできたでしょうか?

さて、次に問題になってくるのが、MediaIDの取得です。

Android -> 画像 -> TypeFile -> POST -> Twitter -> MediaID

この流れで実際の画像から MediaID を生成し取得する必要があります。


画像を Twitter へ登録する


POST media/upload

残念ながら Twitter Kit では media/upload API に標準で対応していません。

対応していないのなら作るのが仕事!

さて作りましょう!

手順は先ほど statuses/update で対応した内容に +α します。


MediaService 作成

今回の API は画像のバイトデーターを送信するので、マルチパートにします。

public interface SKNMediaService {

...
@Multipart
@POST("/1.1/media/upload.json")
void upload(@Part("media") TypedFile media, Callback<Media> cb);


API Response Media の作成

media/Upload の Response の値を格納するモデルクラスを作成します。

public class Media {

@SerializedName("media_id")
public final long mediaId;
@SerializedName("media_id_string")
public final String mediaIdString;
@SerializedName("size")
public final long size;
@SerializedName("image")
public final Media.Image image;

public Media(long mediaId, String mediaIdString, long size, Image image) {
this.mediaId = mediaId;
this.mediaIdString = mediaIdString;
this.size = size;
this.image = image;
}

public static class Image {
@SerializedName("w")
public final long width;
@SerializedName("h")
public final long height;
@SerializedName("image_type")
public final String imageType;

public Image(long width, long height, String imageType) {
this.width = width;
this.height = height;
this.imageType = imageType;
}
}
}


FALTwitterApiClient の拡張

media/upload API では、Twitter API の HOST 名を変更する必要があります。

すんなり変更できると思ったのですが、今のところ、私がわかっているのは、こちらの方法です。

public class SKNTwitterUploadApiClient {

...
final ConcurrentHashMap<Class, Object> services;
final RestAdapter adapter;

static final String TWITTER_API_HOST_NAME = "https://upload.twitter.com";

SKNTwitterUploadApiClient(TwitterAuthConfig authConfig, Session session, TwitterApi twitterApi, SSLSocketFactory sslSocketFactory, ExecutorService executorService) {
if(session == null) {
throw new IllegalArgumentException("Session must not be null.");
} else {
this.services = new ConcurrentHashMap();
Gson gson = (new GsonBuilder()).registerTypeAdapterFactory(new SafeListAdapter()).registerTypeAdapterFactory(new SafeMapAdapter()).create();
this.adapter = (new RestAdapter.Builder()).setClient(new AuthenticatedClient(authConfig, session, sslSocketFactory)).setEndpoint(twitterApi.getBaseHostUrl()).setConverter(new GsonConverter(gson)).setExecutors(executorService, new MainThreadExecutor()).build();
}
}

public SKNTwitterUploadApiClient(Session session) {
this(TwitterCore.getInstance().getAuthConfig(), session, new TwitterApi(TWITTER_API_HOST_NAME), TwitterCore.getInstance().getSSLSocketFactory(), TwitterCore.getInstance().getFabric().getExecutorService());
}

public SKNMediaService getMediaService() {
return (SKNMediaService)this.getService(SKNMediaService.class);
}

protected <T> T getService(Class<T> cls) {
if(!this.services.contains(cls)) {
this.services.putIfAbsent(cls, this.adapter.create(cls));
}

return (T) this.services.get(cls);
}s


POST media/upload 実装編

※ユーザーログイン処理がが完了していること!

File mediaFile ...

TypedFile typedFile = new TypedFile("multipart/form-data", mediaFfile);
...

TwitterSession twitterSession = TwitterCore.getInstance().getSessionManager().getActiveSession();
SKNMediaService mediaService = new SKNTwitterUploadAPIClient(twitterSession).getMediaService();
mediaService.upload(typedFile, new Callback<Media>() {
@Override
public void success(Result<Media> result) {
// メディア登録完了
}

@Override
public void failure(TwitterException e) {
// メディア登録失敗
}
});

以上長くなってしまいましたが、こちらが、Fabric で 画像を Tweet する処理になります。


まとめ


  • Fabric

  • Retrofit

  • POST statuses/update の拡張

  • POST media/upload の作成

  • TwitterUploadApiClient の拡張

  • Media モデルクラスの作成

  • MediaService の作成

わかると意外に簡単ですが、意外に情報が無く結局自分でコードを読むことで解決することができました。

みなさんの参考になればと思います。