TitaniumでiOS,AndroidアプリをCoffeeScript+TDDで爆速開発する環境構築手順メモ
さて、Titaniumによる開発についてこれまで個別にいろいろ調べてきたけど、一気に実際にアプリを開発するための環境についてまとめてみる。
目指す環境
これまでTitanium Studioと標準的エミュレータでサンプルアプリの開発+実行を行ってきたけど、やっぱりEclipseベースのIDEはストレスが高い。また特にAndroidに顕著だけど、標準のエミュレータは重すぎる。これではコーディング外のところで多く時間をとってしまう。
別のところでは、Rails開発をやってきているのでJavascriptはCoffeeScriptで書きたいし、なによりTDDできないと死んでしまう。
このあたりを解決するため、ここ数日調査をしたところ
- IDEの問題
- Titanium Command-Line Interfaceを利用したIDEに頼らない環境
- エミュレータ重すぎの問題
- TiShadowによる爆速デプロイ+実行
- CoffeeScript+TDD
- jmk+TiShadowを組み合わせたTDD環境
という構成がベストと思えたのでこの環境を作っていく。
前提
参考サイト
- http://sssslide.com/www.slideshare.net/keitarouoonishi5/titanium-alloycoffeejade
- https://speakerdeck.com/astronaughts/rapid-prototyping-by-tishadow
- http://www.yydigital.com/blog/2013/2/14/Testing_Alloy_With_Jasmine_And_TiShadow
- http://www.ari-hiro.com/blog/2013/05/26/introduce-alloy/
あとは都度。
プロジェクトの作成
まずはTitaniumプロジェクトを作成する。
http://docs.appcelerator.com/titanium/3.0/#!/guide/Titanium_Command-Line_Interface_Reference
http://www.absolute-keitarou.net/blog/?p=414
ログイン
$ titanium login
Titanium Command-Line Interface, CLI version 3.1.2, Titanium SDK version 3.1.2.GA
Copyright (c) 2012-2013, Appcelerator, Inc. All Rights Reserved.Please report bugs to http://jira.appcelerator.org/
Username: ria10@example.com
Password:Logged in successfully
プロジェクト作成
$ titanium create
Titanium Command-Line Interface, CLI version 3.1.2, Titanium SDK version 3.1.2.GA
Copyright (c) 2012-2013, Appcelerator, Inc. All Rights Reserved.Please report bugs to http://jira.appcelerator.org/
Target platforms: (android,blackberry,ios,ipad,iphone,mobileweb,tizen) android,iphone
App ID: com.example.ria10.titanium
Project name: sample
Directory to place project: .[INFO] Creating Titanium Mobile application project
~snip~
[INFO] Project 'sample' created successfully in 80ms
対話式なので、順に応えていく。AppIDなんかは、たぶんあとで変えられるんじゃないかな。
でProject nameで指定したディレクトリにプロジェクトのひな形一式が生成される。
$ ll
total 0
drwxr-xr-x 92 ria10 staff 3128 9 2 13:32 ..
drwxr-xr-x 8 ria10 staff 272 9 2 13:37 sample
drwxr-xr-x 3 ria10 staff 102 9 2 13:37 .$ cd sample
$ ll
total 56
-rw-r--r-- 1 ria10 staff 1766 9 2 13:37 tiapp.xml
-rw-r--r-- 1 ria10 staff 221 9 2 13:37 manifest
drwxr-xr-x 7 ria10 staff 238 9 2 13:37 Resources
-rw-r--r-- 1 ria10 staff 551 9 2 13:37 README
-rw-r--r-- 1 ria10 staff 11491 9 2 13:37 LICENSE
-rw-r--r-- 1 ria10 staff 33 9 2 13:37 .gitignore
drwxr-xr-x 3 ria10 staff 102 9 2 13:37 ..
drwxr-xr-x 8 ria10 staff 272 9 2 13:37 .
Alloy適用
$ alloy new
.__ .__
_____ | | | | ____ ___.__.
\__ \ | | | | / _ < | |
/ __ \| |_| |_( <_> )___ |
(____ /____/____/\____// ____|
\/ \/
Alloy by Appcelerator. The MVC app framework for Titanium.[INFO] Deployed ti.alloy plugin to plugins/ti.alloy/plugin.py
[INFO] Deployed ti.alloy hook to plugins/ti.alloy/hooks/alloy.js
[INFO] Installed "ti.alloy" plugin to tiapp.xml
[INFO] Generated new project at: app$ ll
total 56
-rw-r--r-- 1 ria10 staff 221 9 2 13:37 manifest
drwxr-xr-x 7 ria10 staff 238 9 2 13:37 Resources
-rw-r--r-- 1 ria10 staff 551 9 2 13:37 README
-rw-r--r-- 1 ria10 staff 11491 9 2 13:37 LICENSE
drwxr-xr-x 3 ria10 staff 102 9 2 13:37 ..
-rw-r--r-- 1 ria10 staff 1820 9 2 13:44 tiapp.xml
drwxr-xr-x 3 ria10 staff 102 9 2 13:44 plugins
drwxr-xr-x 10 ria10 staff 340 9 2 13:44 app
-rw-r--r-- 1 ria10 staff 48 9 2 13:44 .gitignore
drwxr-xr-x 10 ria10 staff 340 9 2 13:44 .
$ ll app/
total 24
drwxr-xr-x 3 ria10 staff 102 9 2 13:44 views
drwxr-xr-x 3 ria10 staff 102 9 2 13:44 styles
drwxr-xr-x 2 ria10 staff 68 9 2 13:44 models
drwxr-xr-x 3 ria10 staff 102 9 2 13:44 controllers
-rw-r--r-- 1 ria10 staff 183 9 2 13:44 config.json
drwxr-xr-x 7 ria10 staff 238 9 2 13:44 assets
-rw-r--r-- 1 ria10 staff 529 9 2 13:44 alloy.js
-rw-r--r-- 1 ria10 staff 1540 9 2 13:44 README
drwxr-xr-x 10 ria10 staff 340 9 2 13:44 ..
drwxr-xr-x 10 ria10 staff 340 9 2 13:44 .
appディレクトリができて、その下に一式Railsチックなファイル郡が生成される。
CoffeeScript導入
これでHello Worldが動作するAlloyアプリができあがったので、これにCoffeeScriptを導入する。
このあたり、ちょっとややこしくなるんだけど、Titanium+AlloyプロジェクトでMVC系のプログラムをCoffeeScriptで開発する場合、最終的なビルド対象のソースまでは
coffeeファイル -- [coffeeのコンパイラ] --> appディレクトリ配下のjsファイル -- [alloyのコンパイル] --> Resourcesディレクト配下のjsファイル
という流れになる。
実機転送でもTiShadowでのテストでも、Resourcesディレクトリのファイルが対象になるわけだからappディレクトリ配下のファイルは本質的には要らないはず。
問題は、apployのコンパイル処理がコピー以上のことをやっているかどうか、ということになる。
ということで、実際にAlloyのコンパイル処理をやってみてログを見てみたんだけど、やっぱコピー以外にもいろいろあるので、今回はcoffee->Resourcesディレクトリまで一気、はあきらめて、二段階の手順を自動的に踏ませる方向でやることにした。
参考:http://www.absolute-keitarou.net/blog/?p=426
CoffeeScriptインストール
$ npm install -g coffee-script
jmkファイル作成と編集
ビルドコンフィグファイルのjmkを作成
$ alloy generate jmk
.__ .__
_____ | | | | ____ ___.__.
\__ \ | | | | / _ < | |
/ __ \| |_| |_( <_> )___ |
(____ /____/____/\____// ____|
\/ \/
Alloy by Appcelerator. The MVC app framework for Titanium.[INFO] Generated "alloy.jmk" compiler hooks file.
編集
task("pre:compile", function(event,logger) { var wrench = require("wrench"), fs = require("fs"), path = require("path"), coffee = require("coffee-script"); event.alloyConfig.coffee = []; wrench.readdirSyncRecursive(event.dir.home).forEach(function(target){ if (target.match(/\.coffee$/)) { event.alloyConfig.coffee.push(target.replace(/\.coffee$/, ".js")); fs.writeFileSync( path.join(event.dir.home,target.replace(/\.coffee$/, ".js")), coffee.compile(fs.readFileSync(path.join(event.dir.home + "/" + target)).toString(), { bare: true })); } }); }); task("post:compile",function(event,logger){ var fs = require("fs"); event.alloyConfig.coffee.forEach(function(target){ fs.unlinkSync(event.dir.home + "/" + target); }); });
jsをcoffeeに変更
app/controllers/index.jsを.coffeeに変更し中身を以下のように修正
doClick = ->
alert($.label.text);
$.index.open()
TDD環境の導入
エミュレータを真正面から使うと、修正のたびにけっこうな時間を待たされるので、それを解決する。
ここでのポイントはTiShadowなんだけど、これほんと意味分かんないけどすごい。
参考:https://speakerdeck.com/astronaughts/rapid-prototyping-by-tishadow
TiShadowとは
自分でたてるTestFlightみたいなもので、
- TiShadowサーバを立てる
- TiShadowアプリを実行対象のデバイスにインストール
- TiShadowアプリからTiShadowサーバに接続をする
という手順をとると、コマンド一発でサーバを介して各デバイスにインストールされたTiShadowアプリ内で、自分のアプリを実行&テストできたりするというものです。
何を言っているのかわかりづらいと思うけど、やればわかる。
TiShadowのインストール
tishadowモジュールをインストールしたのち、tishadowapp(名前は何でもいい)という、エミュレータとか実機などのデバイスにインストールするアプリプロジェクトを自動生成し、それをデバッグや実行したいデバイスにインストールする。
$ npm install tishadow
$ cd ..
$ mkdir ./tishadowapp && tishadow app -d ./tishadowapp
$ cd tishadowapp/
$ ti build -p ios
tishadowappはどこに作ってもいいけど、本来のアプリと同列のところに作った。参考サイトのスライドにも画像が載っているけど、インストールするとこんな感じになる。
TiShadowサーバ起動
何のことだかわからなくていいのだ。とにかくこのプロセスが必要なのだ。
$ tishadow server
どこで実行してもよくて、このターミナルは実行の間、そっとしておこう。&つけてバックグラウンドで走らせることもできるけど、管理がめんどくさいのでターミナルひとつ潰したほうがいいと思われ。
で、この状態でhttp://localhost:3000にアクセスできるか確認する。
railsも同時開発してるから困るぜ!という人は-pでポート指定できるのでその辺はテキトウに。
https://github.com/dbankier/TiShadow
TDD環境導入
CoffeeScriptの導入とほとんど同じ。TiShadowはJasminサポートしているので、あとはspecを書く環境を作るのみ。もちろんspecもCoffeScript前提じゃ。
参考サイト
http://www.yydigital.com/blog/2013/2/14/Testing_Alloy_With_Jasmine_And_TiShadow
http://www.ari-hiro.com/blog/2013/05/26/introduce-alloy/
jmkファイルに追記
task("pre:compile", function(event,logger) { ~snip~ // compile CoffeeScript in spec_coffee directory var specCoffeeDir = event.dir.project + "/spec_coffee"; var specDir = event.dir.project + "/spec"; wrench.mkdirSyncRecursive(specDir, 0755); var rmdirRecursive = function(dirPath) { // cleanup directory fs.readdirSync(dirPath).forEach(function(target){ var targetPath = path.join(dirPath, target); if (fs.statSync(targetPath).isDirectory()) { rmdirRecursive(targetPath); fs.rmdirSync(targetPath); } else { fs.unlinkSync(targetPath); } }); }; rmdirRecursive(specDir); wrench.readdirSyncRecursive(specCoffeeDir).forEach(function(target){ var targetPath = path.join(specCoffeeDir,target); if (fs.statSync(targetPath).isFile()) { var dir = path.dirname(path.join(specDir,target)); var out_file, out_data; if (!fs.existsSync(dir)) { wrench.mkdirSyncRecursive(dir, 0755); } if (target.match(/\.coffee$/)) { out_file = path.join(specDir,target.replace(/\.coffee$/, ".js")); out_data = coffee.compile(fs.readFileSync(path.join(specCoffeeDir + "/" + target)).toString(), { bare: true }); } else { out_file = path.join(specDir,target); out_data = fs.readFileSync(path.join(specCoffeeDir + "/" + target)); } fs.writeFileSync(out_file, out_data); } });
テストコードを書く
spec_coffee/index_spec.coffee
Alloy = require('alloy') $ = Alloy.createController('index') describe 'index controller', -> beforeEach () -> describe 'display', -> it "label", () -> expect($.__views.label.text).toEqual 'Hello, World'
beforeEachいらんね。。
テスト実行
tishadowの実行環境が整っている状態で
$ alloy compile --config platform=ios,android && tishadow spec
~snip~
[TEST] [iphone, 6.1, 192.168.1.3] Runner Started
[TEST] [iphone, 6.1, 192.168.1.3]
[TEST] [iphone, 6.1, 192.168.1.3] display
[TEST] [iphone, 6.1, 192.168.1.3] √ label
[PASS] [iphone, 6.1, 192.168.1.3] √ 1 test(s) completed.
[TEST] [iphone, 6.1, 192.168.1.3]
[PASS] [iphone, 6.1, 192.168.1.3] √ 1 spec(s) completed.
うひょー!
まだ、超シンプルなテストしか書いてないからアレだけど、でもウレシイ。
Titanium Mobile iPhone/Androidアプリ開発入門―JavaScriptだけで作る
- 作者: 小澤栄一,増井雄一郎
- 出版社/メーカー: 秀和システム
- 発売日: 2012/02/01
- メディア: 単行本
- 購入: 9人 クリック: 169回
- この商品を含むブログ (24件) を見る
JavaScriptとTitaniumではじめる iPhone/Androidアプリプログラミング 【Titanium Mobile SDK 2.1 & Titanium Studio 2.1 対応】
- 作者: 森真吾
- 出版社/メーカー: マイナビ
- 発売日: 2012/09/14
- メディア: 単行本(ソフトカバー)
- 購入: 2人 クリック: 319回
- この商品を含むブログ (7件) を見る