Movable Type Data API SDK for Androidの開発

公開

AndroidアプリからMovable Type Data APIを利用しやすくするために、Movable Type Data API SDK for Swiftを参考にして「Movable Type Data API SDK for Android(仮称)」を開発しました。

開発の経緯

目指したのは以下の3点です。

  • DataAPIに関するコードの分離
  • 汎用的なライブラリ化
  • メンテナンス性の向上

以前にも触れましたが今年の夏、親会社からの社命によりiPhoneアプリの学習を始めました。その後MTのDataAPIを利用して記事を表示するサンプルアプリができた頃、「次はAndroidで...」という社命が下りました。しかし、iPhoneに注力したこともあって書籍を読んでもなかなか理解が深まりません。また、「WEB TOUCH MEETING #86 を終えて考えたこと」で触れたように、広く浅く知識を得るより深い知識を得るほうが社会・プロジェクトにより貢献できるのではと考えているため、学習意欲も今ひとつ湧きませんでした。

しかし本を途中まで読み進めてサンプルアプリを作る中で、Movable Type Data API SDK for SwiftをJavaで移植すると、Androidアプリのコードがきれいに分離できたりDataAPIが使いやすくなったりして役立つのではと考えたこと、またその開発ならば僕でもできそうだったと考え、土日の休みを利用して開発に取り組むことにしました。
Movable Type Data API SDK for Android(仮称)を利用して、Androidアプリに記事一覧を表示した画面

成果物

現在できあがっているコードをApiSdkDevリポジトリに格納しています。

ちなみに現在実装完了しているエンドポイントは以下の項目です。

  • 認証
  • 記事の取得
  • 記事の操作(作成・更新・削除)
  • 検索
  • カテゴリの取得

導入方法

app/build.gradleへ以下のように記述します。

apply plugin: 'com.android.application'

android {

    // 省略

    packagingOptions {
        exclude 'META-INF/LICENSE'
    }
}

dependencies {

    // 省略

    compile 'pw.anothersky.movabletype.apisdk:mt-data-api-sdk-android:0.1.0'

    // 省略

}

repositories {
    maven {
        url 'http://raw.github.com/hideki-a/android-app-api-sdk-dev/master/repository/'
    }
}

サンプルコード

DataAPIを利用するためのコードが簡素になり、また都度URLを組み立てたりする必要もなく便利になったと感じています。

AsyncTaskで利用する

AsyncTaskで認証〜記事の投稿をする例です。

HashMap<String, String> authParams = new HashMap<String, String>();
authParams.put("username", mContext.getString(R.string.development_mt_username));
authParams.put("password", mContext.getString(R.string.development_mt_password));
authParams.put("remember", "1");
api.authentication(authParams, null);

HashMap<String, String> createParams = new HashMap<String, String>();
createParams.put("title", "DataAPI SDK for Androidからの投稿テスト");
createParams.put("body", "Movable Type Data API SDK for Androidからの投稿テストです。");
createParams.put("status", "Publish");
JSONObject createEntry = api.createEntry(3, createParams, null);

AsyncTask以外で利用する場合

AsyncTask以外で認証〜記事の投稿をする例です。

final DataApi api = DataApi.sharedInstance;
api.apiBaseUrl = getString(R.string.development);

HashMap<String, String> authParams = new HashMap<String, String>();
authParams.put("username", getString(R.string.development_mt_username));
authParams.put("password", getString(R.string.development_mt_password));
authParams.put("remember", "1");
DataApi.Callback authCb = new DataApi.Callback() {
    @Override
    public void onResponse(JSONObject json) {
        HashMap<String, String> createParams = new HashMap<String, String>();
        createParams.put("title", "コールバック内で記事を投稿するテスト");
        createParams.put("body", "Movable Type Data API SDK for Androidからの投稿テストです。コールバック内で投稿します。");
        createParams.put("status", "Publish");
        DataApi.Callback cb = new DataApi.Callback() {
            @Override
            public void onResponse(JSONObject json) {
                // ひとまずコンソールに出力
                Log.i("On MainActivity", String.valueOf(json));
            }
        };
        api.createEntry(3, createParams, cb);
    }
};
api.authentication(authParams, authCb);

MTの管理画面を見ると、以下の通り記事が作成されています。

サンプルコードを実行し、Movable Typeの管理画面に記事タイトルが表示されたところ

工夫した点

同期処理・非同期処理の両方に対応

Androidアプリについて書籍を読んで学習したものの、DataAPIへのリクエストを常にAsyncTask内で実行するのか否か疑問に思っていました。書籍によっては別のアプローチを取っていたように思いますし、同僚の話を聞くと常にAsyncTaskが使えるようでもなさそうでした。そこで、記述する場所を問わず利用できるよう、ひとまず同期処理・非同期処理の両方に対応しました。これは、OkHttpexecute()enqueue()を利用することで実現できました。

モジュール化

Swift版がCocoaPodsで導入できるように、Android版でもbuild.gradleにライブラリ名を書いて簡単に導入できるようにしたいと考えました。そこで、Android Studioで新規プロジェクトを作成した後、ライブラリモジュールのひな形を新規作成し開発を開始しました。

現在「Android のライブラリづくりとライセンスについて」などを参考にし、build.gradleにリポジトリとライブラリ名だけを書けばライブラリが利用できる状態になっています。

なお、JavaのIDEであるIntelliJ IDEAを使うと.aarではなく.jarが作成でき、AndroidだけでなくJavaのプロジェクトでも利用できるようになりそうです。.jarにした方がより多くの方に恩恵があるかなと思います。以下の画面はapp/libs/に.jarを入れてプロジェクトを開いた画面です。作成したクラスDataApiが利用できる状態になっています。
IntelliJ IDEAで生成した.jarファイルをAndroid Studioで読み込んで利用している画面

Javadocの生成

いくらよいライブラリモジュールを書いても使いにくければ意味がないでしょう。また、ドキュメントは品質向上・コスト削減のために必須だと考えています。Android StudioではメニューからJavadocの生成が可能なので、ひとまずパブリックメソッドにコメントを入れていきました。以下のURLで成果物が確認できます。

コードを分かりやすくするための補足コメントも、今後必要に応じて入れていきたいと考えています。

ユニットテストの実施

Android Studioでプロジェクトを作成すると、プロジェクト内にJUnitを利用したユニットテストのサンプルコードが入っていました。ライブラリモジュールの品質維持向上・開発コスト削減にはユニットテストは欠かせないと考え、ユニットテスト(DataApiUnitTest.java)も書いてみました。
Android Studioでユニットテストを実行した例

開発者ライセンスを利用してテスト専用のMovable Typeを用意し、指定の記事数が返ってくるか、記事の作成・編集ができるか、などをテストできるようにしました。

当初テストを動かしてみると全て成功になっていたのですが、実は非同期処理の完了を待たずに成功の判定が出ていたようです。「Awaitility」ライブラリを見つけて導入したところ、成否が正しく出るようになりました。

また、取得できているはずのレスポンスJSONがテストコード内で使えない問題が発生しました。Android APIsにはorg.jsonが含まれているのですが、JVM上でのテストではtestCompile 'org.json:json:20160810'を指定してインストールすることが必要でした。

ターミナルでgradlewコマンドを実行し出力したHTML形式のレポートは以下の通りです。

Travis CIで自動テスト・ビルド・ドキュメント生成を自動化

ユニットテストを書くと、GitHubへPushした際に自動テストを実行した後デプロイしたいという衝動に駆られました。自動テストができれば、テスト内容が開発したコードの内容を網羅している限りにおいて、不完全なコードのリリースが発生することがなくなるでしょう。

設定がなかなか上手くいかなかったのですが、「Travis CI Android example - Matti - Medium」というタイムリーな記事を見つけ試したところ、なんとか自動テストが意図通り実行された後に.aarファイルがビルドされJavadocが生成できるようになりました。Travis CIのhideki-a / android-app-api-sdk-devで結果をご覧いただけます。

なお、テキストファイルに書いているサーバー情報等は、travis encrypt-filesで暗号化してGitHubにPushしています。

まとめ

MTの話よりも、AndroidやJavaの話になってしまったかもしれませんが、一定の品質を保ちながらSDKの開発を進めることができるビルド環境が構築できました。今後、この環境を活かしてエンドポイントの追加を進めたいと考えています。そしてこのMovable Type Data API SDK for Android(Java?)でAndroidアプリ・JavaアプリとMovable Typeが容易に連携できるようになり、MTDDC Meetup TOKYO 2016のテーマにあった「CONNECTIVEな世界」の実現に役立てば幸いです。