[Titanium] window.urlは推奨されないプログラミング手法らしい

kimoi_girls.png

Titanium Mobileでは、ある程度大きなプロジェクトを作る場合、

var win = Ti.UI.createWindow({
url:'hoge.js'
});

という具合にしてurl引数を使ってソースを分割するのが半ば常識だと思っていました。

ところが実は、これってあんまり推奨されないやり方なのだそうです。
Titaniumの公式トレーニングビデオの二本目、Building Native Mobile Applicationsの10:00あたり、
JavaScriptでファイル分割をする方法について解説しているくだり。

02CrossPlatformJavaScriptApplications_1030.png


一般論だけど、1ファイル1ウインドウのプログラミングモデルはオススメしないよ。
KitchenSinkがやっているけど、あれはデモ用だから。
1ファイル1ウインドウモデルを使うと、たくさんのコンテキストを管理するために多くの問題を抱えることになる。
もちろん、ウインドウのURLプロパティを使いたくなるような場面はあるだろうけど、
一般論としては、Ti.includeやcommon.jsスタイルのrequireを使って、共通のコンテキストでウインドウを開くことをオススメする。

(トレーニングビデオは英語ですけど、単語レベルで全部書き取る自信はなかったので、だいたいこういうことを言っていたよ、という私訳です。)

プロジェクトを根底から作り直す羽目になるくらい重要な話だと思うのですけど、他に書かれているのを見た覚えがないので、トレーニングビデオは一通り見ておく必要がありそうです。
あるいは、日本語公式セミナーに参加したら説明してくれるのかもしれない。

なお、「じゃあWindow.urlを使わずにどうやって作るの?」という疑問については、

を見るのが参考になります。後者は他のテクニックもてんこ盛りで規模が大きいので、まずは前者を見るのがいいかと。
僕もあとで別のブログ記事にまとめようと思っています。


[作ったよ]正確な時刻がわからない時計 for iPhone

「頭ん中」 のmsngさんが、正確な時刻が分からない時計というのを提案されています。去年の話だけど。
.bbpBox{background:url(http://a0.twimg.com/profile_background_images/3222957/bg.png) #eeeeee;padding:20px;}

これ結構いいアイデアだと思ってるんですけどね。> 正確な時刻がわからない時計を作ってみた http://bit.ly/16buUlThu Aug 11 01:03:00 via YoruFukurou

もしかしたら進んでるかもしれないし
もしかしたら遅れてるかもしれないということになると
最悪の場合でも間に合うように動かないといけないから
結果として早め早めの行動ができるようになるかもしれない。

これは面白そうだと思ったのでiPhone用の時計を作ってみました。

vogue clock.

ズレは毎秒計算し直されるので、時計の針は平気で戻ったり進んだりします。時計とは思えないおちつかなさですね。

HTML5を使って時計を書くCoolClock を改造して作りました。

なので、FireFoxやIE9はもちろん、iPhoneやAndroidを含むたいていのブラウザで動作します。vogue clock.を開いてみてくださいませ。

iPhoneだと、ホームスクリーンに追加することでアドレスバーを非表示に出来るのですけど、画面一番上の時計部分を隠すことが出来ないので、正確な時刻はすぐ上を見ると分かってしまうという間抜けなことになっています。実用的に使おうと思ったら、アプリにする必要がありそうですね。

[予算1000円]電源ケーブルをキレイにまとめる

自宅に作業場を持っているプログラマさんの場合、ノートパソコンやディスプレイ、携帯電話やスマートフォンの充電をしないと行けないので、机の周りに電源ケーブルがぐちゃぐちゃになりがちです。

masuidriveさんとtwitterで電源ケーブルの配線の話をしていて、キレイにした写真を上げていただいたので、自分がやっている方法もブログに書いてみます。ちなみにこれはmasuidriveさんの写真、改善前と改善後。
photo by masuidrive
photo by masuidrive

自分の場合、電源はすべて机の裏に貼り付けています。

P1000955.JPG

  • 100円均一で買ってきたネットを机の裏に貼り付ける
  • 電源タップをネットに固定。
  • ケーブル結束バンド、マジックバンドをつかってケーブルをネットに貼り付けてしまう

ACアダプタと電源コンセントは重さがあるので、結束バンドというのを使っています。
Amazonで売っているケーブル結束バンド
は短いタイプなので、もうちょっと太くて再利用可能なものをホームセンターで買ってきました。
ケーブル自体は、結束バンドだと外す時大変なので、マジックバンドを使って固定しています。セロハンテープみたいに必要な長さを切って使えるので、自由にケーブルを固定することが出来ます。結束クリップのほうが付け外しが楽ですけど、マジックバンドのほうが単価が安くて、いろいろ応用が利きます。

足下にケーブルが転がっていると、足を引っかける可能性があるのと、椅子のキャスターでひいてしまう(→やがて断線する危険がある。それ以前に、思ったように椅子が動かなくてイライラする!)という問題があります。全部机の裏に収納してしまえば、見た目もすっきりするし、足下に物がなくなるので快適に過ごすことが出来ます。
難点は外す時大変なことですが、基本的に引っ越しの時以外は外さないことが前提です。モバイラーたるもの、ACアダプタは自宅用と持ち運び用を持っているものですよね。

あと、電源タップは、スイッチのないものがオススメです。余計なスイッチがついていると、間違って足でさわる事故の元になります。上で紹介したバッファローのものは、シンプルなのでとても気に入っています。

CapsLockキーにCtrlキーの仕事をさせる

photo by lincolnose2

※プログラマ以外の方向けの記事です。

翻訳者のヨメは下手なプログラマより打鍵量が多いので、仕事が立て込んでくると小指がつりそうになります。

.bbpBox{background:url(http://a0.twimg.com/images/themes/theme1/bg.png) #C0DEED;padding:20px;}

また左手薬指が攣ってきた。つまり原因はコピペか。Thu Jul 28 13:19:35 via Janetter

プログラマの間では、CapsLockキーにCtrlキーの仕事をさせるというのが良く行われています。
Ctrl+cの代わりにCapsLock+cでもコピー、CapsLock+vでペーストが出来るようにしておくと、
小指を変にたたまなくて良くなるから、疲労度が全然違うのです。指がつりそうになるくらいキーを打つ人は、CapsLockなんてしないですし。

というわけで、プログラマ以外にも需要がありそうなので、WindowsパソコンでCapsLockキーにCtrlキーの仕事をさせる方法を書いてみます。

1. AutoHotKeyをインストール

 AutoHotkey Download

2. タスクバーにAutoHotKeyが居座るようになったと思うので、右クリックして設定ファイルを開く

WS001.JPG

3. 開いた設定ファイルにこんなふうに書いて保存

;CapsLockキーにCtrlキーの仕事をさせる
Capslock::Ctrl
sc03a::Ctrl

WS005.JPG

4. もう一回タスクバーのAutoHotKeyを右クリックして、Reload This Script。

WS003.JPG

出来上がり。AutoHotKeyが立ち上がっている間、CapsLockキーはその役目を忘れて、Ctrlキーのように振る舞うようになります。
コピーペーストはもちろん、CapsLock+pで印刷とか、CapsLock+aで全て選択とかも動作します。
なんかの理由でCapsLockキーを使いたい時は、AutoHotKeyを右クリックしてExitさせれば元の世界に戻ります。

Enjoy!


KitchenSinkでNo such file or directory: u’./Resources/comic_zine_ot.otf’

sxchu_1011518_50479789_font.jpg

今すぐフォローすべきTitanium Mobileの人達に名前を上げていただいていることに今更気づいたmogyaです。こんにちは。
ちなみに明日まで東京滞在中です。顔を見たいという奇特な方は、明日のプログラマーズカフェに遊びに来ていただけると嬉しいです。

さて、TitaniumMobileのお手本帳、appcelerator/KitchenSink。最近、コマンドラインからビルドすると、こういうエラーで止まってしまいませんか。

[INFO] Detected custom font: comic_zine_ot.otf
[ERROR] Error: Traceback (most recent call last):
File “/Library/Application Support/Titanium/mobilesdk/osx/1.6.2/iphone/builder.py”, line 948, in main shutil.copy(f,app_dir)
File “/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/shutil.py”, line 88, in copy copyfile(src, dst)
File “/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/shutil.py”, line 52, in copyfile fsrc = open(src, ‘rb’)
IOError: [Errno 2] No such file or directory: u’./Resources/comic_zine_ot.otf’

どうやら

/Library/Application\ Support/Titanium/mobilesdk/osx/1.7.1/iphone/builder.py run ./

と相対パス指定するとダメで、

/Library/Application\ Support/Titanium/mobilesdk/osx/1.7.1/iphone/builder.py run ~/develop/KitchenSink/

という具合にプロジェクトフォルダのパスを指定してあげないといけないみたい。

それとは別に、「Your TARGET_BUILD_DIR is incorrectly set. 」問題もあるんだけど、こっちの原因はわからないw
昨日Titanium meetup Tokyoで聞いたんだけど、地道にbuild/iphone/以下を削除するとか、project/cleanを試すとかしかないと言われました。
XCodeで設定をいじっても直らないわりに、一晩寝ると直ってたりするんですよね・・

[Titanium]KomodoEditでコード補完

Ti.Developers.meeting Vol 0.2で、「TitaniumStudioのエディタは微妙だからなんかいいのを教えてください。emacsとvi以外で。」と言ったらKomodo Editをオススメされた。
各種文字エンコードへの対応とか、コード補完とか拡張子による扱いの変更とか、ひと通りのことは出来るみたいなのでしばらくお試し中。

JavaScriptやRubyだけでなく、jQueryYUIの保管ライブラリまでデフォルトで用意されているあたりはさすがオープンソース。
さすがにTitaniumModileのAPIを補完するライブラリはなかったのだけれど、ぐぐったらすぐ出てきた。

javecantrell/titanium-mobile_komodo-codeintel – GitHub

ここからダウンロードしてきたファイルを適当なディレクトリに解凍して、Preference-Codeinteligenceで「Add API Catalog」してあげればOK。
Preferences.png
こんな具合に補完してくれます。Titanium.APIだけじゃなくて、Ti.APIの省略形にも対応しています。

codeintelligence.png

Titaniumの単体テスト

Ti.Developers.meeting Vol 0.2 : ATNDでお見せしたコード。

A test library for Titanium Mobile — Gist

上記をtestwin.jsという名前で保存して、こんな感じで使います。

Titanium.include('testWin.js');
addTest('とあるテストの実施ボタン',function(){
mustequal(getValue(),3,'getValue()は3を返すはず');
});

testwin.png

addTestを呼び出すたびに画面にテスト実施ボタンが追加されていきます。なので、unittestを書くような感覚で、思いついたテストをサクサクaddTestすればテスト用アプリが出来るよ、というもの。テスト結果については、mustequal(二つが一致していなかったらエラー扱いにする)とか、musttrue(変数がtrueじゃなかったらエラー扱いにする)という関数が用意されていて、結果をTi.APIのログに出力します。

ある程度大きな規模でAndroidとiPhone両方で動くものをつくろうと思ったら、データ構造とUIの分離が必要ではないかな、と考えていて。UIはもう諦めて別々につくる。データ構造については、両者共通のものが作れるはず。
で、データ構造部分を作るに当たっては、unittest的なものがほしいよね、ということで書いてみたものです。

マクドナルドで15分くらいで書いたものなので、結果出力が美しくないとか、unittestだったら自動実行してほしいとか、色々思いつく点はあるのですけど、まあとりあえず今あるものを公開してみたというスタンスです。
ライセンスは、TitaniumMobileと同じApache License, Version 2.0ということにしておくので、思うところがある方は自由にいじってみてくださいませ。僕も使っていくうちに色々直すだろうから、いいものができたらまたUpdateしようと思います。

[titanium]Basic認証を通す

sxchu_910074_mirage.jpg

TitaniumMobileでBASIC認証を通すのに、HTTPCientのsetBasicCredentialsという関数が使える、という記述を時々見かけます。guides_network_httpclient – titanium-mobile-doc-jaとか。Titanium Mobileで開発するiPhone/Androidアプリにも載っています。

でもこれ、どうも今使えないっぽい。

var xhr = Titanium.Network.createHTTPClient();
xhr.setBasicCredentials('username', 'password');
xhr.onload = function() {
Ti.API.info('xhr.onload');
};
xhr.onerror = function(e) {
Ti.API.info('xhr.onerror '+e.error);
};
xhr.open("GET","http://example.com/hoge.html");
xhr.send();

setBasicCredentialsが使えるのであれば、上記のようなコードでうまくいくはずなのですけど、1.7.1iPhoneで走らせると、

[ERROR] Script Error = invalid method '(null)' at app.js (line 2).

そんな関数は知らんぜ、と言われます。実際、Titanium.Network.HTTPClientを見ても、そんな名前の関数は存在しません。1.5位まではさかのぼってみたんだけど、その頃からなかったっぽい。

最初っから存在しなかったらWikiに書かれることもないはずなので、たぶん過去のある時点では存在したのだと思います。バージョンが変わったら関数が一個なくなるくらい、TitaniumMobileの利用者は慣れっこですよね?(涙)

なお、setBasicCredentialsが使えない状態でどうやってBASIC認証を通すかについては、Antelope Love Fan — Basic Authentication with Titanium.Network.HTTPClientが参考になりました。

var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function() {
Ti.API.info('xhr.onload');
};
xhr.onerror = function(e) {
Ti.API.info('xhr.onerror '+e.error);
};
xhr.open("GET","http://example.com/hoge.html");
var authstr = 'Basic ' +Titanium.Utils.base64encode(username+':'+password);
xhr.setRequestHeader('Authorization', authstr);
xhr.send();

openしてからsetRequestHeaderを呼び出すのがポイントです。

「Titanium Mobileで開発するiPhone/Androidアプリ」


Titanium Mobileで開発するiPhone/Androidアプリ 索引

日本初のTitanium Mobile本「Titanium Mobileで開発するiPhone/Androidアプリ (Smart Mobile Developer)
」が届きました。
titanium-mobile-doc-jaを主催されている@donayamaさんの本ということで、中身を見るまでもなくAmazonで予約注文したのですけど、期待を裏切らない出来上がりです。

Titanium Mobileで開発するiPhone/Androidアプリ (Smart Mobile Developer)

Titanium Mobileで何がめんどくさいかといえば、iPhoneとAndroid両方で動くことを念頭に置くと、あっちで動くものがこっちで動かない、こっちで動くものはあっちで動かない、となることです。
Appcelerator社のエバンジェリストになった増井さんですら、「感覚的にはソースコードの7~8割を共有し、2~3割を対象のOSごとにチューニングしていくようなイメージになる」
言われているくらいなので、そもそも両方で動くものを書こうとするのが間違いなのですけど、書籍や記事のサンプルコードなどは出来れば一個ですませたいですし、分けるにしたって、どこまでが共通で動いてどこからを分けるかを考える時点でかなりめんどくさかったりするのです。

ということで、「めんどくさいからサンプルはiPhoneのみ対応、Androidについては最後に一章もうけて説明するだけ」とかでも仕方ないのかな、と思っていたのですが、中身を見ると、最初から最後までちゃんと両対応で書かれています。
もちろん、iPhoneとAndroidは別のOSなので、片方でしか動かない機能や、片方だけでやる必要のある作業もあるのですけど、それについては一目で分かるマークをつけて解説されていました。
これだけの量のサンプルを、iPhoneとAndroid両方で動くようにチェックするのは相当の手間だったはず。でも、Androidのアプリを開発したい人にしてみれば、iPhoneのおまけみたいに扱われたら残念な気持ちになってしまいますから、これはとても良いことだと思います。

Titanium Mobileで開発するiPhone/Androidアプリ「Androidのみ」

twitterアプリの章では、拙作「tm_twitter_api」を使った例も紹介されています。
つい先日Androidにも対応したのですが、書籍を書かれた時点ではまだリリースされていなかったため、書籍では、donayamaさん自身がパッチを当てたサイトへのリンクが紹介されていました。
そんな状態なのに、作者として「古川大輔氏」と名前を載せていただいていて、なんだか申し訳ないくらいです。

Titanium Mobileで開発するiPhone/Androidアプリ 古川大輔氏

おまけとして、TitaniumMobileの簡易日本語APIリファレンスもついていて、これからTitanium Mobileを触ってみる方には大変お買い得だと思いますので、まだの方はぜひどうぞ。

Ti.includeの不具合が1.7で修正される模様

aa.png

Titaniumのインクルードパスを指定する方法私案で話題にしていた、サブディレクトリ内にあるファイルがTi.includeした時どこを見に行くか問題ですが、1.7で修正が入るみたいです。

[#TIMOB-3349] iOS: Ti.include() not handling relative
pathing properly - Appcelerator JIRA

さっそく1.7RCで実験してみました。

app.js
Ti.include('lib/test.js');
lib/test.js
Ti.include('lib/a.js');
lib/a.js
Ti.API.info('I am lib/a.js');
lib/lib/a.js
Ti.API.info('I am lib/lib/a.js');

こういうプロジェクトを用意して、Titanium Mobile SDK1.62とTitanium Mobile SDK1.7RC、それぞれiOS向けにビルドして走らせてみます。

1.6.2
[INFO] Compiling JavaScript...one moment
:
[INFO] Application started
[INFO] mogyatest1/1.0 (1.6.2.878906d)
[INFO] I am lib/a.js

 1.62では、Resourceからの絶対パスでファイルを参照しています。

1.7RC
[INFO] Compiling JavaScript...one moment
:
[INFO] Application started
[INFO] mogyatest1/1.0 (1.7.0.RC1.e6afca8)
[INFO] I am lib/lib/a.js

1.7RCでは、includeしたファイルを基準とした相対パスでファイルを探すようになりました。Androidと同じ挙動です。

Resource
 └lib/test.js
 └lib/a.js

上記のような構成で、test.jsからa.jsを参照したい場合、1.6.2までは

  • iOS : Ti.include(‘lib/a.js’);
  • Android : Ti.include(‘a.js’);

と使い分けるか、Titaniumのインクルードパスを指定する方法私案で紹介したような方法で工夫する必要がありました。
1.7からは、iOSもAndroidと同じ方法でincludeが出来るようになるので、普通に書けばiOSでもAndroidでも必要なファイルをincludeすることが出来ます。

逆に、iOSしか使わないことを前提に、Ti.include(‘lib/a.js’)と書いていた方は、1.7でビルドし直すと動かなくなることが予想されます。また、僕のブログを参考にして、

var path_lib = 'lib/';
if (Ti.Platform==null || Ti.Platform.osname=='android'){
path_lib = '';
}
Ti.include(path_lib+'a.js');

と書かれていた方も、1.7では動かなくなります(iOSが正だと思っていたので)。

1.6.2、1.7共通で動くコードを書くのであれば、

var path_lib = '';
if(Titanium.Platform.osname == 'iphone' && Titanium.version<'1.7.0'){
path_lib = '/lib/';
}
Ti.include(path_lib+'a.js');

という具合にバージョン番号を見るようにする必要がありますね。