月別アーカイブ: 2015年2月

PhoneGapアプリの公開用APKを作る

このページでは、PhoneGapで作ったAndroidアプリの公開用APKを作るまでを紹介します。APKは「android application package file」の略です。

事前準備

証明書を作る

Google playにアプリを公開するには、アプリに署名する必要があります。これは、アプリの正当性を保証するためです。
まず、署名するための証明書を作ります。keytoolはJDKに入っているので、パスが通っていればどこでも実行できます。パスワードなど色々聞かれるので、好きに答えてください。「よろしいですか?」と聞かれたら、「y」と答えれば次に進みます。

  今回の設定値
エイリアス名 shoarai
アプリ名 app
有効日数  10000
$ keytool -genkey -v -keystore .keystore -alias shoarai -keyalg RSA -validity 10000
> キーストアのパスワードを入力してください:
> 新規パスワードを再入力してください:
> 姓名を入力してください。
> 組織単位名を入力してください。
> 組織名を入力してください。
> 都市名または地域名を入力してください。
> 都道府県名を入力してください。
> この単位に該当する2文字の国コードを入力してください。
> ...でよろしいですか。
10,000日間有効な2,048ビットのRSAの鍵ペアと自己署名型証明書(SHA256withRSA)を生成しています
	ディレクトリ名: ... の鍵パスワードを入力してください
	(キーストアのパスワードと同じ場合はRETURNを押してください):

公開用APKを作る

APKを生成する

アプリの実装が完了したらリリースビルドし、APKを生成します。platforms/android/ant-buildにapp-release-unsigned.apkというファイルが生成されます。appの部分にはアプリ名が入ります。

$ phonegap build --release

署名する

事前に作った証明書でapkに署名します。

$ jarsigner -verbose -keystore .keystore app-release-unsigned.apk shoarai

最適化する

Google playにアプリを公開するには、最適化もする必要があります。最適化後のapkのファイル名をapp.apkとします。これで公開用APIの完成です。

$ zipalign -v 4 app-release-unsigned.apk app.apk

エラー

前述の最適化にて、zipalignコマンドが見つからないことがあります。

-bash: zipalign: command not found

zipalignはANDROID SDKのBuild-toolsに入っています。もしまだBuild-toolsが入ってないなら、Android SDK Managerからインストールしましょう。また、パスを通さないと実行できません。パスを通すのが面倒であれば、下記のように直接アクセスして実行してもいいです。

$ /Applications/android-sdk-macosx/build-tools/21.1.1/zipalign ...

ちなみに

APK生成、署名、最適化をまとめて行えるように下記のようなバッチファイルを作り、証明書と一緒にプロジェクトフォルダに置いておくと楽ですね。

MY_DIRNAME=$(dirname $0)
cd $MY_DIRNAME
# 設定値
UNSIGNED_FILE=platforms/android/ant-build/app-release-unsigned.apk
SIGNED_FILE=app.apk
ALIAS=shoarai
phonegap build --release
jarsigner -verbose -keystore .keystore $UNSIGNED_FILE $ALIAS
zipalign -v 4 $UNSIGNED_FILE $SIGNED_FILE

警告が表示される(2015-12-24追記)

いつの間にか、署名時に下記の警告が表示されるようになっていました。

警告:
-tsaまたは-tsacertが指定されていないため、このjarにはタイムスタンプが付加されていません。
タイムスタンプがないと、署名者証明書の有効期限(2043-05-10)後または将来の失効日後に
、ユーザーはこのjarを検証できない可能性があります。

JDK1.7からタイムスタンプが必要になったそうです。署名を下記のように修正すると警告が表示されなくなります。

$ jarsigner -verbose -tsa https://timestamp.digicert.com -keystore .keystore app-release-unsigned.apk shoarai

Nightwatch.jsのテストをいろいろなブラウザで動かす

WebアプリのUIテストができるSeleniumですが、それをラップして色々なAPIを提供してくれるのがNightwatch.jsです。アプリをJavaScriptで書いていて、テストも同じ言語で書きたい人には特におすすめです。

ただNighwatch単体だと不十分なところがあり、さらなるラッパーを探してたところhttps://github.com/sethmcl/nightwatchを発見。使ってみたところ動かず;そこで少し修正したものを公開します。特徴は下記のとおり。

  • Selenium Serverを事前に動かさなくていい。
  • ChromeとかIEでテストできる。
  • APIが簡単に作れる。

使い方

まずgithubからクローンしてください。

$ git clone https://github.com/shoarai/nightwatch.git
$ cd nightwatch
$ npm install

下記のコマンドで、デフォルトのテストが動きます。
Selenium Serverも組み込まれていて、勝手に動いて勝手に止まります。

$ npm test

ブラウザ選び

デフォルトのテストはFirefoxで動きますが、Google Chrome、Internet Explorerも選べます。Nigthwatchfile.jsを修正してください。

test_settings: {
  default: {
    ...
      desiredCapabilities: {
      browserName: 'firefox',
      // browserName: 'chrome',
      // browserName: 'internet explorer',
      ...

WindowsでChromeを使いたい場合は下記も修正してください。

selenium: {
  cli_args: {
    // 'webdriver.chrome.driver': './node_modules/.bin/chromedriver',      // in Mac
    'webdriver.chrome.driver': './node_modules/.bin/chromedriver.cmd',  // in Windows
    ...

APIを作る

tests/spec/search.jsでは、pageオブジェクトにあるhomepagesearch_resultsの2つのモジュールを使っています。これらを使うためにはbeforeにある処理が必要です。

var path = require('path');
module.exports = {
  tags: ['sanity', 'search'],
  before: function(client) {
    require('nightwatch-pages')(client, path.resolve(__dirname, '..', 'pages'));
  },
  'Bing search from homepage': function (client) {
    var searchTerm = 'selenium';
    client
      .page.homepage.load()
      .page.homepage.search(searchTerm)
      .page.search_results.assertResults(searchTerm)
      .page.search_results.navImages()
      .saveScreenshot('./screen/selenium.png')
      .end();
  }
};

tests/pages/search_results.jsに上記のsearch_resultsモジュールの関数が書いてあります。新しいモジュールを追加したい場合は、tests/pagesにモジュール名にしたい名前のファイルを追加してください。

module.exports = {
  selectors: {
    'resultDiv': '#b_results',
    'navImages': 'nav ul li:nth-child(2) a'
  },
  assertResults: function (text) {
    return this.client.assert.containsText(this.selectors.resultDiv, text);
  },
  navImages: function () {
    return this.client.click(this.selectors.navImages);
  }
};

以上です。よりよいテスト自動化を。

PhoneGapでアプリを作る

このページでは、PhoneGapをインストール後にサンプルプロジェクトを作成し、エミュレータで起動するまでを紹介します。

PhoneGapの導入

PhoneGapをインストールし、phonegapコマンドを使えるようにします。

事前準備

  • Node.jsがインストール済み
  • Antがインストール済み
  • Android SDKがインストール済み

PhoneGapのインストール

npmからPhoneGapをインストールします。

$ npm i -g phonegap

インストールが終わったら、PhoneGapのインストール状況を確認します。PhoneGapのコマンド一覧などが参照できます。

$ phonegap
...
Commands:
  create <path>        create a phonegap project
  build <platform>     build a specific platform
  install <platform>   install a specific platform
  run <platform>       build and install a specific platform
  local [command]      development on local system
  remote [command]     development in cloud with phonegap/build
  platform [command]   update a platform version
  plugin [command]     add, remove, and list plugins
  help [command]       output usage information
  version              output version number
...

プロジェクトの作成

PhoneGapコマンドから以下の内容を持つプロジェクトを作ります。このプロジェクトはAndroidやiOSなどのプラットフォームに共通のプロジェクトです。

プロジェクト名

まず、フォルダ名、パッケージ名、プロジェクト名は以下の通りとします。 ちなみにフォルダ名以外は未入力でも、デフォルトで設定されるので特に決めなくても大丈夫です。

  今回の入力値 デフォルト値
フォルダ名 Hello -(未入力不可)
パッケージ名 com.shoarai.hello com.phonegap.helloworld
プロジェクト名 HelloWorld Hello World

プロジェクトの生成

phonegapコマンドで上記の内容を持ったプロジェクトを生成します。

$ phonegap create Hello com.shoarai.hello HelloWorld

作成されるHelloフォルダの構成は以下の通りです。wwwフォルダ内にプラットフォームに共通するHTML、JavaScriptファイルがあります。

Hello
  ├─ .cordova
  ├─ merges
  ├─ platforms
  ├─ plugins
  └─ www

Helloフォルダに移動します。

$ cd Hello
.../Hello>

アプリケーションの作成

作成したプロジェクトからアプリケーションの実行ファイルを作成します。今回はAndroidアプリを作成しますが、PhoneGapはiosやWindowsPhoneのアプリも作成できます。

プロジェクトのビルド

phonegapコマンドでプロジェクトをビルドします。AndroidアプリケーションとしてビルドするためにAndroid SDKを利用しています。

$ phonegap build android
...
[phonegap] successfully compiled Android app

Androidアプリとしてビルドすると、platformsフォルダ内にandroidフォルダが作成されます。また、iOSとしてビルドするとiosフォルダが追加されることになります。 それぞれのフォルダ内に生成されるplartforms/…/wwwフォルダは、Hello/wwwフォルダがコピーされたものです。つまり、Hello/www内を編集して、 ビルドすると指定したplartforms/…/wwwが更新されることになります。

Hello
  ├─ .cordova
  ├─ merges
  ├─ platforms
  │      └─ android
  │             ├─ assets
  │             │     └─ www
  │              ...
  ├─ plugins
  └─ www

エラー

ビルド時に起こったエラーを記述しておきます。

Please install Android target 19 (the Android newest SDK)

これはPhoneGapが対応するAndroid SDKが入ってないよ!ということです。解決策は2つ。「①対応するSDK Platformをインストールする」または「②PhoneGap側のSDKの対応バージョンを変更する」です。 SDK側を合わせるか、PhoneGap側を合わせるかということです。
①は、エラー文にあるSDKバージョン(ここでは19)をインストールします。
②は、対応するバージョンを.cordova/lib/android/cordova/3.1.0(PhoneGapのバージョン)/frameworkフォルダ内のproject.propertiesファイルのtargetの値で確認できます。 ここではtarget=android-19をインストール済みのSDKのバージョン(android-18など)に変更します。

アプリケーションの実行

作成したAndroidアプリを実行します。

エミュレータの起動

まず、アプリを実行するエミュレータを起動します。AVD(Android Virtual Device Manager)を実行し、起動するエミュレータのAVD名を確認します。もしくは起動するAVDを新規作成します。

$ android avd

ここでは、AVD名がNexus5のエミュレータを起動します。

$ emulator -avd Nexus5

アプリケーションの実行

作成したAndroidアプリケーションをエミュレータで実行します。

$ phonegap run android
...
[phonegap] successfully installed onto emulator

phonegap
Androidアプリケーションをエミュレータで実行できました!実行前に実機を接続しておくと、優先して実機で実行されます。 このときは[phonegap] successfully installed onto deviceが表示されます。

ちなみに

今回は説明のためにアプリケーションのビルドと実行を分けましたが、phonegap run androidを実行すれば、phonegap build androidを実行しなくてもアプリケーションの実行ファイルが生成されてます。