• No results found

Coding Tips You Should Know Before Distributing Your HTML5 Web App on Mobile Devices

N/A
N/A
Protected

Academic year: 2021

Share "Coding Tips You Should Know Before Distributing Your HTML5 Web App on Mobile Devices"

Copied!
50
0
0

Loading.... (view fulltext now)

Full text

(1)

© 2013 Amazon.com, Inc. and its affiliates. All rights reserved. May not be copied, modified, or distributed in whole or in part without the express consent of Amazon.com, Inc.

Russell Beattie, Amazon

November 15, 2013

Coding Tips You Should Know Before Distributing

Your HTML5 Web App on Mobile Devices

(2)

Agenda

• Welcome

• HTML5 Mobile Web App Basics

• Setup

• DevTools Demo

• Coding Tips and Best Practices

• HTML

• CSS

• Javascript

• Offline

(3)

HTML5 Mobile

Web App Basics

(4)

Setup

• Text Editor

• Modern Desktop Browser

• Chrome, Firefox, Safari, IE 11, etc.

• Modern Mobile Browser or Tester

• Amazon Web App Tester, Chrome, etc.

• Android SDK

• For remote debugging

(5)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

<style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head>

<body>

<div id="content"></div>

<script src="main.js"></script> </body>

</html>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(6)

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(7)

<!DOCTYPE html>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(8)

<!DOCTYPE html> <html>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(9)

<!DOCTYPE html> <html>

<head>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(10)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(11)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(12)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(13)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

<style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(14)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

<style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css">

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(15)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

<style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head>

<body>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(16)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

<style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head>

<body>

<div id="content"></div>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(17)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

<style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head>

<body>

<div id="content"></div>

<script src="main.js"></script>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(18)

<!DOCTYPE html> <html>

<head>

<meta charset="UTF-8">

<title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">

<style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head>

<body>

<div id="content"></div>

<script src="main.js"></script> </body>

</html>

Basic HTML5 Web App Template

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Basic Template</title> <meta name="viewport"

content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1"> <style>

html, body {height: 100%; margin: 0; padding: 0; background: #000; color: #FFF} </style>

<link rel="stylesheet" href="main.css"> </head> <body> <div id="content"></div> <script src="main.js"></script> </body> </html> Friday, November 15, 13

(19)

DevTools Demo

• Connecting (via WebSockets or TCP/IP)

• Live modification of page (CSS, HTML)

• Interaction with device via inspection button

• Debugging (JavaScript, Network, etc.)

• Frame-rate / GPU

• Profiling

(20)

Coding Tips and

Best Practices

(21)

HTML

(22)

<meta

name

=

"apple-touch-fullscreen"

content

=

"yes"

>

<meta

name

=

"apple-mobile-web-app-capable"

content

=

"yes"

>

<meta

name

=

"apple-mobile-web-app-status-bar-style"

content

=

"black"

>

<meta

name

=

"apple-mobile-web-app-title"

content

=

"UVM Home"

>

<link

rel

=

"apple-touch-startup-image"

href

=

"/startup.png"

>

<link

rel

=

"apple-touch-icon"

sizes

=

"128x128"

href

=

"niceicon.png"

>

<link

rel

=

"apple-touch-icon-precomposed"

sizes

=

"144x144"

href

=

"img/touch/apple-touch-icon-144x144-precomposed.png"

>

<link

rel

=

"apple-touch-icon-precomposed"

href

=

"img/touch/apple-touch-icon-57x57-precomposed.png"

>

<link

rel

=

"shortcut icon"

href

=

"img/touch/apple-touch-icon.png"

>

Headers - Apple

(23)

<!-- Google -->

<meta

name

=

"mobile-web-app-capable"

content

=

"yes"

>

<link

rel

=

"shortcut icon"

sizes

=

"196x196"

href

=

"nice-highres.png"

>

<link

rel

=

"shortcut icon"

sizes

=

"128x128"

href

=

"niceicon.png"

>

<!-- Blackberry -->

<meta

name

=

"HandheldFriendly"

content

=

"true"

>

<meta

name

=

"cursor-event-mode"

value

=

"native"

>

<meta

http-equiv

=

"x-rim-auto-match"

content

=

"none"

>

<!-- Microsoft -->

<meta

http-equiv

=

"X-UA-Compatible"

content

=

"IE=edge"

>

<meta

http-equiv

=

"cleartype"

content

=

"on"

>

<meta

name

=

"msapplication-TileImage"

content

=

"pics/logowin8pin.png"

/>

<meta

name

=

"msapplication-TileColor"

content

=

"#B20099"

/>

<meta

name

=

"msapplication-badge"

value

=

"frequency=1440;polling-uri=http://

www.example.com/Win8TileNotification.php"

/>

Headers - Google, Blackberry, Microsoft

(24)

<link

rel

=

"shortcut icon"

type

=

"image/x-icon"

href

=

"favicon.ico"

/>

<link

rel

=

"shortcut icon"

href

=

"favicon.ico"

/>

<meta

name

=

"format-detection"

content

=

"telephone=no"

>

<meta

name

=

"format-detection"

content

=

"address=no"

/>

<link

rel

=

"dns-prefetch"

href

=

"page2.html"

>

<meta

name

=

"description"

content

=

""

/>

<meta

name

=

"keywords"

content

=

""

/>

Headers - Firefox, W3C, etc.

(25)

<form>

Date: <input

type

=

"date"

value

=

"2013-09-03"

name

=

"dateInput"

>

Datetime: <input

type

=

"datetime"

name

=

"datetimeInput"

>

Datetime-local:

<input

type

=

"datetime-local"

value

=

"2013-09-03T20:00"

name

=

"datetime-local"

>

Email: <input

type

=

"email"

name

=

"emailInput"

>

Month: <input

type

=

"month"

value

=

"2013-09"

name

=

"monthInput"

>

Number: <input

type

=

"number"

name

=

"numberInput"

>

Password: <input

type

=

"password"

name

=

"passwordInput"

>

Range: <input

type

=

"range"

name

=

"rangeInput"

>

Search: <input

type

=

"search"

name

=

"searchInput"

>

Tel: <input

type

=

"tel"

name

=

"telInput"

>

Time: <input

type

=

"time"

name

=

"timeInput"

>

Url: <input

type

=

"url"

name

=

"urlInput"

>

</form>

Input Field Types

(26)

<input

type

=

"url"

name

=

"urlInput"

required

pattern

=

"https?://.+"

>

...

input

:required:invalid

,

input

:

focus:invalid

{

background-image: url(/images/invalid.png);

background-position: right top;

background-repeat: no-repeat;

}

input

:required:valid {

background-image: url(/images/valid.png);

background-position: right top;

background-repeat: no-repeat;

}

Required and Validation

(27)

CSS

(28)

html

{

-webkit-tap-highlight-color: rgba(

0

,

0

,

0

,

0

);

-webkit-user-select: none;

}

body

{

-webkit-font-smoothing: antialiased;

/* Fix for webkit rendering */

-webkit-text-size-adjust:

100

%;

}

/* don't let "actions" dialog to come up when element is touch/held */

.prevent-action

{

-webkit-touch-callout: none;

}

Interaction

(29)

/* no dragging of element at all */

.content p.no-drag

{

-webkit-user-drag: none;

}

/* drags entire element, not the text/selection */

.sidebar div.element-drag

{

-webkit-user-drag: element;

}

/* change the character used to hide user passwords */

input

[type=

"password"

] {

-webkit-text-security: square;

}

textarea

[contenteditable] {

-webkit-appearance: none;

}

Interaction continued

Friday, November 15, 13

(30)

/* position */

-webkit-transform: translate(

0, 0

);

-webkit-transform: translateZ(

0

);

-webkit-transform: translate3d(

0

,

0

,

0

);

/* scale */

-webkit-transform: scale(

0

);

/* rotation */

-webkit-transform: rotate(

0

);

/* opacity */

opacity:

0.5

;

Hardware acceleration

Friday, November 15, 13

(31)

@-webkit-keyframes pulse { from { -webkit-transform: scale(.1); } to { -webkit-transform: scale(1); } } div { -webkit-animation-name: pulse; -webkit-animation-duration: 2s; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: ease-in-out; -webkit-animation-direction: alternate; } // Javascript

content.addEventListener("webkitAnimationIteration", countAnims, false);

Animations

(32)

// CSS

.box

{

left:

40px

;

-webkit-transition: all

0.3s

ease-out;

}

div.box.totheleft

{

-webkit-transform: translate3d(

0

,

0

,

0

);

}

div.box.totheright

{

-webkit-transform: translate3d(

80px

,

0

,

0

);

}

// Javascript

window.

addEventListener

(

"webkitTransitionEnd"

, function() {

// Handle the end of the transition

}, false);

Transitions

(33)

@media screen and (orientation:portrait)

{

/* portrait-specific styles */

}

@media screen and (orientation:landscape)

{

/* landscape-specific styles */

}

@media only screen and (-webkit-min-device-pixel-ratio:

1.5

), only screen and

(min-resolution:

144dpi

)

{

/* Style adjustments for viewports that meet the condition */

}

Media Queries

(34)

JavaScript

(35)

var mql = window.

matchMedia

(

"(orientation: portrait)"

);

if(mql.matches) {

// Portrait orientation

} else {

// Landscape orientation

}

mql.

addListener

(function(m) {

if(m.matches) {

// Changed to portrait

} else {

// Changed to landscape

}

});

// Resizing

window.

addEventListener

(

"resize"

, function() {

// window.innerHeight > window.innerWidth ...

}, false);

Orientation Detection

(36)

var meta = document.

createElement

(

"meta"

);

meta.

setAttribute

(

'name'

,

'viewport'

);

var content =

'initial-scale='

;

content +=

1

/ window.devicePixelRatio;

content +=

',user-scalable=no'

;

meta.

setAttribute

(

'content'

, content);

document.

getElementsByTagName

(

'head'

)[0].

appendChild

(meta);

Device Resolution

(37)

// no pre-rendering

function

render

() {

drawSpaceShip

(context);

requestAnimationFrame

(render);

}

// pre-rendering

var sprite = document.

createElement

(

'canvas'

);

sprite.width =

64

;

sprite.height =

64

;

var spriteCtx = sprite.

getContext

('

2d

');

drawSpaceShip

(spriteCtx);

function

render

() {

context.

drawImage

(sprite,

0

,

0

);

requestAnimationFrame

(render);

}

Canvas pre-rendering

(38)

// Slower

for (var i =

0

; i < points.length -

1

; i++) {

var p1 = points[i];

var p2 = points[i+

1

];

context.

beginPath

();

context.

moveTo

(p1.x, p1.y);

context.

lineTo

(p2.x, p2.y);

context.

stroke

();

}

// Faster

context.

beginPath

();

for (var i =

0

; i < points.length -

1

; i++) {

var p1 = points[i];

var p2 = points[i+

1

];

context.

moveTo

(p1.x, p1.y);

context.

lineTo

(p2.x, p2.y);

}

context.

stroke

();

Canvas batch calls

(39)

// redraw entire canvas

context.fillRect(0, 0, canvas.width, canvas.height);

// redraw only 'dirty' areas

context.fillRect(last.x, last.y, last.width, last.height);

// faster way to redraw canvas

context.clearRect(0, 0, canvas.width, canvas.height)

Canvas Redraw Regions

(40)

function

animate

(time){

//random drawing

context.

clearRect

(

0

,

0

, canvas.width, canvas.height);

context.

beginPath

();

context.

rect

(x, y,

50

,

50

);

context.fillStyle =

'#8ED6FF'

;

context.

fill

();

// Old way:

// window.setTimeout(animate, 1000/60);

// New way:

window.

requestAnimationFrame

(animate);

}

RequestAnimationFrame

(41)

var bstyle = document.body.style;

// cache

bstyle.padding =

"20px"

;

// reflow, repaint

bstyle.border =

"10px solid red"

;

// another reflow and a repaint

bstyle.color =

"blue"

;

// repaint only, no dimensions changed

bstyle.backgroundColor =

"#fad"

;

// repaint

bstyle.fontSize =

"2em"

;

// reflow, repaint

// new DOM element - reflow, repaint

document.body.

appendChild

(document.

createTextNode

(

'hello...'

));

Reflows and repaints

(42)

// Slower

var elem = document.

getElementById

(

'animated'

);

elem.style.fontSize = (elem.offsetWidth /

10

) +

'px'

;

elem.firstChild.style.marginleft = (elem.offsetWidth /

20

) +

'px'

;

// Faster

var elem = document.

getElementById

(

'animated'

),

elemWidth = elem.offsetWidth;

elem.style.fontSize = (elemWidth /

10

) +

'px'

;

elem.firstChild.style.marginleft = (elemWidth /

20

) +

'px'

;

Minimize dimension or location queries

(43)

function SomeObject() { var self = this;

this.lastExecThrottle = 500; // limit to one call every "n" msec

this.lastExec = new Date();

this.timer = null;

this.resizeHandler = function() {

var d = new Date();

if (d-self.lastExec < self.lastExecThrottle) { if (self.timer) {

window.clearTimeout(self.timer);

}

self.timer = window.setTimeout(self.resizeHandler, self.lastExecThrottle);

return false; // exit

}

self.lastExec = d; // update "last exec" time

self.callResizeHandlerFunctions(); }

}

var someObject = new SomeObject();

window.onresize = someObject.resizeHandler;

Debounce Events

(44)

Offline

(45)

AddType text/cache-manifest

.manifest

AddType text/cache-manifest

.appcache

AddType application/x-web-app-manifest+json

.webapp

Server MIME Types

(46)

CACHE MANIFEST

# Version 1.0

# filename: app.manifest or name.appcache

CACHE:

index.html

Game-Break.mp3

Game-Death.mp3

Game-Shot.mp3

Game-Spawn.mp3

main.js

main.css

three.min.js

...

<html

manifest

=

"app.manifest"

>

App cache manifest

(47)

{

"name": "Flip.io",

"description": "Flip.io - 999 Word Puzzles. A simple, yet challenging word puzzle that

will entertain novices and lexicographers alike. Presented with 10 word definitions and

scrambled tiles of letter combos, can you find all the words?",

"launch_path": "/",

"icons": {

"60": "/flip60.png",

"128": "/flip128.png"

},

"developer": {

"name": "Russell Beattie",

"url": "http://flip.io"

},

"default_locale": "en",

"fullscreen": "true"

}

W3C Web App Manifest

(48)

{

"verification_key": "insert your verification key from the App File(s) tab",

"launch_path": "index.html",

"permissions": [

"iap",

"geolocation",

"auth"

],

"type": "web",

"version": "0.1a",

"last_update": "2013-04-08 13:30:00-0800",

"created_by": "webappdev"

}

Amazon Mobile Web App Platform Manifest

(49)

Real World App Demo

(50)

Please give us your feedback on this

presentation

As a thank you, we will select prize

winners daily for completed surveys!

MBL301

Thank You

@RussB • [email protected]

developer.amazon.com/webapps

Friday, November 15, 13

References

Related documents

You  can  transfer  files  between  computers  or  mobile  devices  using  a  web  browser.    This  could  be  useful  when  a  mobile  app  is  not 

In summary, converting your content to HTML5 provides an easy way to consolidate, future-proof, and scale content assets while facilitating delivery to mobile devices and the Web..

Mobile device HTML5 JavaScript CSS OpenEdge JSDO HTML5 browser HTML5 JavaScript CSS OpenEdge JSDO HTML5 JavaScript CSS OE JSDO Mobile App Web App GET HTTP(S)

Because it takes time to register these documents at the Land Titles Office and to obtain the mortgage advance from the Lender, the sale price may not be paid to the Seller until

Our mobile app comes with your free, it allows you need to manage their best free mobile receipt app sorts them.. Devices

Your developers will quickly see the benefits adding up as they develop high- performance HTML5 web or hybrid apps that are compatible with all mobile devices (smartphones and

Build HTML5 app as Web page. embedded within

If death occurs when local municipal offices are closed, a funeral director may be needed to furnish or sign the disposition or transit permit, especially in states using