© Frank Zammetti 2018
Frank ZammettiPractical Webixhttps://doi.org/10.1007/978-1-4842-3384-9_9

9. Packaging wxPIM with PhoneGap

Frank Zammetti
(1)
Pottstown, Pennsylvania, USA
 
Now that wxPIM is feature-complete on both the client and server sides, it’s time to talk about truly mobilizing this application.
That’s where a new piece of technology comes into play: PhoneGap. With this tool, you’ll be able to transfer the app into a native application (more or less) that will run across multiple mobile platforms including Android and iOS.
While it’s entirely possible merely to put the client app on a web server and have people access it with their web browser, that’s not a true native app experience, like many people expect these days. You can’t just go and download your app from the app store on your device, such Google Play for Android or the App Store for iOS. That’s a piece of the puzzle that you need to supply, and PhoneGap is precisely what you need to pull off that trick!

The Problems with Mobile Development

Mobile development has historically been a bit tricky if you had it in your head to support multiple platforms. If you wanted an app to run on Android, iOS, Windows Phone, and so on, you faced a Herculean task. The only real option for a long time was to write multiple applications using native SDKs specific to each platform. You’d write your app in Objective-C for iOS, in Java for Android, in .NET for Windows Phone, and in C++ for BlackBerry. Sure, you could design the code of the application in such a way that rewriting it for each platform was slightly easier (that’s just good architecture after all), but it was still essentially rewriting it for each platform, so a little easier or not, it was still a major chore.
This is a form of fragmentation ; the market itself is fragmented with the multiple platforms available. This fragmentation is fantastic for consumer choice, but it does make life difficult for a developer, unless you choose not to support some platforms, and that’s usually not a great idea if you want to reach the widest possible audience. Of course, the market has largely narrowed to two main players, iOS and Android, but there are still other players out there that you may want to consider, and certainly the future could find new players on the field at any time.
However, rewriting code for each platform is becoming less and less the approach that most developers take in favor of (arguably, at least) better choices such as cross-platform libraries that let you write a single codebase that runs on multiple platforms (well, mostly a single codebase anyway). Libraries such as Corona, Ionic, and React Native, for example, allow you to do this, and they do so rather well in many situations.
In this context, the combination of HTML, JavaScript, and CSS can also be viewed as such a cross-platform tool. It’s not always thought of like that, but that’s what it is in effect. You target this “platform” made up of these three technologies, and as long as a mechanism is available on a given “physical” platform to execute your application (read: a web browser), it will generally work across platforms. As it happens, a web browser is exactly that mechanism! Using these technologies, you can avoid a number of forms of fragmentation all at once.
Before I talk about that, though, let’s look at the forms of fragmentation you’re trying to avoid in the first place, that is, the forms of fragmentation that come along with actual native development that make it harder than you’d like it to be.

Fragmentation of User Experience

Another problem with mobile development across multiple platforms is that of providing a consistent user experience . Each platform has its own UI design and patterns that the native development methodologies provide an application. That means the application will look, feel, and function differently in terms of its UI from one platform to another. While there are means by which a developer can to some extent work around this default behavior, it is usually frowned upon. Creating an app that follows the iOS modes of operation and UI metaphors and running it on Android isn’t typically the best answer even when you can pull it off.
Still, it’s a starting point at least, and for some apps, it’ll be acceptable, but it’s still a form of fragmentation that you as a developer need to at least consider.

Fragmentation of Features

It’s also true that not all platforms are created equal in terms of features (though the gap there too has narrowed to a significant degree). Android, for example, has the notion of home screen widgets while iOS does not. If your application’s basic functionality depends on widgets, the experience will be different, perhaps drastically so, on iOS (and it might not even be possible to bring your app to a given platform because of it).
This means your application may have considerably different capabilities running on one platform than it does on another platform by necessity. Especially for users who might jump between platforms, that’s not going to endear them to your application, more so if they lose features they depended on previously.

Fragmentation of Development Tools

Another problem is that of the various development tools. Developing an iOS application, for example, requires you to have a Mac. If you’re more of a Windows user, like I am, that’s a bit of a problem. Even if you’re a Mac user, you still need to have Xcode installed to do iOS development. Even though you can do Android development just fine on a Mac, you don’t need to have Xcode installed for that. There can be vast differences in the platforms and tools you need to develop for various mobile platforms; that’s the basic point here. And, that’s before even talking about the vastly different APIs that each platform presents.
If you want to develop for multiple platforms, then the situation becomes worse. Each platform has its own SDK if nothing else, and you’ll need to install them all for the platforms you want to support. That aside, you’ll still need to learn different languages, APIs, and platform-specific tools. While it’s true that a capable developer can generally jump between technologies without too much difficulty, there’s no question that it slows them down and sometimes leads to less optimal designs. Something that works great in Objective-C might not work as well in Java, architecturally speaking. Being able to optimize a design across technologies is a huge task no matter how capable you are, and the best developer in the world may not be able to overcome some challenges because of the intrinsic differences between mobile platforms.

Enter the White Knight: PhoneGap

Now let’s go back to what I proposed earlier, that is, building an app with HTML, JavaScript, and CSS that runs in a browser on a mobile device (because in theory that should avoid all of that fragmentation). HTML, JavaScript, and CSS are all standards-based technologies, which means that aside from some relatively minor differences here and there between browsers, an app written using them will generally look, feel, and function consistently across platforms. That sure sounds like the Holy Grail of mobile development, doesn’t it? Especially if you narrow the scope a bit to HTML5 , which to most people actually means the combination of HTML5, CSS3, and the latest version of JavaScript you can make a strong case for it being exactly that.
There’s still a significant problem to deal with, though: the “native experience.” What I mean by that is the experience that a user has of downloading an app to their device from an online store that appears to run like any other native app written with Objective-C for iOS or Java for Android, for example. Yes, they can point their web browser at a URL and launch your app, and in some ways, that’s arguably better as it ensures that they always run the latest code. However, it’s not the same thing, and people seem to prefer not having to do that. (I make this statement based on the popularity of apps.)
Is there a way to accomplish that goal with these technologies? Of course, there is: PhoneGap.

What Is It?

PhoneGap is a framework that allows you to use standardized web technologies to build mobile applications. In short, you more or less build your application using HTML5 as you always would and then “package” it using PhoneGap to create a native application . This application can be built to target multiple platforms, and it can then be offered for download in each platform’s online app store. The application, to the end user, looks and works just like any other application. It gets an icon in the launcher, for example, which launches the app without opening the web browser.
Not only does PhoneGap provide this native “wrapper” around your HTML5 application code, but it also provides a robust collection of JavaScript APIs that you can (optionally) use to gain access to the native device capabilities that your HTML5-based application running in a web browser otherwise wouldn’t have access to use. Things such as gyroscopes, accelerometers, GPS, databases, and more, are made available to you via these APIs. While you certainly can write an application that doesn’t use them, you often will want to incorporate them in order to provide all the capabilities that users expect from a modern mobile app.
The underlying goal of PhoneGap is to offer, effectively, a runtime that provides parity across platforms. Develop a PhoneGap application using standard HTML5 technologies, one that targets the PhoneGap APIs where necessary, and the result is that your app will work the same across all supported platforms without you having to lift a finger to achieve that goal. In other words, it’s Nirvana!

A Brief History of PhoneGap

PhoneGap was birthed at an event in San Francisco named iPhoneDevCamp in 2008 as a means to deal with the issue that many developers run into when starting iOS development, which is that Objective-C can be challenging or, at the very least, unfamiliar even to experienced developers. Although somewhat less true today because of the popularity of iOS development, it was certainly true in 2008. At that point in time, it was called PhoneGap. It quickly gained popularity because it provided experienced web developers with an avenue into native iOS development using technologies with which they were already comfortable, rather than having to learn Objective-C and a completely new way of doing things. Then, in 2009, Cordova (still known as PhoneGap) won the People’s Choice Award at O’Reilly Media’s Web 2.0 conference. That’s when people really started to take notice, and it was the catalyst for PhoneGap usage to explode quickly.
Though originally created by a company named Nitobi, PhoneGap was purchased by Adobe in 2011. Shortly thereafter, Adobe contributed the PhoneGap codebase to the Apache Software Foundation where it lives now under the name Cordova.
Don’t let this confuse you! In simple terms, Cordova is the underlying open source library, while PhoneGap, still very much alive and kicking under the Adobe banner, is the most commonly used distribution of Cordova, so to speak. Perhaps a better way to put it is that it is analogous to how WebKit relates to Safari: WebKit powers Safari, and, in the same way, Cordova powers PhoneGap. Yes, that also means there could be other competing versions of Cordova, and it also means that PhoneGap could have different capabilities than the basic distribution of Cordova.
As a developer, you can choose to use “naked” Cordova if you like, or you can use PhoneGap specifically. The differences will, by and large, not be huge, aside from some differences in tooling. For the sake of simplicity, you’re going to use PhoneGap because that gives you the ability to use something that Adobe provides called PhoneGap Build, which will make life much easier for you here. We’ll get to that shortly, but before then, let’s cover something else: how PhoneGap does what it does.

How Does This Black Magic (Basically) Work?

I’ve been using the term native app a bit loosely here with regard to PhoneGap. In fact, PhoneGap apps are actually “hybrid” apps, not true native apps. The difference is that a hybrid app runs within a WebView, which handles rendering the UI, rather than the native toolkit of the underlying OS platform.
A WebView is something that nearly all modern mobile OSs have. Some platforms have different names for it, but probably the most common one is WebView. Whatever it’s called, it’s a specific UI component that can be embedded directly into the UI of a true native application. Typically, this is used to show things such as online help content or registration pages—any web site really that the application needs.
This is done without launching a separate web browser, and I’m sure you can see how that’s a handy capability for any app to have! A WebView differs from a web browser in that it doesn’t have typical web browser controls such as the back, forward, and home buttons. Instead, it’s just the viewport portion of a browser—the blank canvas onto which HTML is rendered. Beyond being simply handy for a native app, though, it’s the key to PhoneGap!
At the most basic level, PhoneGap is not much more than a small native app with a UI that is nothing but a full-screen WebView control within which your HTML5 web app is launched. From there on, your app works as if it were running in a web browser, which, of course, it actually is, as far as the HTML and JavaScript that make up your app are concerned! Remember, though, it’s a web browser that doesn’t look like a web browser to the user since it doesn’t have the usual navigation controls or other “chrome” around the rendering surface of a typical browser. The canvas on which your app renders its UI is the entire screen of the mobile device effectively, just as is the case for a native app.
It’s really one of the more clever ideas to come along, but it’s also quite simple and obvious after the fact, which, of course, is a hallmark of any great idea! There is, of course, slightly more to it than that. Every WebView control allows for one other key capability: the ability of JavaScript code to call native code, be it C/C++, Objective-C, or Java, depending on the OS. It presents these calls as part of a large JavaScript API that you can use, or not use at all; it’s completely up to you. Since this book isn’t about PhoneGap, it’s about Webix, I won’t go into much detail on these APIs, just like I didn’t go into the vast API provided by Node or Express . However, near the end of this chapter, I will use an API to enhance wxPIM, just to give you a little bit of a view into what the APIs have to offer.

A Simpler Build Approach: PhoneGap Build

Creating a PhoneGap app isn’t hard. You essentially build it like any other web app you would build and then you use the command-line tools provided by PhoneGap (or just Cordova if you want to stay completely open source). Either of those provides a robust command-line interface (CLI) that allows you to take that simple web app and package it up into a native app.
The problem with that, though, is that it requires all that native tooling I talked about earlier. You need the SDKs for the platforms you want to support installed, plus whatever IDEs or tools they require, and that assumes you’re on the appropriate desktop platform to install any of it in the first place! It can be quite a nightmare to get a proper cross-platform mobile development platform set up. It’s time and effort even if it goes smoothly or it could be a huge pain in the tuchus, as my mom likes to say!
Thankfully, there is a much simpler solution that takes virtually all of this pain away: PhoneGap Build. PhoneGap Build is a cloud-based solution offered by Adobe that allows you to upload your application’s source code, plus a small XML configuration file that provides some details needed by the servers that then builds your application for a number of platforms and ultimately makes download links available to you. You simply upload an archive of your app, and after a few minutes, you’ll be able to download versions for various supported mobile platforms.
It really is a fantastic service that removes virtually all the pain of building for multiple mobile platforms. Let’s dive in, shall we?

Get Ready: Signing Up

The first thing you’ll need to do is to sign up for a PhoneGap Build account. To do so, visit https://build.phonegap.com and click the big Get Started! button next to the floating robot over the scrolling sky. (I know, it sounds crazy, but that’s what’s there, and it actually looks cool!) When you click the button, the page will automatically scroll to a section that outlines your plan choices, as shown in Figure 9-1.
A455420_1_En_9_Fig1_HTML.jpg
Figure 9-1
PhoneGap Build plan options
If you happen already to have an Adobe ID , then you are all set! Simply sign in with your credentials for that service, and you’re good to go. You will have the ability to create 25 separate private apps within PhoneGap Build, and you can then manage and build them independently. You’ll also have the ability to have unlimited open source apps. The difference between a public app and a private app in this context is simply where the source code of your app is found. If your code can be found on GitHub or some other publicly available Git repository, then it is public. Otherwise, it’s private. For your needs here, you’ll be dealing with a private app, so there’s no need to get set up with Git and no need for you to have any knowledge of it if you don’t want to. The number of private apps allowed is the big differentiating factor in the PhoneGap Build plans available to you. For your purposes here, a single private app is fine, but if you need more, then that’s when you’ll need to fork over some cash to Adobe.
Of course, you can remove an existing private app to make room for another at any time, and so as long as you’re working on only one app at a time, then the free option would be sufficient. The free service also, from my experience, is subject to longer lines in terms of queuing for a build to occur. In other words, you might wait five minutes for your build to complete instead of 30 seconds if you have a paid plan (though most of the time the build speed actually is measured in seconds). That’s a small price to pay in my mind. Either way, for what you need to do here, it’s perfectly fine.
Once you select your plan, you’ll be asked to sign into an existing Adobe account or to create a new one (you can also log in with Facebook or Google credentials if you prefer).
Once you create the account or log in, then you’ll find yourself staring at a screen very much like the one shown in Figure 9-2, which is your personal app console. At this point, you can do a number of things. First, you can create a new private app by supplying the URL to a Git repository (or connect to your GitHub account if you have one) or upload a ZIP archive of your application. If you already have an app uploaded, as I do in the screenshot, you can update the code (if I’m creating a new build) or request PhoneGap Build to rebuild all the available versions (iOS, Android, and Windows Phone). You can also click the icons for each of the supported platforms to download the packaged application for that platform. There’s even a QR code you can scan with your phone to access the download link (because typing is for suckers!)
A455420_1_En_9_Fig2_HTML.jpg
Figure 9-2
Your app console
Really, for what you’re doing in this book, that’s just about all you need to know about PhoneGap Build , well, except for one very important thing that allows it to work at all: the configuration file.

Get Set: The Configuration File

The configuration file, which you’ll name config. xml and place in the root directory of the app alongside the index.html file that serves as the app’s starting point, is where you specify metadata about your application that informs PhoneGap Build about various parameters it needs to build your application. Most of the information you can put in this file is optional, and you can get away with a small subset of all that is available to you. Listing 9-1 is the config.xml file for wxPIM. As you can see, it is rather spartan.
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns:="http://www.w3.org/ns/widgets"
  xmlns:gap="http://phonegap.com/ns/1.0"
  id="com.etherient.wxPIM"
  version="1.0.0">
  <name>wxPIM</name>
  <description>wxPIM fom the book Practical Webix by Frank W. Zammetti</description>
  <author href="http://www.zammetti.com" email="[email protected]">Frank W. Zammetti</author>
  <preference name="phonegap-version" value="cli-6.5.0" />
  <plugin name="cordova-plugin-vibration" spec="2.1.5" />
</widget>
Listing 9-1
The config.xml File for wxPIM
The first required element is the <widget> element. This must be the root element that lets PhoneGap Build know you’re following the widget specification, which the config file is based on. This element has a number of attributes, but only id and version are required.
The id attribute is the unique identifier of your application, which must be unique across all apps built using PhoneGap Build. The way you ensure this without meeting up with every other developer in the world and coming to some sort of arrangement is to use reverse-domain name naming. This is typically seen in Java package names, and it is simply your domain name backward, plus an app name. For example, I own the domain name etherient.com, so com.etherient.wxPIM fits the bill. Now I only have to ensure the final portion of that, wxPIM, is unique within the domain I control. I’m not averse to arguing with myself at times, but I’m sure even I can manage this level of cooperation with myself!
The version attribute is a free-form field, but typically the value is in the common major.minor.patch form, as you can see.
The <name> and <description> elements, children of the root <widget> element, are not actually required by the widget spec, but the PhoneGap Build documentation calls them out as required by the build servers. The <author> element is similarly not required, not even by the build servers, though it’s a good element to include anyway.
The <preference> element is how you define various options to direct the build servers what to do. None are required, but at a minimum, the phonegap-version option should usually be specified so that you know what version of the library the build servers will build your code with.
Finally, the <plugin> element tells PhoneGap Build that your app is going to use a PhoneGap plug-in, which are JavaScript modules that expose various native device capabilities through a JavaScript API. In this case, you’re going to use the vibration plug-in so you can make the device vibrate under certain conditions that you’ll see shortly.
There’s quite a lot more you can specify in the config file, including things like images for icons and splash screens and plug-ins to use (plug-ins being extra PhoneGap libraries that provide more capabilities to your app), but that’s going beyond the scope of this book. If you’re interested, and certainly I hope you are at this point, the PhoneGap Build documentation provides all the details (and there are even GUI tools available to create the config file if you prefer; search online for configap to find one).

Go: Starting the Build

With a config.xml file written and added to the root of your application, it’s time to kick off a build. The first step to doing this is a simple one: create a ZIP archive from your application’s directory. This needs to include all your application code, including libraries (like Webix).
Note when I say “zip up that directory,” I mean you should zip up the contents of the directory, not the directory itself. Put another way, after you zip it up, copy the archive file to an empty directory somewhere else and try to extract it. When you do so, you should not see a new directory created in the empty directory. Instead, you should see the contents of the root of the application “spill out,” so to speak, directly into the previously empty directory into which you’re extracting the archive.
With the archive created, you can send it off to PhoneGap Build. To do so, click that New App button on the app console, which will lead to a screen like in Figure 9-3.
A455420_1_En_9_Fig3_HTML.jpg
Figure 9-3
Adding a new app
Here, I’ve clicked the Private tab since that’s the kind of app I want to send. And, given that you have a ZIP file to upload, the Git repo part doesn’t matter; only that big “Upload a .zip file” does. Once you click that button and select the ZIP file, you’ll be greeted by a progress bar for a few seconds before finding yourself back on the app console screen with the new app listed.
But, at this point, nothing has been done other than shipping the archive off to the build servers. To initiate the build, you click the Ready to Build button that you’ll find is available. Once you do, it shouldn’t really take more than ten seconds or so for an app the size of wxPIM to be built.

Crossing the Finish Line: The Output Files

After the build completes and you’re back at the app console screen, you can click the name of your app to see details about it, as shown in Figure 9-4.
A455420_1_En_9_Fig4_HTML.jpg
Figure 9-4
wxPIM details
Each of the supported platforms uses its own native bundle formats, but all of them are archives containing platform-specific code. On iOS, the format is IPA. For Windows Phone, it’s an APPX file. For Android, the answer is an APK.
Notice in Figure 9-4 that the iOS build has failed, as indicated by the error icon. If you click the Error button, it will explicitly tell you that this is because you need to provide a signing key for iOS. While Android and Windows Phone support signing keys as well, they aren’t required for development and so don’t cause an error. I’ll touch on this in the next section.
At this point, you can download the bundle for each platform using the buttons next to each (except for iOS) and install those bundles onto a real device, or an emulator, and begin testing your app.
From here you can also upload a new archive via the Update code button, or you can trigger a rebuild with the “Rebuild all” button . You can also rebuild for a specific platform with the Rebuild button next to each, and you can select signing keys with the drop-downs (which also include functionality to add those keys).
PhoneGap Build also has the notion of “collaborators,” others that are working on a project with you. The Collaborators tab lets you maintain this list of people and provides them with the ability to, for example, download builds. You can also view and maintain plug-ins that your app uses on the Plugins tab (if any are used, obviously). Finally, the Settings tab allows you to control some things about your app. This includes enabling debugging capabilities to your app and enabling hydration (something beyond the scope of this book, but in short, it’s a means to allow you to easily push new builds to testers quickly). You can also switch an app between being public and private (subject to the limitations of your account type of course), and you can delete the app entirely from here as well (to make room for a different single private app if you’re using a free account, for example).

Getting Files onto Your Device

As described in the previous section, the native bundles for each platform for which your app was successfully built are easily downloadable from the app info page or the Install page. However, that tells you nothing about how to get that bundle onto a real device or an emulator. Let’s talk about that now, shall we?

Deploying to Android Devices

For Android, the answer is quite simple: plug in your device and copy the APK to the device like you would any other file. When that’s done, use whatever file manager you prefer and execute the APK. That will trigger an application installation like any other, providing you do one thing first: enable the “Unknown sources” option, which allows for the installation of apps from sources other than the Play store. This option is under Security in your devices’ settings.
Another approach, and the technique I personally use most because it is arguably the simplest and most convenient, at least in my mind, is to create a share to a network directory on my PC. Next, I make sure that the APK is present in that directory, and then I use a file system browser on my device, such as FX File Explorer , ES File Explorer, or Astro File Explorer (all of which critically include SMB capabilities) to browse to that share and directly launch the file. This approach is nice because I don’t have to bother with USB cables, making sure that drivers are installed, or any of that. I also don’t have to worry about uploading to a web server (of course, the web server could be running locally, which would make that approach not much different from this one frankly). It’s still a two-step process, as all of these are, but now it’s very straightforward. In addition, when I’m testing on multiple devices, it’s easy since the same APK is always at the same location, and I can browse to it any time I like to install it.
If you are already familiar with Android development and have the Android SDK installed, then you can use ADB (Android Debug Bridge, a command line tool for interacting with an Android device) to push the APK to your device. But, since that requires installing some development tools to work and you’re trying to avoid that as much as possible, I’ll leave that to an exercise for you if you’d like to explore that option on your own.

Deploying to iOS Devices

To deploy to an iOS device , you’ll need a few things.
  • First, you’ll need a Mac because the development tools you’ll need to accomplish the next few steps (OpenSSL and most likely Xcode) are available only on a Mac. (OpenSSL isn’t Mac-only, but Apple only allows you to complete these steps on a Mac, and Xcode is most definitely Mac-only.)
  • Then, you’ll need to sign up for the iOS developer program ($99 per year). This will give you access to the Apple Developer Portal.
  • Next, you’ll need to obtain an Apple developer certificate using the Keychain Access application.
  • After that, you'll need to register the devices you want to be able to deploy to on the Apple Developer Portal.
  • Once that’s done, you’ll need to create a provisioning profile, also through the Apple Developer Portal.
  • With that accomplished, you’ll be able to use the certificate you created as a signing key on PhoneGap build.
  • Finally, with a build successful using the key, you’ll then be able to plug in your i-device and push the app to it for testing using the developer tools you installed.
And if that sounds like a lot of effort, you are 100 percent correct!
It’s not really that difficult once you walk through the steps , but if it’s your first time, it can seem very daunting—so daunting, in fact, that I’m not going to try to cover it all here! Instead, I’m going to point you to one address.
That’s the PhoneGap Build page that describes the steps and provides links to everything you’ll need. The bottom line is that if you want to deploy an app build with PhoneGap Build to iOS, unlike Android or Windows Phone, you’ll need to pay for the privilege, and you’ll need to run the iOS development gauntlet to at least some degree to be able to do so.

A Few Necessary Code Changes and Enhancements

If you take the wxPIM app code as it exists right now and submit it to PhoneGap Build, assuming you add the config.xml file, it won’t work. That’s because there are a few changes that are necessary. The first is that since you need to include everything your app needs in the archive, which includes Webix, that means that in index.html, the paths to Webix need to be updated. Fortunately, that’s as easy as changing the Webix CSS and JS file imports to the following:
<link rel="stylesheet" href="webix/webix.css" type="text/css" media="screen" charset="utf-8">
<script src="webix/webix.js" type="text/javascript" charset="utf-8"></script>
Now, the Webix source is copied into the root directory of the project, and that minor issue is taken care of.
Something else you need to do is to add a new import.
<script type="text/javascript" src="phonegap.js"></script>
That brings in the core PhoneGap code that is required to use any of PhoneGap’s capabilities, like the vibration API. In fact, you can leave the app as it is now and build it, and it will ostensibly work, but you won’t be able to use any PhoneGap capabilities. Note that the PhoneGap Build documentation says that you should not include this file. However, in practice, using the vibration API, or indeed any PhoneGap plug-in , seems to depend on this import being present. I’m not certain if this is a bug in PhoneGap Build, though that’s my guess, and either way, at the time of this writing, this import is required.
That isn’t quite enough, though, because up until now you’ve been either loading wxPIM directly off the file system or getting it from the Node server. This presents a problem because the AJAX code doesn’t know the address to the Node server now. To deal with that, you’ll add a prompt where the user can enter the server address at startup. To do so, the following code is added to the start() method in the core.js file, right at the end:
const serverAddress = localStorage.getItem("serverAddress");
if (!serverAddress) {
  wxPIM.promptForServerAddress();
} else {
  // Get all data from server.
  wxPIM.getAllData();
}
The server address will be stored in local storage, so if it isn’t found at startup, then you need to prompt for it via a call to wxPIM.promptForServerAddress() , which is this:
promptForServerAddress() {
  wxPIM.maskUI();
  const win = webix.ui({
    view : "ani-window", move : false, width : 260,
    position : "center", resize : false, id : "serverAddressWindow", toFront : true,
    fullscreen : false, head : "Information needed",
    body : { height : 140, rows : [
      { borderless : true, height : 30, template : "Please enter server address",
        css : { "text-align" : "center", "padding-top" : "10px", "padding-bottom" : "10px" }
      },
      { view : "text", id : "serverAddressText", css : { "padding-bottom" : "10px" } },
      { view : "button", label : "Ok",
        click : () => {
          localStorage.setItem("serverAddress", $$("serverAddressText").getValue());
          $$("serverAddressWindow").close();
          wxPIM.unmaskUI();
          wxPIM.getAllData();
        }
      }
    ] }
  });
  win.show();
}
This shows a window asking the user for the server address. After that, the window is closed, and wxPIM.getAllData() is called, which you’ll notice is what is done if the address was found in start(). Of course, what if the server address isn’t correct or isn’t reachable? Well, that’s where some changes to getAllData() come into play.
getAllData() {
  wxPIM.maskUI();
  const failOrExceptionHandler = function(inObj) {
    navigator.vibrate(3000);
    localStorage.removeItem("serverAddress");
    $$("baseLayout").hide();
    webix.message({
      type : "error", text : "Server not available, wxPIM is in read-only mode"
    });
  };
  try {
    webix.ajax()
      .timeout(10000)
      .headers({ "Content-Type" : "application/json" })
      .post(`${localStorage.getItem("serverAddress")}/getAllData`,
        JSON.stringify(wxPIM.registeredModules)
      )
      .then(function(inResult) {
        const serverAddress = localStorage.getItem("serverAddress");
        localStorage.clear();
        const allModuleData = inResult.json();
        for (let moduleName of wxPIM.registeredModules) {
          const moduleDataArray = allModuleData[moduleName];
          const moduleDataObject = { };
          for (let i = 0; i < moduleDataArray.length; i++) {
            const nextItem = moduleDataArray[i];
            moduleDataObject[nextItem.id] = nextItem;
          }
           localStorage.setItem(`${moduleName}DB`, webix.stringify(moduleDataObject));
        }
        localStorage.setItem("serverAddress", serverAddress);
        wxPIM.unmaskUI();
        wxPIM.dayAtAGlance();
      })
      .fail(failOrExceptionHandler);
  } catch (inException) {
    failOrExceptionHandler(inException);
  }
}
The basic logic here is that you make the call to the server to get all data like always, but now you have the possibility of a failure or an exception. Both are treated the same: the server can’t be reached for some reason, whether it’s a network problem or the user fat-fingered the address. To reduce code, you have a single handler for both, the failOrExceptionHandler function. If this executes, then the server address is removed from local storage, and a slightly altered message from the last version of wxPIM is shown. The user can then reload the app to enter the server address again, but note that the UI is not hidden this time like before. This allows them to use the app in read-only mode. (If they try to mutate data, assuming the server still can’t be reached, they’ll get the failure message like before.)
You’ll also see a call to navigator.vibrate() in that handler code. This is using the PhoneGap vibration API and causes the device to buzz for three seconds (assuming the device has haptic feedback capabilities; if it doesn’t, this line will simply do nothing). This is just a little extra alert to the user that the server wasn’t reachable.
Of course, if the AJAX request is successful, then everything just continues as before…well, almost! Since the procedure here is to clear local storage before filling it with the data retrieved from the server, you have a problem because that includes the server address! So, before the clear, the address is saved and then set again after the clear and the data load.
Another required change in wxPIM is in the common saveHandler() and deleteHandler() methods, which are just prepending the server address to the URL, the same as is done in getAllData(). Other than these changes, wxPIM works as expected as a PhoneGap-ified app.
One final change must be made to make this all work, and it’s in the constructor. Previously, the last line of the constructor was as follows:
webix.ready(this.start.bind(this));
Now, however, in the world of PhoneGap, you have to change that to the following:
document.addEventListener("deviceready", this.start.bind(this), false);
The reason this change is necessary is because you can’t use PhoneGap APIs like vibration until the device tells you it’s ready for that, and PhoneGap provides a deviceready event to signal that. To ensure the API hasn’t been used before, then you no longer use webix.ready() since that, it turns out, fires before deviceready does (at least some of the time), so you delegate to PhoneGap’s event instead to ensure you don’t really start the app until it says you’re good to go. (The app being used before is unlikely given it wouldn’t occur until the UI is built and the user enters a server address and clicks the button on the dialog, but this is still something you should try to avoid.)
With that, wxPIM is now PhoneGap-ready and is a true mobile app, at least as close as you’re going to get without having to deal with Objective-C, Java, and all the other stuff that comes with doing true native development!

Summary

In this chapter, you took wxPIM and created a “native” app out of it using the popular PhoneGap tool. You saw how this allows you to have a package specific to a mobile platform like Android or iOS that can be installed like any other application from that platform’s app store. You also saw how the APIs that PhoneGap provides can be used to enhance an application running in such a mode and how PhoneGap Build allows you to do builds in the cloud without mucking about with native SDKs and tooling installation.
In the next chapter, you’ll see a whole new side of Webix as we developer another whole app that is nothing at all like wxPIM: a game!
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset