scalin titanium mobile

Post on 12-Oct-2014

1.482 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ScalingTitaniumMobile

at Android Bazaar and Conference 2012 Spring

http://bit.ly/scale-ti

Saturday, March 24, 12

おぐらじゅんや

@junya

Saturday, March 24, 12

合同会社キュニップabout.qnyp.com

Saturday, March 24, 12

Scaling

Saturday, March 24, 12

Scalingチーム開発

機能の追加・削除

対応デバイスの追加

Saturday, March 24, 12

Scalingチーム開発

機能の追加・削除

対応デバイスの追加 }Saturday, March 24, 12

Scalingを容易にする

コードの書き方

チーム開発

機能の追加・削除

対応デバイスの追加 }Saturday, March 24, 12

What’s Titanium Mobile

最近のTitanium Mobile

コードの分割

underscore.js

CoffeeScript

プラットフォーム依存コードの隠蔽

カスタムイベント

Agenda

Saturday, March 24, 12

What’s

Titanium Mobile?

Saturday, March 24, 12

Titanium Mobileタイタニウム・モバイル

Saturday, March 24, 12

by Appcelerator, Inc.

Saturday, March 24, 12

from JavaScript

Saturday, March 24, 12

from JavaScript

to iOS

Saturday, March 24, 12

from JavaScript

to iOS

to Android

Saturday, March 24, 12

from JavaScript

to iOS

to Android

It’s OpenSource!

Saturday, March 24, 12

from JavaScript

to iOS

to Android

It’s OpenSource!

Community License => Free

Saturday, March 24, 12

from JavaScript

to iOS

to Android

It’s OpenSource!

Community License => Free

Indie License => $49/month

Saturday, March 24, 12

開発環境

Mac OS XWindowsUbuntu Linux

Saturday, March 24, 12

iOS 4.0.X -Android 2.2 (API 7) -

Titanium Compatibility Matrix - Documentation & Guides - Appcelerator Wikihttps://wiki.appcelerator.org/display/guides/Titanium+Compatibility+Matrix

最新版のターゲット環境

Saturday, March 24, 12

Only Mac OS X

iOS

Saturday, March 24, 12

Code Example

Saturday, March 24, 12

Saturday, March 24, 12

var win = Ti.UI.createWindow({ title: 'github/appcelerator' });

var tableView = Ti.UI.createTableView();win.add(tableView);

var tabGroup = Ti.UI.createTabGroup();var tab = Ti.UI.createTab({ icon: 'KS_nav_ui.png', title: 'Repos', window: win});tabGroup.addTab(tab);tabGroup.setActiveTab(tab);tabGroup.open();

var xhr = Ti.Network.createHTTPClient();var url = 'https://api.github.com/orgs/appcelerator/repos?type=public';xhr.open('GET', url);xhr.onload = function() { var res = JSON.parse(this.responseText); tableView.setData(res.map(function(repo) { return Ti.UI.createTableViewRow({ title: repo.name }); }));;};xhr.send();

Saturday, March 24, 12

var win = Ti.UI.createWindow({ title: 'github/appcelerator' });

var tableView = Ti.UI.createTableView();win.add(tableView);

var tabGroup = Ti.UI.createTabGroup();var tab = Ti.UI.createTab({ icon: 'KS_nav_ui.png', title: 'Repos', window: win});tabGroup.addTab(tab);tabGroup.setActiveTab(tab);tabGroup.open();

var xhr = Ti.Network.createHTTPClient();var url = 'https://api.github.com/orgs/appcelerator/repos?type=public';xhr.open('GET', url);xhr.onload = function() { var res = JSON.parse(this.responseText); tableView.setData(res.map(function(repo) { return Ti.UI.createTableViewRow({ title: repo.name }); }));;};xhr.send();

25行

Saturday, March 24, 12

var win = Ti.UI.createWindow({ title: 'github/appcelerator' });

var tableView = Ti.UI.createTableView();win.add(tableView);

var tabGroup = Ti.UI.createTabGroup();var tab = Ti.UI.createTab({ icon: 'KS_nav_ui.png', title: 'Repos', window: win});tabGroup.addTab(tab);tabGroup.setActiveTab(tab);tabGroup.open();

var xhr = Ti.Network.createHTTPClient();var url = 'https://api.github.com/orgs/appcelerator/repos?type=public';xhr.open('GET', url);xhr.onload = function() { var res = JSON.parse(this.responseText); tableView.setData(res.map(function(repo) { return Ti.UI.createTableViewRow({ title: repo.name }); }));;};xhr.send();

25行

Saturday, March 24, 12

var win = Ti.UI.createWindow({ title: 'github/appcelerator' });

var tableView = Ti.UI.createTableView();win.add(tableView);

var tabGroup = Ti.UI.createTabGroup();var tab = Ti.UI.createTab({ icon: 'KS_nav_ui.png', title: 'Repos', window: win});tabGroup.addTab(tab);tabGroup.setActiveTab(tab);tabGroup.open();

var xhr = Ti.Network.createHTTPClient();var url = 'https://api.github.com/orgs/appcelerator/repos?type=public';xhr.open('GET', url);xhr.onload = function() { var res = JSON.parse(this.responseText); tableView.setData(res.map(function(repo) { return Ti.UI.createTableViewRow({ title: repo.name }); }));;};xhr.send();

25行

Saturday, March 24, 12

Titanium Mobile製アプリ

Saturday, March 24, 12

MogSnapZaim

GetGlue Welcome to NIFTY-Serve

Built with Appcelerator Titanium / http://www.builtwithtitanium.com/

Saturday, March 24, 12

Titanium Mobile

最近の

Saturday, March 24, 12

Titanium Mobile SDK 1.8.2Feb 29, 2012

Saturday, March 24, 12

1.8系のサービスパック

メモリリーク修正

クラッシュバグ修正

など

http://developer.appcelerator.com/apidoc/mobile/1.8.2/changelog.html

Saturday, March 24, 12

4月に2.0がリリース予定

Cocoafishサービスとの統合

ジオロケーション機能の強化

TableViewのパフォーマンス改善

モジュールAPIの改良

Saturday, March 24, 12

Scalingを容易にする

コードの書き方

チーム開発

機能の追加・削除

対応デバイスの追加 }Saturday, March 24, 12

Code Structure

コードの分割

Saturday, March 24, 12

// app.jsvar win = Ti.UI.createWindow({ backgroundColor: '#fff'});

var button = Ti.UI.createButton();button.addEventListener(‘click’, function(e) { alert(‘Button Clicked’);});win.add(button);

win.open();

簡単なアプリ。

Saturday, March 24, 12

// app.jsvar win = Ti.UI.createWindow({ backgroundColor: '#fff'});

var button = Ti.UI.createButton();button.addEventListener(‘click’, function(e) { alert(‘Button Clicked’);});win.add(button);

win.open();

ウィンドウの生成。

Saturday, March 24, 12

// app.jsvar win = Ti.UI.createWindow({ backgroundColor: '#fff'});

var button = Ti.UI.createButton();button.addEventListener(‘click’, function(e) { alert(‘Button Clicked’);});win.add(button);

win.open();

ボタンの生成とクリック時の処理設定。

Saturday, March 24, 12

// app.jsvar win = Ti.UI.createWindow({ backgroundColor: '#fff'});

var button = Ti.UI.createButton();button.addEventListener(‘click’, function(e) { alert(‘Button Clicked’);});win.add(button);

win.open();

ウィンドウのオープン。

Saturday, March 24, 12

1つのapp.jsでは、

すぐに見通しが悪くなる。

Saturday, March 24, 12

チーム開発では分業も困難。

Saturday, March 24, 12

コードを分割する手法。

Saturday, March 24, 12

window.url

Ti.include()

CommonJS

Saturday, March 24, 12

手法によって、

Android対応

テストのしやすさ

保守性

などに大きく影響する。

Saturday, March 24, 12

window.url

Saturday, March 24, 12

ウィンドウ生成時の

urlパラメータを利用。

Saturday, March 24, 12

// app.jsvar win = Ti.UI.createWindow({ backgroundColor: '#fff', url: 'window.js'});win.open();

// window.jsvar win = Ti.UI.currentWindow;var button = Ti.UI.createButton();button.addEventListener(‘click’, function(e) { alert(‘Button Clicked’);});win.add(button);

Saturday, March 24, 12

window.urlスタイルは、

古いサンプルコード、ブログ、記事

などで使われている。

Saturday, March 24, 12

パフォーマンスの問題もあり、

現在は推奨されていないので

使わないこと。

Saturday, March 24, 12

window.url

Ti.include()

CommonJS

Saturday, March 24, 12

Ti.include

Saturday, March 24, 12

Ti.include関数を利用。

Saturday, March 24, 12

// app.jsvar name = 'Foo';var win = Ti.UI.createWindow({ backgroundColor: '#fff', name: name});Ti.include('window.js');win.open();

// window.jsvar label = Ti.UI.createLabel({text: win.name});label.addEventListener('click', function(e) { alert(name + ' Clicked');});win.add(label);

Saturday, March 24, 12

var name = 'Foo';var win = Ti.UI.createWindow({ backgroundColor: '#fff', name: name});var label = Ti.UI.createLabel({text: win.name});label.addEventListener('click', function(e) { alert(name + ' Clicked');});win.add(label);win.open();

実際には1つのファイルに結合されて実行される。

Saturday, March 24, 12

名前の衝突が起こりやすい。

Saturday, March 24, 12

現在はTi.includeも非推奨なので

使わないこと。

Saturday, March 24, 12

window.url

Ti.include()

CommonJS

Saturday, March 24, 12

CommonJS

Saturday, March 24, 12

サーバーサイドJavaScriptにおける

共通仕様 CommonJSの、

モジュール仕様を採用。

Saturday, March 24, 12

コードの分割・再利用の手法として

現在、Appceleratorが推奨。

Saturday, March 24, 12

// app.jsvar name = 'Foo';var window = require('window');var win = window.myWindow(name);win.open();

alert('label = ' + label); // labelは見えない

// window.jsexports.myWindow = function(name) { var win = Ti.UI.createWindow({ backgroundColor: '#fff' }); var label = Ti.UI.createLabel({text: name}); label.addEventListener('click', function(e) { alert(name + ' Clicked'); }); win.add(label); return win;};

Saturday, March 24, 12

Titanium Studioで生成される

テンプレートもCommonJS形式。

Saturday, March 24, 12

Saturday, March 24, 12

Saturday, March 24, 12

app.jsui/ApplicationWindow.jsui/FirstView.js

Saturday, March 24, 12

function FirstView() { var self = Ti.UI.createView(); var label = Ti.UI.createLabel({ color:'#000000', text:String.format(L('welcome'),'Titanium'), height:'auto', width:'auto' }); self.add(label);

label.addEventListener('click', function(e) { alert(e.source.text); });

return self;}

module.exports = FirstView;

ui/FirstView.js

Saturday, March 24, 12

function ApplicationWindow() { var FirstView = require('ui/FirstView');

var self = Ti.UI.createWindow({ backgroundColor:'#ffffff', navBarHidden:true, exitOnClose:true });

var firstView = new FirstView(); self.add(firstView);

return self;}

module.exports = ApplicationWindow;

ui/ApplicationWindow.js

Saturday, March 24, 12

var ApplicationWindow = require('ui/ApplicationWindow');new ApplicationWindow().open();

app.js

Saturday, March 24, 12

注意

相対パスを指定した際の挙動が

CommonJSと異なり、Resources/

からの相対指定として認識される。

Saturday, March 24, 12

パフォーマンスの問題がない。

メンテナンス性が高い。

再利用しやすい。

単体テストが行いやすい。

Saturday, March 24, 12

var Window;if (globals.osname === 'ipad') { Window = require('ui/ipad/iPadWindow');} else if (globals.osname === 'iphone') { Window = require('ui/iphone/iPhoneWindow');} else { Window = require('ui/android/AndroidWindow');}new Window().open();

デバイスに応じたUIの読み込み。

Saturday, March 24, 12

window.url

Ti.include()

CommonJS

Saturday, March 24, 12

underscore.js

Saturday, March 24, 12

配列や関数に対する操作を

容易にするライブラリ。

Saturday, March 24, 12

JavaScriptの

ビルトインオブジェクトを

拡張しない。

Saturday, March 24, 12

関数プログラミング由来の

ものを中心とした60ほどの関数。

each, map, reduce,filter, reject, any,max, min, shuffle,union, uniq, ...

Saturday, March 24, 12

It’s CommonJS

var _ = require('underscore')._;

Saturday, March 24, 12

JSONをUI用のデータに整形・変換。

var items = JSON.parse(responseText);

var itemNames = _(items).chain() .uniq(false, function(item) { return item.id; }) .select(function(item) { return item.available; }) .sortBy(function(item) { return item.name; }) .name();

Saturday, March 24, 12

JSONをUI用のデータに整形・変換。

var items = JSON.parse(responseText);

var itemNames = _(items).chain() .uniq(false, function(item) { return item.id; }) .select(function(item) { return item.available; }) .sortBy(function(item) { return item.name; }) .name();

Saturday, March 24, 12

JSONをUI用のデータに整形・変換。

var items = JSON.parse(responseText);

var itemNames = _(items).chain() .uniq(false, function(item) { return item.id; }) .select(function(item) { return item.available; }) .sortBy(function(item) { return item.name; }) .name();

Saturday, March 24, 12

JSONをUI用のデータに整形・変換。

var items = JSON.parse(responseText);

var itemNames = _(items).chain() .uniq(false, function(item) { return item.id; }) .select(function(item) { return item.available; }) .sortBy(function(item) { return item.name; }) .name();

Saturday, March 24, 12

JSONをUI用のデータに整形・変換。

var items = JSON.parse(responseText);

var itemNames = _(items).chain() .uniq(false, function(item) { return item.id; }) .select(function(item) { return item.available; }) .sortBy(function(item) { return item.name; }) .name();

Saturday, March 24, 12

JSONをUI用のデータに整形・変換。

var items = JSON.parse(responseText);

var itemNames = _(items).chain() .uniq(false, function(item) { return item.id; }) .select(function(item) { return item.available; }) .sortBy(function(item) { return item.name; }) .name();

Saturday, March 24, 12

CoffeeScript

Saturday, March 24, 12

JavaScriptに比べて

コードの記述量を削減できる。

Saturday, March 24, 12

バグ、ケアレスミスの削減。

Saturday, March 24, 12

パラメータ記述が簡潔に。// JavaScriptvar win = Ti.UI.createWindow({ title: 'github' });var tab = Ti.UI.createTab({ icon: 'KS_nav_ui.png', title: 'Repos', window: win});

# CoffeeScriptwin = Ti.UI.createWindow(title: 'github')tab = Ti.UI.createTab icon: 'KS_nav_ui.png' title: 'Repos' window: win

Saturday, March 24, 12

コールバック記述が簡潔に。

// JavaScriptbutton.addEventListener('click', function(e) { Ti.API.debug('button clicked');});

# CoffeeScriptbutton.addEventListener 'click', (e) -> Ti.API.debug('button clicked')

Saturday, March 24, 12

ループがシンプルに。// JavaScriptvar rows = [];for (var i = 0; i < items.length; i++) { var item = items[i]; if (item.isPublic()) rows.push(createTableRow(items[i]));}var tableView = Ti.UI.createTableView({ data: rows });

# CoffeeScriptrows = []for item in items when item.public() rows.push(createTableRow(item))tableView = Ti.UI.createTableView(data: rows)

Saturday, March 24, 12

後置ifでプラットフォーム毎の

場合分けをシンプルに。

# CoffeeScriptTi.UI.iPhone.appBadge = 10 if Ti.Platform.osname is “iphone”

# JavaScriptif (Ti.Platform.osname === “iphone”) { Ti.UI.iPhone.appBadge = 10;}

Saturday, March 24, 12

クラスベースに設計しやすい。

# CustomView.coffeeclass CustomView view: null constructor: -> @initView() @initEvents() initView: -> @view = Ti.UI.createView() initEvents: -> @view.addEventListener 'click', (e) -> alert('clicked')

module.exports = CustomView

# app.coffeeCustomView = require('CustomView')view = new CustomView()

Saturday, March 24, 12

文字列内で変数展開ができる。

name = "Titanium"alert("Hello, #{name}")

Saturday, March 24, 12

Auto Compile with Guard

$ brew install nodejs$ curl http://npmjs.org/install.sh | sh$ npm install -g coffee-script

$ gem install guard-coffeescript$ gem install rb-fsevent

# Guardfileguard 'coffeescript', :input => 'coffee', :output => 'Resources', :bare => true

$ guard

Saturday, March 24, 12

Facade

プラットフォーム

依存コードの隠蔽

Saturday, March 24, 12

iOSとAndroidで場合分けするコード。if (Ti.Platform.osname === "android") { var picker1 = Ti.UI.createPicker({type:Ti.UI.PICKER_TYPE_DATE}); var picker2 = Ti.UI.createPicker({type:Ti.UI.PICKER_TYPE_TIME}); picker1.addEventListener('change', callback); picker2.addEventListener('change', callback); win.add(picker); win.add(picker2);} else { var picker = Ti.UI.createPicker({ type:Ti.UI.PICKER_TYPE_DATE_AND_TIME }); picker.addEventListener('change', callback); win.add(picker);}

Saturday, March 24, 12

分岐処理をラップして隠蔽。var calendarWindow = function(callback) { var win = Ti.UI.createWindow(); if (Ti.Platform.osname === "android") { var picker1 = Ti.UI.createPicker({type:Ti.UI.PICKER_TYPE_DATE}); var picker2 = Ti.UI.createPicker({type:Ti.UI.PICKER_TYPE_TIME}); picker1.addEventListener('change', callback); picker2.addEventListener('change', callback); win.add(picker1); win.add(picker2); } else { var picker = Ti.UI.createPicker({ type:Ti.UI.PICKER_TYPE_DATE_AND_TIME }); picker.addEventListener('change', callback); win.add(picker); } return win;};

Saturday, March 24, 12

分岐処理をラップして隠蔽。

var win = calendarWindow(function(e) { ... });

Saturday, March 24, 12

モジュール化して再利用。

// utils.jsexports.createCalendarWindow = function(callback) { ...};

// app.jsvar utils = require('/utils');var win = utils.createCalendarWindow(function(e) { ...});

Saturday, March 24, 12

Custom Event

カスタムイベント

Saturday, March 24, 12

イベント

Saturday, March 24, 12

button.addEventListener(‘click’, function (e) {...});window.addEventListener(‘focus’, function (e) {...});

UIウィジェットの操作に伴って発生するもの、

Saturday, March 24, 12

とは限らない。

Saturday, March 24, 12

アプリ内コンポーネントの

連携にもイベントを活用する。

Saturday, March 24, 12

ApplicationLevelEvents

Saturday, March 24, 12

アプリケーションレベルイベント

アプリケーション内でグローバルに有効。

利用にはTi.Appモジュールを使う。

すべてのコンテキスト、関数スコープ、

CommonJSモジュールから参照できる。

Saturday, March 24, 12

Ti.App.addEventListener('settingsUpdated', function(params) { alert('New value: ' + params.newValue);});

Ti.App.fireEvent('settingsUpdated', { newValue: '...'});

ハンドラの設定とイベントの発生

Saturday, March 24, 12

コンポーネント同士がメソッドを呼び合うと、

エラー処理が分散する。

// メモ作成addButton.addEventListener('click', function(e) { if (dataManager.insertMemo(newMemo)) { memoList.append(newMemo); } else { alert('error!'); }});

Saturday, March 24, 12

イベントのやり取りで疎結合に。

メモ作成

Ti.AppdataManager

memoList

Saturday, March 24, 12

イベントのやり取りで疎結合に。

メモ作成 fire memoWillCreate

Ti.AppdataManager

memoList

Saturday, March 24, 12

イベントのやり取りで疎結合に。

メモ作成 fire memoWillCreate

Ti.AppdataManager

memoList

memoWillCreate

Saturday, March 24, 12

イベントのやり取りで疎結合に。

メモ作成 fire memoWillCreate

Ti.AppdataManager

memoList

memoWillCreate

fire memoDidCreated

Saturday, March 24, 12

イベントのやり取りで疎結合に。

メモ作成 fire memoWillCreate

Ti.AppdataManager

memoList

memoWillCreate

fire memoDidCreated

memoDidCreated

Saturday, March 24, 12

エラー時はイベントを発生させない。

メモ作成 fire memoWillCreate

Ti.AppdataManager

memoList

memoWillCreate

fire memoDidCreated×

Saturday, March 24, 12

// メモ作成addButton.addEventListener('click', function(e) { Ti.App.fireEvent('memoWillCreate', { id: memo.id, title: memo.id, body: memo.body });});

メモ作成の際には、データ保存やメモ一覧の更新には関与しない。

Saturday, March 24, 12

// dataManagerTi.App.addEventListener('memoWillCreate', function(memo) { if (insertMemo(memo)) { Ti.App.fireEvent('memoDidCreated', memo); } else { // エラー処理 }});

データ保存失敗時には次のイベントを発生させない。

Saturday, March 24, 12

// memoListTi.App.addEventListener('memoDidCreated', function(memo) { updateMemoList(memo);});

メモ一覧の更新処理はイベントの発生だけを待っていればよい。

Saturday, March 24, 12

注意

アプリケーションレベルのイベントハンドラ内

で生成したオブジェクトは、ハンドラを明示的

に削除するまでメモリに残る。

Managing Memory and Finding Leaks - Documentation & Guideshttps://wiki.appcelerator.org/display/guides/Managing+Memory+and+Finding+Leaks

Saturday, March 24, 12

var doSomething = function() { var foo = new Foo(); // ハンドラを削除するまで残り続ける};Ti.App.addEventListener(‘doSomething’, doSomething);

// 不要になったタイミングでハンドラを削除するTi.App.removeEventListener(‘doSomething’, doSomething);

Saturday, March 24, 12

var win = Ti.UI.createWindow();win.addEventListener('userLoggedIn', function(user) { updateAvatar(user.avatar);});win.open();

var button = Ti.UI.createButton();button.addEventListener(‘click’, function(e) { win.fireEvent(‘userLoggedIn’, { avatar: ‘...’ });});

グローバルなスコープが不要ならば、

ビューオブジェクトにカスタムイベントを設定することも可能。

Saturday, March 24, 12

Summary

まとめ

Saturday, March 24, 12

Scalingを容易にする

コードの書き方

チーム開発

機能の追加・削除

対応デバイスの追加 }Saturday, March 24, 12

What’s Titanium Mobile

最近のTitanium Mobile

コードの分割

underscore.js

CoffeeScript

プラットフォーム依存コードの隠蔽

カスタムイベント

Agenda

Saturday, March 24, 12

コードの分割は常にCommonJSスタイル。

モジュール化で分業が容易に。

プロジェクト間でのコード再利用を促進。

CommonJS

Saturday, March 24, 12

underscore.js配列や関数に対する操作を簡潔に記述。

チーム内での配列操作スタイルを統一。

Saturday, March 24, 12

冗長なコードの削減。

JavaScriptの良い部分だけを利用。

チーム内でJavaScriptのコード品質を統一。

CoffeeScript

Saturday, March 24, 12

iOS/Android判定のコードはできるだけ隠蔽。

関数やモジュールに隠す。

再利用できるノウハウを蓄積。

状況が変わった際の対応を容易に。

プラットフォーム依存コードの隠蔽

Saturday, March 24, 12

コンポーネント間の通信はできるだけイベントで。

エラー処理を集約。

シンプルな処理フロー。

カスタムイベント

Saturday, March 24, 12

Thanks.

@junya

http://bit.ly/scale-ti

Saturday, March 24, 12

top related