58
Titanium Mobile簡介 阿修 用Javascript打造原生行動應用程式

20110525[Taipei GTUG] titanium mobile簡介

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: 20110525[Taipei GTUG] titanium mobile簡介

Titanium Mobile簡介

阿修用Javascript打造原生行動應用程式

Page 2: 20110525[Taipei GTUG] titanium mobile簡介

李易修 Justin Lee赫迅互動科技 使用者經驗架構師

Page 3: 20110525[Taipei GTUG] titanium mobile簡介

現場調查

Page 4: 20110525[Taipei GTUG] titanium mobile簡介

誰想開發Mobile App?

Page 5: 20110525[Taipei GTUG] titanium mobile簡介

會JAVA和Objective-C的請舉手

Page 6: 20110525[Taipei GTUG] titanium mobile簡介

會做網頁的請舉手

Page 7: 20110525[Taipei GTUG] titanium mobile簡介

進軍手機、平板有哪些選擇?

在瀏覽器內執行Web App

HTML5+CSS+JS

尚可

沒辦法

把網站包進全螢幕瀏覽器Hybrid App

HTML5+CSS+JS+JS API

尚可

完全為裝置打造Native App

Java, Obj-C+Native API

最佳

最佳

技術

跨平台能力

使用者經驗

學習門檻

離線能力

整合性與功能

上架賣錢

Page 8: 20110525[Taipei GTUG] titanium mobile簡介

網路應用程式沒辦法上架賣錢

原生應用程式門檻太高,找不到人

Page 9: 20110525[Taipei GTUG] titanium mobile簡介

混合式應用程式好像不錯!

但是...

Page 10: 20110525[Taipei GTUG] titanium mobile簡介

要做混合式應用程式很簡單,要做好混合式應用程式不簡單。

Page 11: 20110525[Taipei GTUG] titanium mobile簡介

要有好的使用體驗,必須看起來像原生應用程式

Page 12: 20110525[Taipei GTUG] titanium mobile簡介

必須自己刻UI

系統整合有限

效能是個問號

混合式應用程式

Page 13: 20110525[Taipei GTUG] titanium mobile簡介

混合式應用程式快不起來

hello world!

建立window建立webview載入DOM parser載入JavaScript interpreter載入CSS parser載入HTML renderer載入SVG renderer載入Canvas renderer載入history manager載入SQLLite engine載入index.html等待載入完成render頁面打開windowlabel顯示在螢幕上

建立window建立label打開windowlabel顯示在螢幕上

網路應用程式 原生應用程式

Page 14: 20110525[Taipei GTUG] titanium mobile簡介

用熟悉的web技術開發原生應用程式?

Page 15: 20110525[Taipei GTUG] titanium mobile簡介

讓網站開發人員能夠快速上手的跨平台原生應用程式開發框架

Titanium Mobile

Page 16: 20110525[Taipei GTUG] titanium mobile簡介

簡易的語法使用JavaScript語言,便能開發原生行動應用程式

var win = Titanium.UI.createWindow({ backgroundColor:'#fff'});

var label = Titanium.UI.createLabel({ text: 'Hello World!'});

win.add(label);win.open();

Page 17: 20110525[Taipei GTUG] titanium mobile簡介

Javascript原始碼+素材

原生應用程式

Titanium API

Native API

Titanium高效能的祕密

JS to Native Bridge

Page 18: 20110525[Taipei GTUG] titanium mobile簡介

一套原始碼跨多平台iPhone, iPad, Android與BlackBerry

Page 19: 20110525[Taipei GTUG] titanium mobile簡介

與作業系統高度整合透過UI API與Phone API,取用原生的使用者介面與系統功能

Page 20: 20110525[Taipei GTUG] titanium mobile簡介

更少的程式碼更高的生產力50%的程式碼長度,同時支援多平台

Page 21: 20110525[Taipei GTUG] titanium mobile簡介

高度擴充性可經由Java或Objective-C擴充Titanium API功能

Page 22: 20110525[Taipei GTUG] titanium mobile簡介

開發環境

Page 23: 20110525[Taipei GTUG] titanium mobile簡介

要開發Titanium行動應用程式你需要:

SDK•Titanium Mobile SDK (1.6.2)•iOS SDK or Android SDK

Developer Tool•Titanium Developer (1.2.2)•Titanium Studio (RC1)

文字編輯器•textmate, vim...

Page 24: 20110525[Taipei GTUG] titanium mobile簡介

開發iOS應用程式仍然需要Mac

{

Page 25: 20110525[Taipei GTUG] titanium mobile簡介

Titanium Developer

Page 26: 20110525[Taipei GTUG] titanium mobile簡介

Titanium StudioBreakpoint+Debugger

Page 27: 20110525[Taipei GTUG] titanium mobile簡介

Titanium的javascript環境

沒有DOM,不用JQuery

所有的UI由Javascript建立window相當於瀏覽器視窗view相當於div事件處理同樣是用AddEventListener

維持一個execution context

Page 28: 20110525[Taipei GTUG] titanium mobile簡介

牛刀小試Hello World! Titanium

Page 29: 20110525[Taipei GTUG] titanium mobile簡介

HowIsTheWeather/ build/ android/ ... iphone/ ... CHANGELOG.txt LICENSE LICENSE.txt manifest README Resources/ android/ ... app.js iphone/ ... KS_nav_ui.png KS_nav_views.png tiapp.xml

檔案及目錄結構原生專案

起始檔

設定檔

android專用檔案

iphone專用檔案

原始碼和其他資料檔

Page 30: 20110525[Taipei GTUG] titanium mobile簡介

var win = Titanium.UI.createWindow({ backgroundColor:'#fff'});

var label = Titanium.UI.createLabel({ text: 'Hello World!', textAlign: 'center'});

label.addEventListener('click', function(e){ Titanium.API.info('label clicked!');});

win.add(label);win.open();

Hello World!

Page 32: 20110525[Taipei GTUG] titanium mobile簡介

Titanium開發實戰現在天氣怎麼樣?

Page 33: 20110525[Taipei GTUG] titanium mobile簡介

功能:顯示這裡現在的天氣

你可以學到:建立UI取得GPS資訊讀取遠端XML儲存資訊顯示網頁使用各平台特有功能

現在天氣怎麼樣?

原始碼:http://goo.gl/Fj3pl

Page 34: 20110525[Taipei GTUG] titanium mobile簡介

var win = Titanium.UI.createWindow({ backgroundColor:'#fff'});

var locationLabel = Titanium.UI.createLabel({ color:'#000', text:'內湖區', font:{fontSize: 30, fontFamily:'Helvetica Neue'}, textAlign:'center', width:'auto', height: 'auto', left: 15, top: 75});

var weatherIcon = Titanium.UI.createImageView({ image: 'images/mostly_cloudy.gif', width: 80, height: 80, left: 15, top: 120});

建立UI

75px

15px絕對定位

Page 35: 20110525[Taipei GTUG] titanium mobile簡介

var temperatureLabel = Titanium.UI.createLabel({ color:'#000', text:'28°C', font:{fontSize: 90, fontFamily:'Helvetica Neue'}, textAlign:'center', width:'auto', height: 'auto', right: 15, top: 100});

var detailLabel = Titanium.UI.createLabel({ color:'#000', text: '多雲時陰\n濕度: 62%\n風向: 西北\n風速:10 公里/小時', font:{fontSize: 24, fontFamily:'Helvetica Neue'}, textAlign:'left', width:'auto', height: 'auto', left: 20, top: 220});

win.add(locationLabel);win.add(weatherIcon);win.add(temperatureLabel);win.add(detailLabel);win.open();

建立UI (續)

Page 36: 20110525[Taipei GTUG] titanium mobile簡介

if (Titanium.Geolocation.locationServicesEnabled === false){ Titanium.UI.createAlertDialog({title:'無法使用定位服務',

message:'請開啓定位服務,這樣才能取得現在位置的天氣。'}).show();}else{ Ti.Geolocation.purpose = "get current position"; Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_THREE_KILOMETERS; Titanium.Geolocation.distanceFilter = 1000; Titanium.Geolocation.getCurrentPosition(function(e) { if (e.error) { Titanium.API.info("error: " + JSON.stringify(e.error)); return; } var latitude = e.coords.latitude; var longitude = e.coords.longitude; Ti.API.info(longitude+','+latitude); }); ...}

取得經緯度座標

iOS 3.2以上需要這行。

取座標

Page 37: 20110525[Taipei GTUG] titanium mobile簡介

function updateLocationName(lat, lng){ Titanium.Geolocation.reverseGeocoder(lat, lng, function(e) { if (e.success) { var places = e.places; if (places && places.length) { locationLabel.text = places[0].city; } else { locationLabel.text = ""; } Ti.API.debug("reverse geolocation result = "+JSON.stringify(e)); } else { Ti.UI.createAlertDialog({ title:'Reverse geo error', message:evt.error }).show(); Ti.API.info("Code translation: "+translateErrorCode(e.code)); } });}

更新地名利用座標查詢地址

Page 38: 20110525[Taipei GTUG] titanium mobile簡介

http://www.google.com/ig/api?hl={locale}&weather=,,,{lat},{lng}

Google’s secret Weather API

http://www.google.com/ig/api?hl=zh-tw&weather=,,,25060808,121485606

<?xml version="1.0"?><xml_api_reply version="1"><weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0" > <forecast_information> <city data=""/> <postal_code data=""/> <latitude_e6 data="25060808"/> <longitude_e6 data="121485606"/> <forecast_date data="2010-09-15"/> <current_date_time data="2010-09-14 23:00:00 +0000"/> <unit_system data="SI"/> </forecast_information> <current_conditions> <condition data="多雲"/> <temp_f data="79"/> <temp_c data="26"/> <humidity data="濕度: 87%"/> <icon data="/ig/images/weather/cloudy.gif"/> <wind_condition data="風向: 公里/小時"/> </current_conditions> <forecast_conditions> <day_of_week data="週三"/> <low data="26"/> <high data="35"/> <icon data="/ig/images/weather/thunderstorm.gif"/> <condition data="晴午後短暫雷陣雨"/> </forecast_conditions> ...</weather></xml_api_reply>

http://img0.gmodules.com/前面要加上

Page 39: 20110525[Taipei GTUG] titanium mobile簡介

更新天氣function updateWeather(lat, lng){ var xhr = Titanium.Network.createHTTPClient();

xhr.onload = function() { Ti.API.info('weather xml ' + this.responseXML + ' text ' + this.responseText); //var doc = this.responseXML.documentElement; encoding bug on Android var doc = Titanium.XML.parseString(this.responseText).documentElement;

var condition = doc.evaluate("//weather/current_conditions/condition").item(0).getAttribute('data'); Ti.API.info(condition);

...

temperatureLabel.text = temp_c + '°C'; weatherIcon.image = icon; detailLabel.text = condition + '\n';

detailLabel.text += humidity + '\n'; detailLabel.text += wind_condition.split('、')[0] + '\n'; detailLabel.text += wind_condition.split('、')[1] + '\n'; }; var url = 'http://www.google.com/ig/api?hl=zh-tw&weather=,,,'+parseInt(lat*1000000, 10)+','+parseInt(lng*1000000, 10); Ti.API.info(url); xhr.open('GET', url); xhr.send();}

Page 40: 20110525[Taipei GTUG] titanium mobile簡介

包裝一下function getCurrentWeather()

{

if (Titanium.Geolocation.locationServicesEnabled === false)

{

Titanium.UI.createAlertDialog({title:'無法使用定位服務', message:'請開啓定位服務,這樣才能取得現在位置的天氣。'}).show();

}

else

{

Ti.Geolocation.purpose = "取得目前位置的天氣資訊";

Titanium.Geolocation.accuracy = Titanium.Geolocation.ACCURACY_BEST;

Titanium.Geolocation.distanceFilter = 1000;

Titanium.Geolocation.getCurrentPosition(function(e)

{

if (e.error)

{

Titanium.API.info("error: " + JSON.stringify(e.error));

Titanium.UI.createAlertDialog({title:'無法取得位置資訊', message: e.error.message}).show();

detailLabel.text = '無法取得目前位置的天氣資訊,請稍候再試。';

return;

}

var latitude = e.coords.latitude;

var longitude = e.coords.longitude;

Ti.API.info(longitude+','+latitude);

updateLocationName(latitude, longitude);

updateWeather(latitude, longitude);

});

}

}

Page 41: 20110525[Taipei GTUG] titanium mobile簡介

getCurrentWeather();updateInterval = setInterval(getCurrentWeather, 300000);

每五分鐘更新一次

別忘了第一次

Page 42: 20110525[Taipei GTUG] titanium mobile簡介

建立設定頁面—相同的部份var settingWin = Titanium.UI.createWindow({ backgroundColor: '#999'});

var aboutWebview = Titanium.UI.createWebView({ url: 'about.html', ... });settingWin.add(aboutWebview);

var doneButton = Titanium.UI.createButton({ title: '完成', ...});settingWin.add(doneButton);

doneButton.addEventListener('click', function(e){ if(Titanium.Platform.osname === 'iphone') { settingWin.close({transition: Ti.UI.iPhone.AnimationStyle.FLIP_FROM_RIGHT}); mainWin.open(); }else if(Titanium.Platform.osname === 'android') { mainWin.open(); settingWin.close(); } getCurrentWeather();});

iOS內建特效

依平台不同調整轉場效果

Page 43: 20110525[Taipei GTUG] titanium mobile簡介

<!doctype html><html lang="zh-tw"><head> <meta charset="utf-8"> <title>About</title> <meta name="description" content="About the app"> <meta name="viewport" content="width=320"/> <meta name="author" content="lis186"> <link rel="stylesheet" href="screen.css"></head>

<body><h1>現在天氣怎麼樣</h1><img src='appicon.png'><p>版本 1.0</p><p>Powered by Titanium Mobile.</p></body></html>

about.js

用WebView來簡化文字段落編排

Page 44: 20110525[Taipei GTUG] titanium mobile簡介

建立設定頁面—iPhone部份if(Titanium.Platform.osname === 'iphone'){ var unitTabbedBar = Titanium.UI.createTabbedBar({ labels:['°C', '°F'], style:Titanium.UI.iPhone.SystemButtonStyle.BAR, ... }); unitTabbedBar.addEventListener('click', function(e){ if(e.index === 0) { Titanium.App.Properties.setString('tempUnit', 'c'); }else if (e.index === 1){ Titanium.App.Properties.setString('tempUnit', 'f'); } }); settingWin.add(unitTabbedBar); var settingButton = Titanium.UI.createButton({ ... style: Titanium.UI.iPhone.SystemButton.INFO_DARK }); mainWin.add(settingButton);}

iOS系統按鈕

Page 45: 20110525[Taipei GTUG] titanium mobile簡介

建立設定頁面—Android部份if(Titanium.Platform.osname === 'android'){ var cButton = Titanium.UI.createButton({ title: '°C', ... }); var fButton = Titanium.UI.createButton({ title: '°F', ... });

cButton.addEventListener('click', function(e){ Titanium.App.Properties.setString('tempUnit', 'c'); cButton.enabled = false; fButton.enabled = true; }); fButton.addEventListener('click', function(e){ Titanium.App.Properties.setString('tempUnit', 'f'); cButton.enabled = true; fButton.enabled = false; });

settingWin.add(cButton); settingWin.add(fButton);}

Page 46: 20110525[Taipei GTUG] titanium mobile簡介

依照平台UI慣例切換頁面—iPhone部份

if(Titanium.Platform.osname === 'iphone'){ mainWin.add(settingButton); settingButton.addEventListener('click', function(e){ settingWin.open({ transition: Ti.UI.iPhone.AnimationStyle.FLIP_FROM_LEFT

}); var tempUnit = Titanium.App.Properties.getString('tempUnit', 'c'); if(tempUnit === 'c') { unitTabbedBar.index = 0; }else if(tempUnit === 'f') { unitTabbedBar.index = 1; } mainWin.close(); });}

iOS內建特效

利用Property儲存溫度單位

Page 47: 20110525[Taipei GTUG] titanium mobile簡介

依照平台UI慣例切換頁面—Android部份if(Titanium.Platform.osname === 'android'){ Titanium.Android.currentActivity.onCreateOptionsMenu = function(e) { Titanium.API.info("create menu"); var menu = e.menu; var refreshMenuItem = menu.add({ title: '更新天氣' }); var settingMenuItem = menu.add({ title: '設定' }); refreshMenuItem.addEventListener("click", function(e) { getCurrentWeather(); }); settingMenuItem.addEventListener("click", function(e) { indicator.hide(); settingWin.open(); var tempUnit = Titanium.App.Properties.getString('tempUnit', 'c'); if(tempUnit === 'c') { cButton.enabled = false; fButton.enabled = true; }else if(tempUnit === 'f') { cButton.enabled = true; fButton.enabled = false; } mainWin.close(); }); };}

Page 48: 20110525[Taipei GTUG] titanium mobile簡介

if(Titanium.Platform.osname === 'iphone'){ var service; Titanium.App.addEventListener('pause',function(e) { Ti.API.info('pause'); service = Titanium.App.iOS.registerBackgroundService({ url: 'bgjob.js', tempUnit: Titanium.App.Properties.getString('tempUnit', 'c') }); Titanium.API.info("registered background service = "+service); });

Titanium.App.addEventListener('resumed',function(e) { Ti.API.info('resumed'); if(service != null){ getCurrentWeather(); service.stop(); service.unregister(); Ti.API.info('Stop background service'); } });}

利用iOS background service更新badge

custom property

Page 49: 20110525[Taipei GTUG] titanium mobile簡介

function updateWeather(lat, lng){ var xhr = Titanium.Network.createHTTPClient(); xhr.onload = function() {

var tempUnit = Titanium.App.currentService.tempUnit;

...

if(tempUnit === 'c') { Titanium.UI.iPhone.appBadge = temp_c; Ti.API.info('Update badge:' + temp_c); }else if(tempUnit === 'f') { Titanium.UI.iPhone.appBadge = temp_f; Ti.API.info('Update badge:' + temp_f); } }; var url = 'http://www.google.com/ig/api?hl=zh-tw&weather=,,,'+

parseInt(lat*1000000, 10)+','+parseInt(lng*1000000, 10); Ti.API.info(url); xhr.open('GET', url); xhr.send();}

function getCurrentWeather(){

...}...Ti.API.info('starting background service');var updateInterval = setInterval(getCurrentWeather, 300000);...

bgjob.js

custom property

Page 50: 20110525[Taipei GTUG] titanium mobile簡介

if(Titanium.Platform.osname === 'android'){ Titanium.Android.currentActivity.addEventListener('resume', function(e) { Ti.API.info("resumed"); getCurrentWeather(); });}

Android從背景resume後更新天氣

Page 51: 20110525[Taipei GTUG] titanium mobile簡介
Page 52: 20110525[Taipei GTUG] titanium mobile簡介

結論

Page 53: 20110525[Taipei GTUG] titanium mobile簡介

跨平台 !== “Write Once, Run Everywhere”別忘了為各平台最佳化

Page 54: 20110525[Taipei GTUG] titanium mobile簡介

有了好工具,仍然需要好點子

http://www.cultofmac.com/self-evidently-bad-app-idea-scale-for-ipad

Page 55: 20110525[Taipei GTUG] titanium mobile簡介

http://goo.gl/Se1dF

http://goo.gl/Fj3pl範例:現在天氣怎麼樣

Titanium Mobile SDK

Kitchen Sink

http://goo.gl/5v6dJ

Page 56: 20110525[Taipei GTUG] titanium mobile簡介

Titanium Mobile說明會(加映場)

6/9晚上 邀請制http://www.lis186.com/?p=2140

Page 57: 20110525[Taipei GTUG] titanium mobile簡介

We’re Hiring!

Titanium SDK Developer

Titanium Evangelist

http://ti.herxun.co/?page_id=66

Page 58: 20110525[Taipei GTUG] titanium mobile簡介

謝謝!