TitaniumMobileの最近のブログ記事

最近まーったくTiを触れていないのですが。書くと役立ちそうな話題を見かけたのでちょっとだけ。

WebViewを利用したアプリケーションの場合によくあるのが、
特定のドメイン(URL)じゃないページへ遷移する場合は、通常のブラウザアプリ(Safari等)で開く
という要件です。
Ti.UI.WebView で、遷移先(遷移しようとしている)URLを知りたい ~ 'beforeload' イベントで url が反映されない件 #titaniumjp #titanium - harukazepcの日記


【はじめに】

この記事は、@astronaughtsさん企画の「Titanium Advent Calendar 2011」向けに書いています。
@astronaughtsさんは、この企画もそうですけど、それ以外にも関西で最大規模のTitaniumイベントTi.Developers.meetingの主催者でもあります。最初はどうしようかと思うくらいしょぼかったw Ti.Devs.me、諦めずに開催を繰り返して大きなイベントに育て上げた@astronaughtsに、個人的今年のTitaniumMVPを送りたいです。


さて、そんなわけでTitaniumの話題を一つ。Titaniumでは、アプリ内でブラウザが開くwebViewという仕組みを使うことができます。
これを使うと、アプリ内でWEBページを見てもらうことができるので、Titanium以外でもよく使われている仕組みです。これ、意外と怖いということはご存知ですか?

例えば簡単なアプリを用意してみましょう。このアプリは、起動すると、モバイラーズオアシスというサイトをwebviewで開きます。
mo.png 俺ブラウザ -- Gist

このアプリの最後に、ちょっとスパイスをかけてみます。

mo1.png

上野駅が蒲田駅に変わってしまいました。これで、モバイラーズオアシスの中の人は、「蒲田駅を検索したら違う位置が表示された」という謎のバグ報告に悩まされることになります。クックック。永久に悩み続けるがいい...


ご自分のアプリのWebViewに上記を仕掛けるとか、絶対やめてください。やめろってば!
冗談はさておき、技術的にこういうことが可能であることは頭においておく必要があります。今回は上野が蒲田になる程度ですみましたが、ニュースサイトの内容を書き換えられたら?ログインしたときにユーザー名とパスワードを他のサイトに送信する仕組みが入っていたら?
webViewとブラウザを同一視していると、あっと驚く手品に巻き込まれてしまうかもしれません・・・

逆に、この手法をうまく使えば、スマートフォンに最適化されていないHTMLに別のCSSを適用して要素を大きく表示させたり、サイドバーを隠してスマートフォン向けのページに見せるようなこともできるかも。
...できるかもしれないのですけど、実際は結構大変です。この記事を書くために色々試したのですけど、evalJSしたJSコードをデバッグする手段が無いので、泣きそうでした。
ちょっと複雑なJSを書くと、なぜか処理が行われなくて途方にくれます。いい思いつきだと思ったんだけどなぁ。

【おわりに】

明日は@rakiさんかな。よろしくおねがいします〜。



Titaniumで作ったiPhoneアプリに広告を出す場合、モジュールが簡単に手に入るAdMobが人気ですが、AdMaker(MediaAd)は使えないの?という声も多いみたいです。やってみたら簡単に出来たので、やり方をまとめてみます。

モジュールを使う

下記を落としてきます。
tryden/TiAdMaker - GitHub

titanium.xcconfigを開くと、TitaniumSDKのバージョンが定義されているので、これを自分の好みのものに書き換えます。1.6.1はちょっと微妙ですね。
titanium.xcconfig.png

で、build.pyを走らせるとモジュールが出来上がります。
build.png build2.png

出来上がったモジュールを解凍して、新しいプロジェクトにこんな感じで配置。
module-1.png

example/app.jsにサンプルがあるので、まずはこれを動かしてみるのがいいんじゃないかと思います。

app.js-1.png

AD_URL、SITE_ID、ZONE_IDはAdMakerでメディアを作るともらえます。
medibaad-1.png

というわけで起動してみるとこんな感じ。
sample1.png

めでたしめでたし。

webviewを使う方法

 ちなみに、AdMakerの公式サイトでは、こんなふうに案内されています。

TitaniumへSDKを実装できません。どうすればいいですか?
SDKでの対応はしておりません。
Web Viewを作って頂き、そこにJavaScriptタグを実装して頂くことで表示して頂くことも可能です。
(よくあるご質問|スマートフォン広告なら「mediba ad」|iPhone、Androidアプリ・サイト広告)

JavaScriptと空っぽのbodyタグを書いたHTMLを用意してwebviewで開いたところ、広告はちゃんと表示されたのですけど、クリックしたあとの広告もwebviewの中で開いて、どうしてくれようかという感じになりました(当たり前ですね)。
webviewのイベントをハンドリングしてあれこれという手も考えられるのですが、あんまりやると広告に手を入れているように見えてしまうことが懸念されます。モジュールが動くのだったら、そのほうがいいんじゃないかな、と思います。

P.S: Android用はこちら。
titanium の AdMaker モジュール作ってみました(Android用) #titaniumjp - harukazepcの日記



Ti.Developers.meeting vol 0.3 で、MogSnapのコバヤシトールさんに、アニメーションについてお話していただきました。

その際の説明用サンプルとして掲示されたTKAnimationSampleがとても素晴らしかったのでご紹介。

toru0325/TKAnimationSample - GitHub

TKAnimationSample1.png
KitchenSinkみたいに、複数のサンプルが見られるようになっています。

TKAnimationSample2.png
HelloWorld.js。静止画見ても何のことだか分からないと思いますが、HelloWorldが下から飛び出してくるサンプルです。

TKAnimationSample4.png
buttons.js。ボタンが出現するサンプル。よりかっこいいbuttons_with_scale.jsというのもあります。

TKAnimationSample5.png
赤いボールが複雑な軌跡を描いて飛び回るredbox.js。「Hint」ボタンを押すことで、どういうふうに実現されているかを見ることが出来ます。

TKAnimationSample6.png
AndroidやiPadのように画面上にポップアップを出現させるInfo_view.js。iPhoneではあまりやらないことになってますが、実現させたい人はたくさんいると思うので、そういう方はこのサンプルを参考にすると良いと思います。

ゲームやかわいいアプリケーションにアニメーションが必須なのはいうまでもないですが、情報系のアプリケーションでも、ちょっとアニメーションを利かせておくことで、 ユーザーさんの目線を誘導することが出来るのでとても役に立ちます。
APIリファレンスを見て実装してもなかなか上手く動かないのですけど、TKAnimationSampleで動いているサンプルをみて実装するのなら簡単に実装できますよね。
自分はTKAnimationSampleを見て30分くらいで、今作っているアプリにアニメーションを追加することが出来ました。
とても勉強になるので、ぜひさわってみてくださいませ。



TitaniumMobileにはSystemButtonというのがあって、ローカルに画像を持っていなくても標準的アイコンのボタンを表示させることができる(iphone only)。

systembutton.png

でも例えば、ブラウザでよく見る左右の三角形、forward/backボタンはsystemButtonに存在しない。
デザイナさんと一緒にお仕事をしている人はいいのですけど、プログラマが適当に作ったアプリでは、こういうのを下手に描いたせいでデザインが素人っぽくなってしまったりする。著作権的なものには目をつぶって他のアプリからキャプチャするにしても、この程度の画像をいちいち切り出すのはめんどくさいよね。

そこで、文字コードを使ってそれらしい文字をtitleに指定してみた。

// Forward and back button for browser.
var buttonForward = Titanium.UI.createButton({
    title:String.fromCharCode(0x25b6)
});
var buttonBack = Titanium.UI.createButton({
    title:String.fromCharCode(0x25c0)
});
win.setToolbar([flexSpace,buttonBack,flexSpace,buttonStop,flexSpace,buttonReload,flexSpace,buttonForward,flexSpace]);  

browserbuttons.png
お、いい感じ。もしかしてもっと色々出来るかも?

// OK. more buttons!
var buttonApple = Titanium.UI.createButton({
    title:String.fromCharCode(0xf8ff)
});
var buttonCommand = Titanium.UI.createButton({
    title:String.fromCharCode(0x2318)
});
var buttonOption = Titanium.UI.createButton({
    title:String.fromCharCode(0x2325)
});
var buttonReturn = Titanium.UI.createButton({
    title:String.fromCharCode(0x23ce)
});
var buttonForward2 = Titanium.UI.createButton({
    title:String.fromCharCode(0x25c1)
});
var buttonBack2 = Titanium.UI.createButton({
    title:String.fromCharCode(0x25b7)
});
var buttonNote1 = Titanium.UI.createButton({
    title:String.fromCharCode(9833)
});
var buttonNote2 = Titanium.UI.createButton({
    title:String.fromCharCode(9834)
});
var buttonNote3 = Titanium.UI.createButton({
    title:String.fromCharCode(9835)
});
win.setToolbar([flexSpace,buttonForward2,buttonBack2,buttonApple,buttonCommand,buttonOption,buttonReturn,buttonNote1,buttonNote2,buttonNote3,flexSpace]);  

morebutton1.png
もうソースコードは省略するけど、こういうのも出せる。

morebutton2.png

WEBの世界では、エンドユーザーが持っているフォントにその文字がある保証がなかったり、フォントによってどんな文字が出るか予想ができないということで、こういう文字を使うのはご法度ということになっていた。
iPhoneアプリをTitaniumMobileで作るのであれば、クライアントのフォントは常に同じだから、かなりの数の記号を使うことができる。
残念ながらtoolbarにはフォントを指定できないみたいなので、toolbarに出せる文字はヒラギノで出せる範囲に限られるみたいだけど、labelとか普通のボタンだったら、font指定することで、もっと変な記号も出せるかもしれない。

文字と文字コードの関係を調べるには、下記サイトか、Mac標準の「文字ビューア」を見ればOK.

Androidは試してないのだけれど、原理的には同じようなことができるはず。
でもAndroidの場合、インストールされているフォントが保証されないから、機種によってボタンが見えなくなったりするリスクがあるかも。

テストアプリのソースコードは下記。もちろん、画像ファイルなんて不要です:-)



sxchu_1276335_threads.jpg

[Titanium] window.urlは推奨されないプログラミング手法らしい - もぎゃろぐの続きです。

つい先日まで使っていた物を突然駄目だと言われても納得が出来ないと思うので、どういう場面で困ったことになるのかの例を一つ。

ある程度大きなプロジェクトになると、アクセスクラス付きのデータクラスみたいなのを作りたくなることがあります。たとえばこんなクラス。

var Obj = function(){
  this.v = 1;
}
Obj.prototype.setVar = function(v){
        this.v = v;
}
Obj.prototype.getVar = function(v){
  return this.v;
}
var obj = new Obj();

obj.vを直接書き換える代わりに、セッターとゲッターを用意しておくことで、例えばセットした時にログを書くとか、セットする時に不正な値だったらはじくとか、いわゆるカプセル化のクラスです。
この状態で、objをあちこちの画面で共有したいとします。

var Obj = function(){
	this.v = 1;
}
Obj.prototype.setVar = function(v){
	this.v = v;
}
Obj.prototype.getVar = function(v){
	return this.v;
}
var obj = new Obj();
var win = Ti.UI.createWindow({});
win.obj = obj;
win.obj.setVar(2);
Ti.API.debug('app.js win.obj.getXXX:'+win.obj.getVar()); // 1が帰ってきてしまう

obj.setVar(2)で値を渡したはずなのですけど、newした時の値が帰ってきてしまいました。
この例では簡単にテストするためにファイル一個でやっていますが、winの定義を別ファイルに分けても再現します。

なんでこうなるの?

Ti.UI.createWindowで生成したオブジェクトは、JavaScriptのオブジェクトみたいに振る舞っていますけど、実際にはObjectiveCやJavaのオブジェクトにリンクされています(そうじゃないとネイティブUIの部品を画面に出すことが出来ないですからね)

ここからは推測なのですけど、そうやって生成されたWindowオブジェクトのプロパティに値を代入する(たとえば、win.obj = obj; のように)と、JavaScriptとObjectiveC/Java言語の壁を越えるために、いったんJSON文字列に変換されてしまいます。

結果としてメソッドは生き残ることが出来ないので、obj.setVar()がまともに動作しなくなります。

それだったらいっそ例外になってくれれば良いと思うのですけど、中途半端に動くあたり、もしかしたらJSON化じゃなくてもう少し別の実装になっているのかもしれない。その辺はちょっと自信なしです。ソース追ってみたんだけど糸口がわかんなかった(><)

オブジェクトはコンテキストを越えられない

ちょっと底の浅い説明になってしまいましたけど、ともあれ、obj.setVar()が動作しないことは事実です。この現象は、Windowオブジェクトに限らず、Ti.Appのプロパティとして割り当てても同じ現象が起きます。要するに、Ti.のプロパティにメソッドがついたオブジェクトを引き渡してはならない、ということです。

なぜwindow.urlを使ってはいけないのか。
window.urlスタイルのプログラムを使うと、上記のようなメソッド付きのオブジェクトを共有する手段がなくなってしまうからです。

単に数値や文字列を画面間で共有したいだけであれば、windowのプロパティに渡してもいいし、相互に変更をやりとりしたければ、Titanium.App.Propertiesを使うこともできます。
このやり方で実装してしまうと、各画面がロジック部分まで持つことになるので、UIとロジックを分離することが困難になってしまいます。
UIとロジックを分離するためには、メソッドの共有がどうしても必要なのです。

公式ビデオの三本目、Building Native Mobile Applications 03 - UI Fundamentalsでは、こんなふうに説明されていました。

「真っ平らな地面」が必要な場合のみ、マルチコンテキストを使う意味がある。KitchenSinkは、たくさんのデモを見せるための物で、互いにデータを共有する必要がなかったからマルチコンテキストが使われている。

あと、ロジック部分は全部インターネット上のサーバにあって、各画面はWebAPIを叩くだけ、というアプリも、マルチコンテキストで実装しやすそうな気がします。TitaniumMobileが得意とするカタログアプリみたいなのですね。



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を使わずにどうやって作るの?」という疑問については、

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




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で設定をいじっても直らないわりに、一晩寝ると直ってたりするんですよね・・


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



このアーカイブについて

このページには、過去に書かれたブログ記事のうち <$ MTCategoryLabel$> カテゴリに属しているものが含まれています。

前のカテゴリは PHP です。

次のカテゴリは css です。

最近のコンテンツは インデックスページ で見られます。過去に書かれたものは アーカイブのページ で見られます。

Powered by
Movable Type