HOWTO: Create native-looking iPhone/iPad applications from HTML, CSS and JavaScript

Though it's not widely known, you can write native-feeling iOS apps for the iPhone and iPad in JavaScript (+ HTML and CSS).

In this article, I'll explain how to:

  • strip away the browser chrome (the url bar and button bar);
  • prevent viewport scrolling and scaling;
  • respond to multi-touch and gesture events;
  • use webkit CSS to get the iPhone OS look and feel;
  • cache the app so it runs without internet access;
  • get a custom icon on the home screen; and
  • have a splash screen load at the start.

If you want to put it in the app store, you can even package your web app as a "native" Objective-C app. (Although, why you'd want to subject yourself to the app store approval process when you don't have to is beyond me.)

I've put this HOWTO together, because--even on Apple's site--there's not one centralized page that tells you how to do all this. I've included templates, examples and a stubbed-out XCode project.

If you want to go deeper than what's in this post, I recommend the bookBuilding iPhone Apps with HTML, CSS, and JavaScript.

My motivation for finally building an iPhone app was frustration with a paper-based medical logging system. My wife and I have to keep a medical log of just about everything my son does: seizure types/lengths, caloric intake/composition, hydration, medication doses, sleep, urine chemistry, blood pressure, heart rate, weight, activities and bowel movements. Naturally, we're always trying to remember where we last had the log book. An iPhone/iPad app seemed like the perfect solution for medical logging, so I took the plunge.

Update: I built a second iOS app out of JavaScript, also for my son: it's amultitouch remote control for a robot: use the rotate gesture to rotate the robot; use the swipe to move it forward and back; tilt to take a picture with its camera.

Read on for the details, tips and tricks I've learned.

 

More resources

On top of the information below, I can recommend a few other resources:

Making it full-screen

Normally, if you press "+" in mobile Safari and then "Add to Home Screen," the icon it creates acts like a bookmark into Safari. When the browser opens up, you've got the URL bar at the top and the button bar at the bottom. If you're trying to deploy a real app, this just wastes screen real estate and detracts from its professional feel.

To get rid of the URL and button bars, just add a meta tag:

<meta name="apple-mobile-web-app-capable"
      content="yes" />

This is what my log app looks like when launched from the home screen:

Changing the phone status bar

You can also change how the phone's status bar is displayed with a meta tag. You can make it white, black or translucent:

<meta name="apple-mobile-web-app-status-bar-style"
      content="default" />

The values for content are defaultblack and black-translucent.

Preventing scaling

If you pinch on a web app, it still responds like it's in a browser and zooms in. This can be a giveaway that the app isn't native. If you want to prevent scaling, use the viewport meta tag:

<meta name="viewport"
    content="user-scalable=no, width=device-width" />

You'll almost certainly want to set the viewport width to the device width as well, so that the app shows up at its natural resolution.

Preventing elastic scrolling

If you a flick a web app past the bottom or top of the page, the page itself gets elastically tugged away from the URL bar or the button bar (or the bottom/top of the screen if it's in full-screen mode).

This behavior is another giveaway that your app isn't native, and it's rarely the behavior you want in a native app.

To stop this behavior, capture touchmove events on the document in JavaScript and cancel them. You can do this by adding a handler to the bodytag, and invoking the preventDefault method on the event object:

<script>
 function BlockMove(event) {
  // Tell Safari not to move the window.
  event.preventDefault() ;
 }
</script>
 
<body ontouchmove="BlockMove(event);" >
  ...
</body>

Creating a home screen icon

To add a home screen icon, create a 114x114 .png file, and then link to it in the header:

<link rel="apple-touch-icon"
      href="./apple-touch-icon.png" />

The iPhone automatically applies the glossy finish.

On older iPhones, which used 56x56 icons, and the iPad, which uses 72x72 icons, the graphic automatically scales down.

If you don't want the glossy finish applied automatically, use apple-touch-icon-precomposed instead of apple-touch-icon.

Creating a splash screen

To add a splash screen during loading, create a 320x460 .png file, and then link to it in the header:

<link rel="apple-touch-startup-image"
      href="./startup.png" />

The file must be exactly 320x460, or else the iPhone ignores it. (The iPad requires 1004x768.)

Caching application files

If you want to be able to use your application without internet, or you want to improve its load time, create a cache manifest file, and link to it from the main file for the web app:

<html manifest="cache.manifest">

Make sure your web server serves up .manifest files with the MIME typetext/cache-manifest, or else this won't work. If you're using apache, put the following in your .htaccess file:

 AddType text/cache-manifest .manifest

And then check using wget -S that the content type in the response headers is correct.

Inside the cache.manifest file, list which files should be cached and which should be retrieved from the network:

CACHE MANIFEST
local1.file
local2.file NETWORK:
network1.php
network2.cgi

If you find your app suddenly stopped working when you started using a cache manifest, make sure every URL you use is in the right section.

When a cache manifest is in use, the app launches with the last version of the files.

It pulls a new version of the manifest in the background if network connectivity is available, and on the next launch you'll see the new version if the manifest has changed. You'll want to include a serial number in a comment in the cache manifest, so that you can up it every time you release a new version; for example, here's my logging application's manifest:

CACHE MANIFEST

# Bump this with each release:
# Serial number 7 apple-touch-icon.png
jquery.js
scroll-bg.jpg
startup.png
medical-log.css
medical-log.js
cached.html NETWORK:
show-log.php
insert-into-log.php
delete-log-entry.php
update-log-entry.php

I recommend renaming the manifest file so that it 404s during iterative development.

Detecting touch and gesture events

You can capture multi-touch and gesture events in JavaScript. And, there's a good reason to do this too: if you listen for traditional events like clicks, you'll get a one second delay while the iPhone highlights the element that was "clicked." If you're trying to mimic a real app, this behavior starts to feel tedious and slow. By capturing touch events directly, you can respond instantly to user input.

There are two ways to track touch events. When you capture raw touch events, you're tracking individual fingers. When you capture gesture events, you're capturing interpretations of finger movement, like scaling and rotating.

The touch handlers you can attach to are:

  • ontouchstart - a finger goes down.
  • ontouchmove - a finger moves.
  • ontouchend - a finger goes up.

The gesture handlers you can attach to are:

  • ongesturestart - a scale or a rotation starts.
  • ongesturechange - a scale or a rotation.
  • ongestureend - a scale or a rotation ends.

If you just want to use touching in place of clicking, then the target field of the event object contains the element that was touched.

I created an example app that uses gestures to scale a graph.

There's also a great write-up of touch and gesture events in JavaScript, if you want to provide deeper multi-touch support.

For more code and a second JavaScript app that uses gestures heavily, see my second iPhone app post: a multitouch remote control for a robot.

Detecting rotation events

If you want to take an action when the phone is rotated, listen foronorientationchange events on the body tag. The current orientation is inwindow.orientation, and it is encoded as the angle (in degrees) that the iPhone is rotated--0, -90 or 90--away from vertically upright.

Mimicking iPhone OS components

The webkit rendering engine supports a lot of CSS extensions, and you can use these to simulate native Cocoa components; for example, buttons are easy:

.button {
font-family: Helvetica ;
font-weight: bold ;
padding: 15px;
border: 1px solid black ;
-moz-border-radius: 8px ;
-webkit-border-radius: 8px ;
margin-top: 10px ;
margin-bottom: 10px ;
background-color: white ;
}

I created the iPhone-like background for my logging app with a background-image for the document body.

The book Building iPhone Apps with HTML, CSS, and JavaScript can show you how to simulate all of the standard iPhone UI elements.

Creating a native "Objective-C" app

If you want to publish your app in the app store, you'll need to write it in Objective-C. Fortunately, Cocoa includes a UIWebView class, which is just the Mobile Safari browser without its chrome. So, you can actually bundle your HTML/CSS/JavaScript app up natively by wrapping it in a few lines of canned Objective-C.

Of course, once you wrap your web app up as a native app, you can use Objective-C to access more features of the iPhone. If you want to get into Objective-C programming, I recommend the book Cocoa and Objective-C: Up and Running as both a reference and a tutorial.

Here are the bare bones steps to turning a web app into a native app:

  1. Open XCode.
  2. Create a new "View-based Application" iPhone project.
  3. Move the files for your web app into the Resources folder in XCode, but strip out the cache manifest. (You don't want the manifest screwing things up, since everything is now local.)
  4. Create a new instance variable, webView, inside the @interface ViewController header file:
       IBOutlet UIWebView* webView ;
    // IBOutlet means it's visible to Interface Builder.

    and create a property:

       @property (nonatomic, retain) UIWebView *webView;
      
  5. In the ViewController implementation file, synthesize webView:
       @synthesize webView; 
  6. Open the ViewController interface file from Interface Builder Files folder.
  7. From the Library's Objects menu, drag a Web View component into the layout/design window.
  8. Select the ViewController.xib window, and then File's Owner.
  9. Connect (by dragging) the webView outlet from the connections window to the Web View.
  10. Return to XCode.
  11. Implement the viewDidLoad method in the ViewController implementation file:
    - (void)viewDidLoad {
    [super viewDidLoad];
    NSString *filePath =
    [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
    NSData *htmlData = [NSData dataWithContentsOfFile:filePath]; if (htmlData) {
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *path = [bundle bundlePath];
    NSString *fullPath = [NSBundle pathForResource:@"index"
    ofType:@"html" inDirectory:path];
    [webView loadRequest:[NSURLRequest requestWithURL:
    [NSURL fileURLWithPath:fullPath]]];
    }
    }

    This will load index.html from the Resources folder on launch.

  12. Fire it up in the simulator. You should now see your app.

Confused? Just download my pre-configured web application XCode project, and drop your files into Resources.

Tips

  • Download the iPhone SDK and test with the simulated iPhone/iPad Safari. Only do tests on the iPhone itself when you're checking to see if performance is good enough.
  • Install the app from an IP address rather than a hostname to cut out the DNS look-up time on application launch.
  • JavaScript on the iPhone doesn't handle lots of string manipulation well; prefer DOM tree manipulation for constructing user interfaces over mashing innerHTML.
  • Take advantage of JavaScript libraries like jQuery for cutting down on the tedium.

iPad quirks

Creating native iPad web apps is almost identical to creating native iPhone web apps. The biggest changes are that your start-up image must be exactly 1004x768. Other than that, it's mostly the same.

Detecting iPhone OS

You might want your app to behave a little differently depending on where it's run. I used the following JavaScript to detect if the app is running inside an iPhone, an iPod Touch or an iPad:

 var IsiPhone = navigator.userAgent.indexOf("iPhone") != -1 ;
var IsiPod = navigator.userAgent.indexOf("iPod") != -1 ;
var IsiPad = navigator.userAgent.indexOf("iPad") != -1 ; var IsiPhoneOS = IsiPhone || IsiPad || IsiPod ;

Hosting

If you're looking for a hosting provider for your web app, I recommendlinode.com

I've been running might.net on a linode for years, and I'm using them to host my medical logging app.

They're hard to beat for price, performance, flexibility and customer service.

Code

Feel free to use my template.html, a stubbed-out blank web app.

Example: Multi-touch graph navigation

I wrote an app that creates a full screen canvas and then lets you zoom in and out of the graph of f(x) = sin(x) using the pinch-to-zoom gesture.

This runs well on my iPad and in the simulator, but it's a little choppy on my first-gen iPhone.

Feel free to poke around and modify the code: graph.html.

Example: Medical logging application

The medical logging app is a nice example because it caches much of itself locally, resorting to the network only for synchronization via PHP scripts that interact with a database.

And, it's been a major quality-of-life improvement for me and my wife.

HOWTO: Create native-looking iPhone/iPad applications from HTML, CSS and JavaScript的更多相关文章

  1. 网络电话pjsip Getting Started: Building for Apple iPhone, iPad and iPod Touch

    Getting Started: Building for Apple iPhone, iPad and iPod Touch ¶ Getting Started Preparation Get th ...

  2. iPhone/iPad/Android UI尺寸规范 UI尺寸规范,UI图标尺寸,UI界面尺寸,iPhone6尺寸,iPhone6 Plus尺寸,安卓尺寸,iOS尺寸

    iPhone/iPad/Android UI尺寸规范 UI尺寸规范,UI图标尺寸,UI界面尺寸,iPhone6尺寸,iPhone6 Plus尺寸,安卓尺寸,iOS尺寸 iPhone界面尺寸 设备 分辨 ...

  3. Glyphish – 精心打造的 iPhone & iPad 应用程序图标

    Glyphish 是一套精心打造的图标库,包含 iOS 工具栏.标签栏.导航条等等,Glyphish 图标也完美的用在 Android.Windows Mobile App 和移动网站的 UI 设计等 ...

  4. 通过Mac远程调试iPhone/iPad上的网页(转)

    我们知道在 Mac/PC 上的浏览器都有 Web 检查器这类的工具(如最著名的 Firebug)对前端开发进行调试,而在 iPhone/iPad 由于限于屏幕的大小和触摸屏的使用习惯,直接对网页调试非 ...

  5. 体验应用程序在Mac/iPhone/iPad之间的Handoff

    对于苹果新推出的Handoff功能,之前只体验了接电话的Handoff.一个电话打过来,iPhone/iPad/Mac同时响起,这时如果手上拿着东西在吃,就可以直接在Mac上接电话. 除此之外,还可以 ...

  6. iphone/ipad关于size, frame and bounds总结和UIScroll view学习笔记

    1. iphone/ipad大小 Device Screen dimensions(in points) iphone and ipod 320 X 480 ipad 768 X 1024 2. UI ...

  7. iOS iPhone iPad 各种控件默认高度

    iPhone iPad 各种控件默认高度 注意:这些是ios7之前的,ios7之后(包括ios7)有改动,我会在后面标注出来 iPhone和iPad下各种常见控件的宽度和标准是一样的,所以这里就用iP ...

  8. 【Xamarin挖墙脚系列:现有IPhone/IPad 设备尺寸】

    原文:[Xamarin挖墙脚系列:现有IPhone/IPad 设备尺寸]

  9. 【优秀的iPhone/iPad数据恢复工具】Omni Recover for Mac 2.5

    [简介] 今天和大家分享最新的 Omni Recover for Mac 2.5 版本,这是一款Mac上优秀的iPhone/iPad设备数据恢复工具,支持恢复误删除的短信.照片.视频.文档.通话记录等 ...

随机推荐

  1. 第六节:宿主如何使用AppDomain

    前面已经讨论了宿主以及宿主加载CLR的方式.同时还讨论了宿主如何告诉CLR创建和卸载AppDomain.为了使这些讨论更加具体,下面将描述一些常见的宿主和AppDomain使用情形.特别地,我要解释不 ...

  2. viewPager+Handler+Timer简单实现广告轮播效果

    基本思想是在Avtivity中放一个ViewPager,然后通过监听去实现联动效果,代码理由详细的解释,我就不说了. MainActivity.java package com.example.adm ...

  3. hdu 1277 全文检索

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1277 全文检索 Description 我们大家经常用google检索信息,但是检索信息的程序是很困难 ...

  4. hdu 1622 Trees on the level

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1622 小白书上的题... #include<algorithm> #include< ...

  5. Android程序完全退出的三种方法

    很多网友可能发现自己的Android程序有很多Activity,比如说主窗口A,调用了子窗口B,在B中如何关闭整个Android应用程序呢? 这里Android123给大家三种比较简单的方法实现. 首 ...

  6. iOS学习之UI自定义cell

    一.自定义Cell 为什么需要自定义cell:系统提供的cell满足不了复杂的样式,因此:自定义Cell和自定义视图一样,自己创建一种符合我们需求的Cell并使用这个Cell.如下图所示的这些Cell ...

  7. 六大Nagios常见问题解决办法

    Nagios常见问题1: It appears as though you do not have permission to view information for any of the host ...

  8. Resizing the View(待续。。。。)

    在iOS开发的过程中,控件的大小和位置如何去安排是一个现在看来比较麻烦的事情,需要从上到下的通知和从下到上的调整.而这部分在整个开发过程中是比较重要的,但是却经常没有被掌握.如果将这部分掌握,不管界面 ...

  9. C++11 常用语法

    1 新类型 C++ 11新增了long long和unsigned long long,以支持64bit宽度: 新增char16_t和char32_t以支持16位和32位字符表示: 增加了“原始”字符 ...

  10. python time,string 转换

    1. 将字符串转换成时间,字符串格式为05/16/2015 datetime.datetime.strptime(STRING,"%m/%d/%Y") 2. 将时间转换成字符串:格 ...