万人のためのモバイル: 自作の Android アプリに署名を付け、封印し、配布する

Android モバイル・アプリに多肢選択式のクイズを追加した後、セキュアなデジタル証明書とともに署名を付ける

Web ロジックではコンテンツが何よりも重要ですが、モバイル・ユーザーにとってはアプリとの対話がすべてを支配します。モバイル・アプリでは、静的な情報によるデザインが行われなくなり、代わりにゲーミフィケーションが採用されるようになっています。今回の記事では、Andrew Glover が Android モバイル開発の紹介を完結するために、前回の記事で紹介したサンプル・アプリケーションの Overheard Word に多岐選択式クイズの機能を追加します。その後、デジタル署名を生成する方法、そして署名付きのアプリを Android 向けの Google Play または Amazon Appstore で公開して宣伝する方法を説明します。

Andrew Glover, CTO, App47

Andrew GloverAndrew Glover は開発者であり、モバイル・テクノロジーにはまっています。現在 App47 の CTO を務める彼は、easyb BDD (Behavior-Driven Development) フレームワークの作成者でもあり、『継続的インテグレーション入門 開発プロセスを自動化する 47 の作法』、『Groovyイン・アクション』、『Java Testing Patterns』の 3 冊の本の共著者でもあります。彼の最新情報を追うには、ブログを読むか、Twitter でフォローしてください。



2013年 10月 03日

この連載について

モバイル・アプリの配布が急増するなか、モバイル開発のスキルを要する市場が急成長しています。この連載では、プログラミングの経験は積んでいても、モバイルの世界でのプログラミングには馴染みのない開発者を対象に、モバイルの世界でのプログラミング をわかりやすく紹介します。

まず Java コードでネイティブ・アプリを作成することから始め、JVM 言語、スクリプティング・フレームワーク、HTML5/CSS/JavaScript、サード・パーティー・ツールなどを使いこなせるようにモバイル開発のスキルを磨いていきます。ステップ・バイ・ステップで、ほとんどどのようなモバイル開発シナリオにも対応できるだけのスキルをマスターしてください。

この連載のこれまでの記事をすべて読んでください。

連載「万人のためのモバイル」では、これまでのところ、モバイル開発の方法を学ぶエントリー・ポイントとして Android を使用して、Android アプリのライフサイクルに関するハウツー情報、Android アプリにスワイプ・ジェスチャー機能を実装する方法、開発の簡素化とアプリの機能強化を目的にサード・パーティー・ライブラリーを利用する方法などを説明してきました。Android についての説明が完了したわけではありませんが、私は他のモバイル環境やモバイル手法についても探りたくてうずうずしています。そこで、今回はこの Android にフォーカスした一連の記事を締めくくるために、Overheard Word デモ・アプリにクイズの機能を追加して、人気の高い 2 つの Android 向けアプリ・ストアである Google Play と Amazon Appstore にデプロイするための準備を整えます。このすべての作業が、次のステップに進むための基礎となります。次のステップとは、HTML5 を使用したモバイル開発に取り組むことです!

アプリにゲームの要素を盛り込む

Overheard Word に署名を付けて Android 市場向けの Google Play と Amazon Appstore に送信し、他の何百万ものアプリと張り合う前に、この Overheard Word をできる限り最高のアプリにしたいと思います (Overheard Word アプリを十分に理解していない場合は、このデモ・アプリを紹介している記事に戻ってください)。ご存知のとおり、ゲームは現在のモバイル・エコシステムの推進力であり、真面目なアプリにでさえも、高度な対話性が求められています。好奇心と「勝ちたい」という気持ちを刺激するモバイル・アプリは、その目的が情報価値を提供することであったとしてもうまく行きます。これが、Overheard Word が単にページ上で単語のリストを作成するだけのアプリではなく、ボキャブラリーをさらに増やす意欲をユーザーに起こさせて、単語を学習したことに対してご褒美を与えるようにデザインされている理由です (ちなみにゲーミフィケーションとは、このデザイン手法を表す、今流行っている言葉です)。

無償の評価版ソフトウェア

IBM Worklight で Android アプリをテストしてください。

IBM Worklight Developer Edition は無償の Eclipse プラグインです。Android 端末だけでなく、iOS、Blackberry、および Windows Phone 端末を対象としたネイティブ・アプリ、Web アプリ、ハイブリッド・アプリを視覚的に作成、テスト、デプロイするための開発プラットフォーム兼サーバー・プラットフォームを提供します。詳しくは、ここをクリックしてください。

Worklight Developer Edition をダウンロードするには、このボタンをクリックします。

Overheard Word の粘り強さ (つまり、端末ユーザーの興味を引き付けて離さないこと) は、さらに強化できると思います。これを目的に、今回は既存のプログラムに新しい Activity クラスを追加して、ボキャブラリーの単語の定義、そしてその下にその定義に当てはまる単語の選択肢が表示されるようにします。ユーザーが選択肢のなかから正しい単語を選択すると新しい定義が表示され、間違った単語を選択すると再挑戦のチャンスが与えられるという仕組みです。

この新規 Activity のレイアウトでは、連載でまだ使ったことのないコンポーネントとして RadioGroupRadioButton を利用します。また、これらの要素のために TextView を追加する必要もあります。単語の定義はユーザーが学習した単語に基づかせるため、ここでも Thingamajig ライブラリーを利用することになります。さらにこの機会を利用して Android の IntentHandlerBundle を使用したプログラミングについても説明するつもりです。

Overheard Word をクイズ形式にする

まずは Overheard Word のクイズ・ビューに合った新しいレイアウトを定義した上で、そのレイアウトを表示する Activity を定義します。これまでの記事と同様に、今回も Eclipse ADT (「参考文献」を参照) を開発環境として使用するので、皆さんも同じ開発環境を使用していることを前提とします。

プロジェクト内で、「New (新規)」「Android XML File (Android XML ファイル)」の順に選択します。以下の図に示すように、「Resource Type (リソース・タイプ)」として「Layout (レイアウト)」が選択されていること、「Root Element (ルート要素)」として「RelativeLayout」が選択されていることを確認してください。

図 1. Eclipse 内で新規レイアウトを作成する
Eclipse Android 開発ツールを使用して新規レイアウトを選択および構成する

レイアウトにはどのような名前を付けても構いませんが、アプリのどの Activity にレイアウト・ファイルが関連付けられているかを簡単に突き止められるようなパターンにすることをお勧めします。

次に、以下の XML をコピーして新規ファイルに貼り付けます。

リスト 1. Overheard Word のクイズ・レイアウト
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".OverheardWord" >

    <LinearLayout
        android:id="@+id/widget33"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="20dp"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/quiz_definition"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="20dp"
            android:layout_marginLeft="13dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="48dp"
            android:text="Definition"
            android:textSize="18sp" />

        <RadioGroup
            android:id="@+id/quiz_answers"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="17dp" >

            <RadioButton
                android:id="@+id/quiz_answer_1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Answer 1" />

            <RadioButton
                android:id="@+id/quiz_answer_2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Answer 2" />

            <RadioButton
                android:id="@+id/quiz_answer_3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Answer 3" />
        </RadioGroup>

        <TextView
            android:id="@+id/quiz_result"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="40dp"
            android:layout_marginTop="20dp"
            android:lines="2"
            android:text="Result"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/quiz_number"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:layout_marginTop="30dp"
            android:gravity="right"
            android:text="1/10" />
    </LinearLayout>

</RelativeLayout>

学習ガイドの UI を定義する、Overheard Word の既存のレイアウト・ファイルと同様に、上記レイアウトでは一連の UI 要素をサンプル・テキストとともに定義することで、アプリが実行されているときに、どのような表示になるのかがすぐにわかるようにしています。クイズ・レイアウトには、特定の定義を保持する TextView と、その定義に当てはまる単語の選択肢のための RadioGroup が含まれます。ユーザーが単語を選択すると、アプリはイベントの通知を受けて即時に応答し、新しい質問を表示するか、または再挑戦のチャンスを与えます。このレイアウトには、ユーザーのクイズの進行状態を追跡するカウンターもあります。

次のステップとなるのは、新規 Activity クラスを作成することです。リスト 2 に示すように、このクラスは Activity を継承して、onCreate メソッドを提供する必要があります (setContentView が、リスト 1 で作成した新規レイアウト・ファイルを指定していることに注意してください)。

リスト 2. 新規 Activity クラス: OverheardQuiz
import android.app.Activity;
import android.os.Bundle;

public class OverheardQuiz extends Activity {

 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_overheard_quiz);
 }
}

続いて、この新規 Activity をインスタンス化し、最終的に Overheard Word のクイズ・レイアウトを表示させるようにします。クイズの起動については、メニュー項目から選択してクイズを起動するのではなく、スワイプ・ジェスチャー機能を使用してクイズを起動させるようにしましょう。後で、クイズをアプリのメニューに追加することも可能です。


Intent を使用したプログラミング

前にも説明したとおり、Android 端末はバッテリー容量、処理能力、メモリーに関して極めて制約されています。個人で使用する端末のほとんどは、電話とメールの機能に加え、アプリケーションも数多くホストしています。そのため、端末では複数のアクティビティーが同時に進行することになります。Android プラットフォームはこれを管理するために、開発者が任意の時点でアプリに実行させる内容に関して特定の制限を設けています。例えば、開発者が Activity クラスを強制的に起動して、そのクラスのビューを表示することはできません。代わりに、開発者はプラットフォームに対し、Activity を起動する「意向 (intent)」を通知します。すると、プラットフォームは可能なタイミングで Activity を起動します。

Intent とは、タスクを実行するための非同期メカニズムであると考えてください。実行する必要があるタスクをプラットフォームに提示すると、プラットフォームは実行可能なときにそのタスクを実行します。ユーザーの観点からすると、これは即時に行われるのが通常です。

したがって、ただ単に Activity を起動するのではなく、ActivityIntent の内部にラップする必要があります。こうすれば、後は Android が代わって Activity を起動してくれます。新しいクイズ Activity を起動するにはジェスチャーを使用するため、この私たちの意向を GestureDetector インスタンスに追加します (GestureDetector についての詳細は、連載の前の 2 回の記事を参照してください)。isUpSwipe 条件で false を返す代わりに、以下のようにして新規 Intent を起動します。

リスト 3. 新規 Activity を GestureDetector に追加する
//.....
if (detector.isDownSwipe()) {
  return false;
} elseif (detector.isUpSwipe()) {
  startActivity(new Intent(getApplicationContext(), OverheardQuiz.class));
} elseif (detector.isLeftSwipe()) {
//.....

Intent は、コンテキストと起動対象のクラスを引数に取ることに注意してください。startActivity は、すべての Activity インスタンスにあるメソッドです。

試しに、エミュレーター・インスタンスを起動して、単語が表示されたら上にスワイプしてください。図 2 に示す新規 Activity が表示されるはずです。

図 2. クイズができあがりました!
クイズ・レイアウトの初期ビュー (値は未設定) のスクリーン・ショット

このクイズはなかなかの見栄えですが、まだ UI ロジックを追加する必要があります。そのロジックのほとんどで、私が作成した Thingamajig ライブラリー (「参考文献」を参照) を使用するため、私たちはプログラムによる UI の強化に専念することができます。


上にスワイプ、下にスワイプ

まず始めに、ユーザーがクイズを終了して単語の学習に戻れるように、ジェスチャー・ディテクターを追加しなければなりません。上にスワイプするとクイズが表示されるので、クイズを終了するには下にスワイプするのが直観に合った操作です。Activity クイズを終了して学習モードに戻るには、finish を呼び出します。

リスト 4. スワイプ・ジェスチャー内で finish を呼び出す
private GestureDetector initGestureDetector() {
    return new GestureDetector(new SimpleOnGestureListener() {

      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        try {
          final SwipeDetector detector = new SwipeDetector(e1, e2, velocityX, velocityY);
          if (detector.isDownSwipe()) {
            finish();
          } else if (detector.isUpSwipe()) {
            return false;
          } else if (detector.isLeftSwipe()) {
            return false;
          } else if (detector.isRightSwipe()) {
            return false;
          }
        } catch (Exception e) {
          // nothing
        }
        return false;
      }
    });
  }

以前の記事で、Overheard Word の学習 Activity 内にアクション・バーを実装し、このアクション・バーを使用してアプリを終了できるようにしました。今回は、そのコードに別の目的を持たせて、クイズ専用の新しい quit 関数を作成します。

リスト 5. クイズを終了するためのアクション・バー
@Override
public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.overheard_quiz, menu);
  return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case R.id.quit_quiz:
    this.finish();
    return true;
  default:
    return super.onOptionsItemSelected(item);
  }
}

ここで終了したいのはクイズだけであって、アプリは終了したくないことに注意してください。そのため、アクション・バーのテキストを「Quit (終了)」ではなく「Quit Quiz (クイズの終了)」に更新しています。

単語と定義

次に、1 つの正しい答えと 2 つの誤った答えを設定した定義をセットアップします。ロジックには Thingamajig を使用していることから、ここで必要な作業は、関連するフィールドにデータを取り込むことだけです (リスト 6 を参照)。

リスト 6. 定義と併せてテスト可能な単語をセットアップする
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_overheard_quiz);
    initializeGestures();
    
    List<Word> words = buildWordList();

    if (engine == null) {
      engine = WordTestEngine.getInstance(words);
    }

    final TestableWord firstWord = engine.getTestableWord();
    final TextView testDefinition = (TextView)findViewById(R.id.quiz_definition);
    testDefinition.setText(formatDefinition(firstWord.getValidDefinition()));

    final List<String> possibleAnswers = possibleAnswersFrom(firstWord);

    final int[] radios = { R.id.quiz_answer_1, R.id.quiz_answer_2, R.id.quiz_answer_3 };
    for (int x = 0; x < radios.length; x++) {
      final RadioButton rButton = (RadioButton)findViewById(radios[x]);
      rButton.setText(possibleAnswers.get(x));
    } 
}

リスト 6onCreate メソッドは、まず指定されたレイアウトに基づいて View を作成し、それに続いてジェスチャーを初期化します。元の学習 Activity の仕組みと同じように、(WordStudyEngine ではなく) WordTestEngine インスタンスが作成されて、Overheard Word の単語のストア (この例の場合は JSON ファイル) に接続されます。possibleAnswersFrom メソッドは 3 つの定義のリストを返します。そのうちの 1 つが正しい定義です。WordTestEngine インスタンスは定義をシャッフルするため、クイズは常に同じ順序で再生されるわけではありません。

最後に、for ループによって RadioButton に値が取り込まれます。これらの値は、その特定の定義と一致する可能性のある単語です。現時点でアプリのインスタンスを起動すると、単語の定義と、3 つの単語の選択肢がクイズのインターフェースに表示されるようになっています。

図 3. 単語と定義が表示されたクイズ UI
単語の定義と、3 つの単語の選択肢を表示するように更新されたクイズ・インターフェースのスクリーン・ショット

画面の一番下にある静的な「Result (結果)」ボタンと、用意されているクイズの質問のうち、使用された質問の数を示すカウンターにも注目しください。上記のスクリーン・キャプチャーでは、10 個の質問のうちの 1 つが使用されたことが示されています。

コードをお忘れなく!

Git リポジトリー内にある Overheard Word にアクセスして、完全なアプリケーション・ソース・コードを確認してください。

ここまでの作業で、Thingamajig と前の Activity ロジックの一部を使用してクイズの定型ロジックを手早く作成しました。次は、ハンド・コーディングしなければならないクイズの部分に対処します。それは、複数の選択肢から解答を選ぶためのラジオ・ボタンです。項目を選択したことを示すためにユーザーに別のボタン (「Submit (送信)」など) をタップさせるのではなく、ラジオ・グループ自体の振る舞いに接続して、項目が選択されるのをリッスンすることにします。こうすれば、ユーザーは即時にフィードバックを受け取ることになるため、さらに別のボタンをタップする必要がなくなります。


Handler を使用したイベント・スケジューリング

ユーザーが単語を選択すると、ユーザーに対して即時にフィードバックが提供されるようにしたいと言いましたが、それだけではありません。そのフィードバックを表示しておくために短い時間の一時停止をするようにも Overheard Word をプログラミングしたいと思います。ユーザーの解答が正しい場合、ユーザーは次の質問に挑戦する前に、少しの間その喜びを味わいたいはずと考えたからです。解答が誤っている場合には、ユーザーに再度挑戦させるか、あるいは正しい解答を表示する間、画面を 1、2 秒間そのままの状態にする必要があります。いずれにしても、このクイズでは、ユーザーには自分の行動から学習するチャンスが与えられます。

ただし、Android アプリでは開発者が好きなことを何でもできるわけではないことを思い出してください。オンデマンドでアプリをスリープ状態にしたり、スレッドを起動したりすることはできません (もちろん、Android アプリでスレッドを起動することは可能ですが、さまざまな関連要因を制御することはできません)。Intent を使用して意図する動作を Android アプリに指示するのと同じく、遅延または並列アクションの要求を示すには、Handler を使用します。Android がその要求を処理する方法は、Android に任されます。

一時停止をお願いします

Android では、イベントのスケジューリングだけでなく、スレッド間でのメッセージ・パッシングにも Handler を使用します。この例の場合、Handler でイベントをスケジューリングし、それを Runnable インスタンスでカプセル化します。

ユーザーが単語を選択するというイベントに応答して Handler のインスタンスを作成し、Runnable インスタンス内部で何らかのロジック (新規 Activity を表示するなど) を渡し、数秒間の遅延を設定します。

ラジオ・ボタンのタップに接続するために、onCheckedChangeListener を実装し、これを RadioGroup のインスタンスに接続します (リスト 7 を参照)。

リスト 7. setOnCheckedChangeListener
final RadioGroup group = (RadioGroup)findViewById(R.id.quiz_answers);
    group.setOnCheckedChangeListener(new OnCheckedChangeListener() {

      @Override
      public void onCheckedChanged(final RadioGroup group, final int checkedId) {
        final RadioButton selected = (RadioButton)findViewById(checkedId);
        final String answer = (String) selected.getText();
        if (answer.equals(firstWord.getSpelling())) {
          final TextView result = (TextView)findViewById(R.id.quiz_result);
          result.setTextColor(Color.parseColor("#228b22"));
          result.setText("Correct!");
          final Handler handler = new Handler();
          handler.postDelayed(new Runnable() {
            public void run() {
              final Intent nextQuiz = new Intent(getApplicationContext(), OverheardQuiz.class);
              startActivity(nextQuiz);
              result.setText("");
              finish();
            }
          }, 2500);
        } else {
          final TextView result = (TextView)findViewById(R.id.quiz_result);
          result.setTextColor(Color.parseColor("#ff0000"));
          result.setText("Nope, that's not it! Try again.");
          final Handler handler = new Handler();
          handler.postDelayed(new Runnable() {
            public void run() {
              selected.setChecked(false);
              result.setText("");
            }
          }, 2000);
        }
      }
    });

Java AWT や Swing を使用した従来の GUI プログラミングと同じように、イベントにはリスナーを接続することができます。この例では、OnCheckedChangeListenerRadioGroup に接続しているため、ユーザーが RadioButton を選択すると、このリスナーのコードが実行されます。ユーザーの選択が正しければ、OverheardQuizActivity の新規インスタンスに新しい単語が表示されます。さらにユーザーに対し、TextView 内に緑色のテキストでレンダリングされた「Correct!」というフレンドリーなメッセージも表示されます。

ユーザーが誤った単語を選択した場合は、テキストの結果が赤色で表示され、ユーザーが再度挑戦できるように Activity の UI がリセットされます。

スレッドの起動を遅延する 2 つの Handler インスタンスにも注目してください。一方のインスタンスでは新規 Intent が起動され、もう一方のインスタンスでは UI がリセットされます。

リスト 1 のクイズ・レイアウト定義から、デフォルトのテキストを削除する必要もあります。それには、該当する XML ファイルに戻って、ID が quiz_result に設定された TextView から android:text="Result" の行を削除します。それが終わったら、アプリを起動して確認してください。


Android の Bundle

最後に必要な作業は、クイズ・ビューの右下隅に表示されるカウンター (図 3 を参照) にロジックを追加することです。ユーザーがクイズを進めていくとともに、その進行状態と残っている質問の数をユーザーに示す必要があります。このカウンターを動作させるには、カウンターの状態を保持する何らかの手段が必要です (例えば、カウンターが 2 であった場合、今度は 3 にするなど)。これはつまり、あるアクティビティーから次のアクティビティーにデータを渡すことができなければならないことを意味します。この処理のために使用するのが、Bundle です。

この連載を読み続けているとしたら、その間に Bundle を目にしたことがあるはずです。それは、Bundle インスタンスはあらゆる ActivityonCreate メソッドにとって唯一のパラメーターであるためです。

Bundle は基本的に、キーと値のペアを格納する Map です。キーの値は、値の型に対応するメソッド呼び出しによって取得することができます。Bundle は、Activity インスタンスの一部であるだけでなく、Intent にも含まれています。事実、新規 Activity に関連付けられた Intent 内にキーと値のペアを組み込むと、その Activity を作成した Intent を介して該当する Bundle を取得することができます。以上の内容は複雑なように聞こえるかもしれませんが、一度自分で作業してみると、理解できるはずです。

カウンターを作成する

最初に、新規 OverheardQuizActivity を作成する Handler を更新して、増分式カウンターを追加します (リスト 8 を参照)。

リスト 8. 増分式カウンターを追加する
final Handler handler = new Handler();
  handler.postDelayed(new Runnable() {
    public void run() {
      final Intent nextQuiz = new Intent(getApplicationContext(), OverheardQuiz.class);
      nextQuiz.putExtra(QUIZ_NUM, ++quizNumber);
      startActivity(nextQuiz);
      result.setText("");
      finish();
    }
  }, 2500);

putExtra メソッドは、キー QUIZ_NUM を値 quizNumber に関連付けます。このキーと値は、どちらも OverheardQuiz クラスのメンバー変数です。

次に、OverheardQuiz クラスの onCreate メソッドを更新して、このメソッドを起動した Intent から上述の値を取得します。onCreate は、値が見つからなければ、値は 1 であると想定します。OverheardWordActivity から初めて起動されたインスタンスは QUIZ_NUM 値を設定しないため、これは理にかなった想定です。値が 10 より大きい場合は、シーケンスがリセットされ、ユーザーには (トースト (Toast) を介して) お祝いのメッセージが送信されます。そして最後に、カウンターの TextView を新しいカウントで更新します。このすべての仕組みが、リスト 9 に示されています。

リスト 9. TextView を現在のカウントで更新する
final Bundle previous = getIntent().getExtras();
quizNumber = (previous != null) ? previous.getInt(QUIZ_NUM) : 1;

if (quizNumber > 10) {
  quizNumber = 1;
  CharSequence text = "Great Job! You made it through 10 questions. Here's another 10!";
  Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
}

final TextView quizCounter = (TextView)findViewById(R.id.quiz_number);
quizCounter.setText(quizNumber + " of 10");

早速 Overheard Word のこの最終版を起動して、アプリの動作を見てみましょう。

図 4. Overheard Word のクイズの答えは munificent で正解です!
正しい単語が選択されて更新されたカウンターを表示する完成版アプリのスクリーン・ショット

この状態であれば、アプリの成功を手中に収めたも同然です。このアプリは、迅速な動作をする直観的なインターフェースで価値あるサービス (ボキャブラリーの増強) を提供するだけでなく、今やユーザーが何度もトライするように意匠を凝らしたクイズ機能も備えています。UI デザインはもっと趣向を凝らしたものにできるはずですが (白い背景に黒のテキストというのは、かなり平凡なデザインです)、とりあえずはアプリに署名を付けて市場に送り出す段階に来ていると思います。


Android アプリに署名を付ける

世界中の人々の端末で自作のアプリが使われるようにするには、アプリを公開アプリ・ストアにデプロイする必要があります。アプリ・ストアは多数の選択肢の中から選択できるものの、Android 向けの Google Play と Amazon Appstore の 2 つが最大のアプリ・ストアです (「参考文献」を参照)。セキュリティー上の理由から、この 2 つのアプリ・ストアでは、ホストするアプリには署名が付けられていることを条件としています。

アプリに署名を付けるときには、証明書を作成して、その証明書の秘密鍵を自分で所持します。その上で、その証明書を使用してコードにデジタル署名を付けます。署名とは、悪意を持っている可能性のある身元不明の者ではなく、自分がその特定のバイナリーをビルドして署名を付けたことを立証する手段です。Android 端末は署名の付いていないアプリ・インスタンスをインストールしないため、Android 開発者として成功したいのであれば、アプリに署名を付ける方法を知っている必要があります。

これまでの何回かの記事で Android 端末にテスト・アプリをインストールする方法を説明したときに、実際にアプリに署名を付けるために使用したのはテスト証明書でした。テスト証明書はテストの際に使用するには役立つものの、公開アプリ・ストアでは許容されません。今回は、Eclipse を使用して本物の証明書を生成する方法を説明します。

アプリに署名を付けるには、Eclipse ADT プロジェクト・メニューに進み、「Android Tools (Android ツール)」「Export Signed Application Package (署名付きアプリケーション・パッケージのエクスポート)」の順に選択します。これにより、新規証明書を生成するためのウィザードが起動されます。

図 5. Eclipse ADT 証明書ウィザード
Eclipse ADT 証明書ウィザードのスクリーン・ショット

このウィザードは、証明書を生成するための一連のステップを案内し、最後のダイアログで個人および職業の詳細を入力するよう求めます。Web サイトの SSL 証明書を購入したことがあるとすれば、同じようなプロセスに従ったことがあるはずです。ただし、Android の場合、このプロセスに証明局は関与しません。したがって、SSL 証明書を入手する場合よりも、アプリに署名を付けるプロセスのほうが遥かに簡単ですが、このプロセスでは不正な主張を行う可能性が出てきます。例えば、私がバンク・オブ・アメリカやコカコーラ社であると自称することを止めるものは何もありません。

図 6. 証明書用の身元識別情報
証明書用の身元識別情報を入力するフォームのスクリーン・ショット

プロセスに従って証明書と (秘密鍵を格納する) 鍵ストアを作成した後は、デジタル署名が付けられたアプリのインスタンスを .apk ファイルとしてエクスポートすることができます (図 7 を参照)。

図 7. OverheardWord.apk
Overheard Word の新しい宛先 apk ファイル名を示す証明書ウィザードのスクリーン・ショット

デジタル署名が付けられたアプリのインスタンスがあれば、少なくとも技術的には、それを自由に世界に配布することができます。アプリを配布するということは、署名を付けてアプリ・ストアに公開するだけの話ではありません。公開したアプリを宣伝する必要もあります。

アプリを宣伝する

公開アプリ・ストアは世界市場に参入するためのプラットフォームになりますが、アプリ市場の抜け目のないコンシューマーは何でもダウンロードするわけではありません。機能的で楽しめるパッケージでは、高い価値を提供するアプリを作成する方法を知らなければならないのと同じように、開発者はユーザーに試してみようとする気を起こさせる必要があります。アプリを Android 向け Google Play または Amazon Appstore にアップロード (つまり公開) するときには、次のいずれかのことを求められる可能性があります。

  • アプリの主要な特徴を明確にすること
  • 簡潔なフォーマットと詳細なフォーマットの両方で、キャッチ・フレーズを使用してアプリについて説明すること
  • アプリが検索でヒットするようなキーワードを指定すること
  • さまざまなサイズのアプリのスクリーン・ショットをアップロードすること
  • 実行中のアプリの動画を提供すること

当然、アプリを無料で提供するか、有料で提供するかを決定する必要もあります。アプリを有料にする場合には、適切な相場の価格を設定しなければなりません。まさに、アプリを作成して署名を付けるのは簡単な部分だと思うことでしょう。モバイル・アプリを成長著しい競争市場で売るのは、大変な作業なのです!


まとめ

ご存知のとおり、ネイティブ Android 開発は、モバイル・アプリを作成する際の 1 つの選択肢に過ぎません。この連載の次回の記事では、話題を変えて、HTML5 を使用したモバイル Web アプリの作成について検討します。Web ベースのモバイル・アプリには、ネイティブ・アプリに勝る利点がいくつかあります。その 1 つは、どこででも配布できるという点です。ただし、Web ベースのアプリはネイティブ・アプリほど洗練されていないことが多く、ネイティブ・アプリと同じレベルのパフォーマンスを発揮できるとは限りません。今後は、HTML5 の詳細を探りながら、モバイル Web アプリの利点と制約の両方を探ります。

参考文献

学ぶために

製品や技術を入手するために

  • Worklight: IBM Worklight を使用して、iOS 端末、Android 端末、Blackberry 端末、および Windows Phone 端末向けのネイティブ・アプリ、Web アプリ、ハイブリッド・アプリを容易に作成、再利用してください。
  • Overheard Word: この Github リポジトリーには、この記事でデモに使用したモバイル・アプリのソース・コードが含まれています。
  • Thingamajig: この Github リポジトリーには、単語の定義を学習したり、クイズにしたりすることを許可する単純な単語定義エンジンのソース・コードが含まれています。
  • Android のダウンロード: ADT バンドルが組み込まれた Android SDK は、Android 向けアプリのビルド、テスト、デバッグに必要な API ライブラリーと開発者ツールを提供します。

議論するために

  • developerWorks コミュニティーに参加してくださいい。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Mobile development, Java technology, Open source
ArticleID=946925
ArticleTitle=万人のためのモバイル: 自作の Android アプリに署名を付け、封印し、配布する
publish-date=10032013