在过去的一年里,你是不是很沮丧,对于所有的使用Objective-C开发iPhone程序的开发者而言,日子都不那么好过,你是不是为了学习开发iPhone应用程序曾经硬着头皮去读着那生涩难懂的学习教程,事实是Objective-C是一门类似C语言的语言,这也就绝定了它不是那么容易学习。
我不是劝你去放弃学习Objective-C,因为世上无难事,只怕有心人。但是条条大路通罗马,也许你转换下思路你可以用另一种方法达到相同的目的。
你可以制作一个原生的iPhone应用程序去模仿其他的程序,多半上它也许会成为一个不错的复制品。
但是你完全可以利用已有的技能(HTML5,CSS,Javascript)去完成上面的事.
下面我会向你们展示如何创建一个具有离线功能的HTML5 iPhone应用程序。更进一步的话,我会向你们展示编写一个俄罗斯方块游戏的过程。
离线
到底什么是离线?好吧,它其实意味着当我们的手机没有互联网连接时,能够有一个像本地应用程序样子的程序图标,启动画面。
这意味这我们的应用程序能够像原生应用程序那样在手机离线时使用。
其实这不仅是一篇针对iPhone开发的教程,它同样适用于所有带有HTML5功能支持浏览器的手机。
OK,下面我们开始吧。看看下面的图片。没有地址栏,没有导航条,它就像是一个原生的应用程序。
准备工作
如果我们要想使用HTML5的离线功能的话,你需要有能够操作服务器端,因为我们需要更改文件的HTTP的头信息。(下面我们会详细讲解)
我们使用Apache做为服务器,为了完成任务,我们需要配置.htaccess文件。这里是个教程使用.htaccess改变HTTP头信息。
其他我们需要做的就是在iPhone设置中打开Safari浏览器的调试模式。在你的iPhone中进入Settings.app > Safari > Developer,然后打开调试模式,这样做的目的是帮助你寻找可能出现的JavaScript错误。
一旦你完成你的App,您应该关闭调试模式以便于你正确的测试你的应用程序。
关于你的App
图标和启动画面
图标的大小57px x 57px。
无论你使用什么样的图标,iPhone会自动对它进行圆角处理,创建投影,并增加光泽。
图标最好使用PNG或JPG格式。
下面是我使用的俄罗斯方块游戏图标。
启动画面大小最好是320px x 460px,且格式为PNG或JPG。
下面是我使用的启动画面。
一些小提示
谨记,简单就是美(Stay small, sparse and simple.)
- Small:虽然可以使用缓存以保存一部分文件,但是保持轻量级也是一个明智的行为。
- Sparse:尽可能的减少处理的文件。
- Simple:不要盲目扩大范围,从小的方面着手,会使你事半功倍。
应用程序缓存
这是一个新的标准,详细信息请看这里。
应用程序缓存允许我们提前告知浏览器我们的应用程序使用了那些文件。浏览器将会把这些文件缓存下来(有时也会失败)。这个文件的语法格式很简单,仅仅就是在manifest文件中列举了文件的相对(例如 /picture.png)或绝对地址(例如 http ://yourwebserver.com/picture.png),浏览器会在离线时保留这些文件。
你也可以列举一些文件地址代表你不想缓存的,但是这跟我们的离线应用程序没有什么关系(如果你有兴趣的话,看这个文档)。
还有一件重要的事是manifest(就是你需要缓存的文件列表)的filetype头信息必须被设置成text/manifest。这就是我们为什么需要有一个web服务器以使我们能够设置HTTP头信息。
屏幕尺寸
当设计你的应用程序时,你需要注意:当你出入App模式时,你的屏幕可利用面积是320px x 46px。当你处于网页模式时你的屏幕可利用面积是320px x 356px。这会影响你的程序的用户界面。
下面就是处于两种模式下的不同点
HTML
你的App其实就是一个网页,因此跟在浏览器中展示的没什么不同。iPhone的浏览器对HTML5的支持程度也是排在前列的,如果你想深入了解的话,请移步Safari开发者中心:
- Safari HTML Reference
- Safari CSS Reference
开始编写代码
应用程序以一些标记开始,下面的就是我的俄罗斯方块游戏的标记。
<!DOCTYPE html> <html manifest=”tetris.manifest”> <head> <metaname=”viewport” content=”user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0″/> <meta name=”apple-mobile-web-app-capable”content=”yes” /> <meta name=”apple-mobile-web-app-status-bar-style”content=”black” /> <link rel=”apple-touch-icon”href=”iphon_tetris_icon.png”/> <link rel=”apple-touch-startup-image”href=”startup.png” /> <link rel=”stylesheet” href=”tetris.css”type=”text/css” media=”screen, mobile” title=”main” charset=”utf-8″><title>offline Tetris</title> </head> <body> <!– Put your Markup Here –><script type=”text/javascript” src=”tetris.js”></script> </body> </html>
首先注意Doctype。哦也以后在也不用写那么长的Doctype了。
在HTML标签里manifest=”cache.manifest”属性是告诉浏览器我们需要缓存那些文件。
这些是在HTML5页面中Apple的专属标记,这里是他们的一些简要说明:
- apple-mobile-web-app-capable: 这是又一个地方告诉浏览器,它一个离线应用程序
- apple-mobile-web-app-status-bar-style:当处于离线时隐藏状态栏和导航栏。
- apple-touch-icon:告诉浏览器程序图标的地址。
- apple-touch-startup-image: 告诉浏览器启动画面的地址。
还有一点请注意,最好把CSS文件放在上面,JavaScript文件放在下面。
CSS
它跟个普通网页没什么两样,但是你可以利用一些特殊的CSS -webkit特性做一些很炫很酷的事情,像动画等。下面是一个很简单的指导,这已经超出了本文的知识范畴。
简单的CSS代码
body { overflow:hidden; background: #d7d7d7; margin:0; padding:0; } #tetris { width: 320px; height: 460px; background:#000; }
主要是设置div元素在网页中适配iPhone的视图。
JavaScript
我使用的是Dalton Ridenhour修改版本的JS库,是我在Github上找到的,这个JS库适用与大多数的浏览器。我唯一做的修改就是让它在没有键盘时也可以使用。
一般情况下,JavaScript能在iPhone上很好的工作,但是也有例外。想想一下mouseover这个事件,它是存在与iPhone浏览器上的,但是如果没有一个标准的指示设备,我很好奇它怎么使用。Quirksmode写了一篇很不错的文章讲解了iPhone浏览器上的事件。
如果上面的事情你已经完成了,你就可以测试你的程序了,只要在iPhone上打开index.html,你就能看到一个最基本的程序已经完成了。
下一步就是把你的程序放到服务器上,然后正确的设置好cache.manifest文件,并放置到你的程序根目录里。好了,看看你的缓存文件工作了没有。
这是我写的一个完成版,你可以在这里查看
- http://tetris.alexkessinger.net
补充说明:离线数据
其实除了可以保存离线文件之外,我们也可以保存离线数据。我们主要使用两个API:第一个是localStorage。localStorage是一个很易于使用的键/值对应的存储形式,我们可以使用这个API像这样:
localStorage.dataToStore = 5; console.log(localStorage.dataToStore); // 5
我们可以利用上面的方式保存用户数据。
第二种方式是离线web SQL数据库(点击链接查看W3C官网的说明)。这个API使用起来有点复杂。下面是一些代码片段。
// Try and get a database object var db; try { if (window.openDatabase) { db = openDatabase(“NoteTest”, “1.0″, “HTML5 Database API example”, 200000); if (!db) alert(“Failed to open the database on disk. This is probably because the version was / bad or there is not enough space left in this domain’s quota”); } else alert(“Couldn’t open the database. Please try with a WebKit nightly with this feature enabled”); } catch(err) { } // Check and see if you need to initalize the DB db.transaction(function(tx) { tx.executeSql(“SELECT COUNT(*) FROM WebkitStickyNotes”, [], function(result) { loadNotes(); }, function(tx, error) { tx.executeSql(“CREATE TABLE WebKitStickyNotes (id REAL UNIQUE, note TEXT, timestamp / REAL, left TEXT, top TEXT, zindex REAL)”, [], function(result) { loadNotes(); }); }); }); // Insert a test Note. var note = { id: “1″, text:” This is a test note”, timestamp: “112123000″, left:10, top:10, zIndex:2 }; db.transaction(function (tx) { tx.executeSql(“INSERT INTO WebKitStickyNotes (id, note, timestamp, left, top, zindex) VALUES / (?, ?, ?, ?, ?, ?)”, [note.id, note.text, note.timestamp, note.left, note.top, note.zIndex]); }); // Get all the notes out of the database.db.transaction(function(tx) { tx.executeSql(“SELECT id, note, timestamp, left, top, zindex / FROM WebKitStickyNotes”, [], function(tx, result) {for (var i = 0; i < result.rows.length; ++i) { var row = result.rows.item(i); var note = new Note(); note.id = row['id']; note.text = row['note']; note.timestamp = row['timestamp']; note.left = row['left']; note.top = row['top']; note.zIndex = row['zindex']; if (row['id'] > highestId) highestId = row['id']; if (row['zindex'] > highestZ) highestZ = row['zindex']; } if (!result.rows.length) newNote(); }, function(tx, error) { alert(‘Failed to retrieve notes from database – ‘ + error.message);return; }); });
总结
通过离线Web App,我们可以做很多东西。做游戏也是可以的,就像我做的俄罗斯方块,但是你最好想清楚哪些东西适合做成离线应用。像Quake 3竞技场估计做不出来,做一个待办事项的App肯定是绰绰有余。