Przeglądaj źródła

Migrate UsingPhoneGapBuildWithVaadinTouchKit

tags/7.7.11
Erik Lumme 6 lat temu
rodzic
commit
f1a263c737

+ 269
- 0
documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc Wyświetl plik

@@ -0,0 +1,269 @@
[[using-phonegap-build-with-vaadin-touchkit]]
Using PhoneGap Build with Vaadin TouchKit
-----------------------------------------

At first, using https://build.phonegap.com/[PhoneGap Build] to point to
your Vaadin TouchKit apps seems like a breeze. Just create a simple
`config.xml` and an `index.html` that redirects to your web site, and you
have an app! Unfortunately, simply doing this is not robust. Mobile
devices lose connectivity, and when they do your app not only stops
working, it may appear to freeze up and have to be killed and restarted
to get working again.

With the release of TouchKit v3.0.2 though, there is a solution! This
article summarizes this solution, which was worked out over months of
trial and error on http://dev.vaadin.com/ticket/13250[Vaadin ticket
13250].

'''''

First, server side you need TouchKit v3.0.2. (The needed enhancements
and fixes should roll into _v4.0_ at some point, but as of _beta1_ it isn't
there.) You also need to ensure that your VAADIN directory resources are
being served up by a servlet extending `TouchKitServlet`. If you have a
main application extending `VaadinServlet`, this needs to be changed to
`TouchKitServlet`.

'''''

When your PhoneGap app runs, it loads your provided `index.html` file into
an embedded WebKit browser. Only this file has access to the PhoneGap
Javascript library, so it handles things like offline-mode detection,
and passes this via messages to the iframe containing your
server-provided application.

[source,html]
....
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="user-scalable=no,initial-scale=1.0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>My Application Name</title>
<style type="text/css">
html, body {height:100%;margin:0;}
.spinner {-webkit-animation: spin 6s infinite linear;}
@-webkit-keyframes spin {
0% {-webkit-transform: rotate(0deg);}
100% {-webkit-transform: rotate(360deg);}
}
</style>
</head>
<body style='margin: 0px'>
<script type="text/javascript" src="cordova.js"></script>
<script>
function failedIframe() {
document.getElementById('offline').style.display = 'none';
document.getElementById('spinner').className = '';
document.getElementById('retry').style.display = 'block';
}
function retryIframe() {
document.getElementById('offline').style.display = 'block';
document.getElementById('spinner').className = 'spinner';
document.getElementById('retry').style.display = 'none';
setTimeout(failedIframe, 20000);
document.getElementById('app').src = document.getElementById('app').src;
}
// Use cordova network plugin to inform the iframe about the connection
document.addEventListener('deviceready', function() {
if (!navigator.network || !navigator.network.connection || !Connection) {
console.log(">>> ERROR, it seems cordova network connection plugin has not been loaded.");
return;
}

var iframe = document.getElementById('app');
var loading = document.getElementById('loading');
var offline = document.getElementById('offline');

function sendMessage(msg) {
iframe.contentWindow.postMessage("cordova-" + msg, "*");
}

function check() {
var sts = navigator.network.connection.type == Connection.NONE ? 'offline' : 'online';
sendMessage(sts);
}
function showIframe(ev) {
if (loading.parentNode) {
loading.parentNode.removeChild(loading);
document.getElementById('app').style.width = iframe.style.height = "100%";
sendMessage('resume');
}
navigator.splashscreen.hide();
}
function showOffline() {
document.getElementById('offline').style.display = 'block';
navigator.splashscreen.hide();

// if after a while we have not received any notification we show the retry link
setTimeout(failedIframe, 20000);
}

// Listen for offline/online events
document.addEventListener('offline', check, false);
document.addEventListener('online', check, false);
document.addEventListener('resume', function(){sendMessage('resume')}, false);
document.addEventListener('pause', function(){sendMessage('pause')}, false);
// check the connection periodically
setInterval(check, 30000);

// when vaadin app is loaded, it sends to the parent window a ready message
window.addEventListener('message', showIframe, false);

// If the app takes more than 3 secs to start, proly .manifest stuff is being loaded.
setTimeout(showOffline, 3000);

// Ignore back button in android
// document.addEventListener('backbutton', function() {}, false);
}, false);
</script>
<!-- A div to show in the meanwhile the app is loaded -->
<div id='loading' style='font-size: 120%; font-weight: bold; font-family: helvetica; width: 100%; height: 100%; position: absolute; text-align: center;'>
<div id='spinner' class='spinner'><img src="spinner.png"></div>
<div id='offline' style='display: block; padding: 15px;'>Downloading application files,<br/>Please be patient...</div>
<div id="retry" style="display: none;">
<p>Failed to contact the server.</p>
<p>
Please ensure you have a stable Internet connection, and then
<a href="javascript:void(0)" onclick="retryIframe();">touch here</a> to retry.
</p>
</div>
</div>
<!-- Load the app in an iframe so as we can pass messages, instead of using redirect -->
<iframe id='app' style='width: 0px; height: 0px; position: absolute; border: none' src='http://www.example.com/touch/'></iframe>
</body>
</html>
....

Change the `<title>` and URL in the iframe at the end to match your app.
This also expects a file named `spinner.png` along side `index.html`, which
will be displayed and spin while loading application files from the
server.

This Javascript handles detecting when the app goes offline and back
online (and passes that to TouchKit), provides user feedback during a
long initial load, and provides a friendly retry mechanism if the app is
initially run without network access. It also hides the initial
splashscreen.

'''''

PhoneGap Build requires a config.xml file to tell it how to behave.
Below is a working example that works to create Android 4.0+ and iOS 6 &
7 apps.

[source,xml]
....
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE widget>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:gap="http://phonegap.com/ns/1.0"
id="com.example.myapp" version="{VERSION}" versionCode="{RELEASE}">
<name>My App Name</name>
<description xml:lang="en"><![CDATA[
Describe your app. This only shows on PhoneGap - each app store has you enter descriptions on their systems.
]]>
</description>
<author href="http://www.example.com">
Example Corp, LLC
</author>
<license>
Copyright 2014, Example Corp, LLC
</license>

<gap:platform name="android"/>
<gap:platform name="ios"/>

<gap:plugin name="com.phonegap.plugin.statusbar" />
<gap:plugin name="org.apache.cordova.network-information" />
<gap:plugin name="org.apache.cordova.splashscreen" />
<feature name="org.apache.cordova.network-information" />

<icon src="res/ios/icon-57.png" gap:platform="ios" width="57" height="57" />
<icon src="res/ios/icon-57_at_2x.png" gap:platform="ios" width="114" height="114" />
<icon src="res/ios/icon-72.png" gap:platform="ios" width="72" height="72" />
<icon src="res/ios/icon-72_at_2x.png" gap:platform="ios" width="144" height="144" />
<icon src="res/ios/icon-76.png" gap:platform="ios" width="76" height="76" />
<icon src="res/ios/icon-76_at_2x.png" gap:platform="ios" width="152" height="152" />
<icon src="res/ios/icon-120.png" gap:platform="ios" width="120" height="120" />

<icon src="res/android/icon-36-ldpi.png" gap:platform="android" width="36" height="36" gap:density="ldpi"/>
<icon src="res/android/icon-48-mdpi.png" gap:platform="android" width="48" height="48" gap:density="mdpi"/>
<icon src="res/android/icon-72-hdpi.png" gap:platform="android" width="72" height="72" gap:density="hdpi"/>
<icon src="res/android/icon-96-xhdpi.png" gap:platform="android" width="96" height="96" gap:density="xhdpi"/>
<icon src="res/android/icon-96-xxhdpi.png" gap:platform="android" width="96" height="96" gap:density="xxhdpi"/>

<gap:splash src="res/ios/Default.png" gap:platform="ios" width="320" height="480" />
<gap:splash src="res/ios/Default@2x.png" gap:platform="ios" width="640" height="960" />
<gap:splash src="res/ios/Default_iphone5.png" gap:platform="ios" width="640" height="1136"/>
<gap:splash src="res/ios/Default-Landscape.png" gap:platform="ios" width="1024" height="768" />
<gap:splash src="res/ios/Default-Portrait.png" gap:platform="ios" width="768" height="1004"/>
<gap:splash src="res/ios/Default-568h.png" gap:platform="ios" width="320" height="568" />
<gap:splash src="res/ios/Default-568@2x.png" gap:platform="ios" width="640" height="1136"/>
<gap:splash src="res/ios/Default-Landscape@2x.png" gap:platform="ios" width="2048" height="1496"/>
<gap:splash src="res/ios/Default-Portrait@2x.png" gap:platform="ios" width="1536" height="2008"/>

<gap:splash src="res/android/splash-ldpi.9.png" gap:platform="android" gap:density="ldpi" />
<gap:splash src="res/android/splash-mdpi.9.png" gap:platform="android" gap:density="mdpi" />
<gap:splash src="res/android/splash-hdpi.9.png" gap:platform="android" gap:density="hdpi" />
<gap:splash src="res/android/splash-xhdpi.9.png" gap:platform="android" gap:density="xhdpi"/>

<!-- PhoneGap version to use -->
<preference name="phonegap-version" value="3.4.0" />

<!-- Allow landscape and portrait orientations -->
<preference name="Orientation" value="default" />

<!-- Don't allow overscroll effects (bounce-back on iOS, glow on Android.
Not useful since app doesn't scroll. -->
<preference name="DisallowOverscroll" value="true"/>

<!-- Don't hide the O/S's status bar -->
<preference name="fullscreen" value="false" />

<!-- iOS: Obey the app's viewport meta tag -->
<preference name="EnableViewportScale" value="true"/>

<!-- iOS: if set to true, app will terminate when home button is pressed -->
<preference name="exit-on-suspend" value="false" />

<!-- iOS: If icon is prerendered, iOS will not apply it's gloss to the app's icon on the user's home screen -->
<preference name="prerendered-icon" value="false" />

<!-- iOS: if set to false, the splash screen must be hidden using a JavaScript API -->
<preference name="AutoHideSplashScreen" value="false" />

<!-- iOS: MinimumOSVersion -->
<preference name="deployment-target" value="6.0" />

<!-- Android: Keep running in the background -->
<preference name="KeepRunning" value="true"/>

<!-- Android: Web resource load timeout, ms -->
<preference name="LoadUrlTimeoutValue" value="30000"/>

<!-- Android: The amount of time the splash screen image displays (if not hidden by app) -->
<preference name="SplashScreenDelay" value="3000"/>

<!-- Android: Minimum (4.0) and target (4.4) API versions -->
<preference name="android-minSdkVersion" value="14"/>
<preference name="android-targetSdkVersion" value="19"/>
</widget>
....

The listed plugins are all required to make the splash screen and
offline-mode work properly. The slew of icons and splash screen .png
file are required by the app stores, so be sure to include all of them
in the source .zip that you upload to PhoneGap Build. Placing these
files in a subdirectory allows you to also put an empty file named
".pgbomit" in that folder, which ensures that *extra* copies of each of
these file are not included in the file app package produced by PhoneGap
Build.

'''''

Special thanks to "manolo" from Vaadin for working with me for over a
month to make all of this work by creating enhancements to TouchKit and
the index.html file that the above one is based on.

+ 1
- 0
documentation/articles/contents.asciidoc Wyświetl plik

@@ -15,3 +15,4 @@
- link:BuildingVaadinApplicationsOnTopOfActiviti.asciidoc[Building Vaadin applications on top of Activiti]
- link:UsingVaadinInAnExistingGWTProject.asciidoc[Using Vaadin in an existing GWT project]
- link:UsingPython.asciidoc[Using Python]
- link:UsingPhoneGapBuildWithVaadinTouchKit.asciidoc[Using PhoneGap Build with Vaadin TouchKit]

Ładowanie…
Anuluj
Zapisz