diff options
author | Erik Lumme <erik@vaadin.com> | 2017-09-15 09:10:39 +0300 |
---|---|---|
committer | Erik Lumme <erik@vaadin.com> | 2017-09-15 09:10:39 +0300 |
commit | f1a263c737b68b9117cefecd59ca74e88e33f67e (patch) | |
tree | ab4e39fc91ef69398a70be80299cd91751bff867 | |
parent | c03cac6468b040bd8f2c7cb82f8f0fd1d2d34609 (diff) | |
download | vaadin-framework-f1a263c737b68b9117cefecd59ca74e88e33f67e.tar.gz vaadin-framework-f1a263c737b68b9117cefecd59ca74e88e33f67e.zip |
Migrate UsingPhoneGapBuildWithVaadinTouchKit
-rw-r--r-- | documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc | 269 | ||||
-rw-r--r-- | documentation/articles/contents.asciidoc | 1 |
2 files changed, 270 insertions, 0 deletions
diff --git a/documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc b/documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc new file mode 100644 index 0000000000..7c09d6ac9c --- /dev/null +++ b/documentation/articles/UsingPhoneGapBuildWithVaadinTouchKit.asciidoc @@ -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. diff --git a/documentation/articles/contents.asciidoc b/documentation/articles/contents.asciidoc index 012d040654..74e58e9708 100644 --- a/documentation/articles/contents.asciidoc +++ b/documentation/articles/contents.asciidoc @@ -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] |