Tag Archives: PhoneGap

Installing Crosswalk in an Older PhoneGap Project

08 Sep 2015

Starting with Android 5.0 the webview has been separated from the OS and is now itself an app that will receive updates like any other app. The implication here is that from Android 5.0 and up users won’t have to receive an OS update to get better webviews for PhoneGap apps to use, they can now download and install WebView updates separate from the OS.

All fine and good – in the meantime older Android versions still have the webviews that shipped with the OS / device. OS updates don’t happen very often, typically only occurring when someone gets a new phone or until the device manufacturer decides to issue an update. In even rarer instances a device might be updated if it is rooted and a custom ROM is applied.

Until recently this meant that PhoneGap developers would still have to deal with the various webkits that their apps may encounter and whatever features might be lacking (The most infamous example of a lacking feature that comes to mind was the completely missing toDataURL() canvas method a few years ago.)

Given all the different Android devices in the wild it is sometimes quite a task for developers to be able to create hybrid apps that behave predictably in all the different webkit flavors. The Crosswalk plugin addresses this issue by embedding a web runtime in your Android apps (Android 4 and up) meaning that you don’t need to worry about the version of webkit on older Android OS’s as you now have an modern embedded Chromium under the hood giving you a consistent environment for your apps to execute within.

Today I’m trying to update an older app of mine so that it will use Crosswalk and I hit an issue that prevented me from installing it. The error:

“Plugin doesn’t support this project’s cordova-android version. Cordova-android: 3.6.3, failed requirement: >=4”

corsswalk_1

The first thing to be aware of is that the CrossWalk plugin requires Android 4. While searching online revealed some hacks to force Crosswalk to install that wasn’t something that I wanted to do.

My first instinct was to edit the manifest.xml since I recall from having previously used Eclipse to compile my apps that that would be the course of action to take. Unfortunately as you may know the Eclipse ADT no longer works with Eclipse and the latest SDK’s so thats not something I want to try and get working since the Cordoca CLI makes compiling a lot easier.

Anyway, editing the manifest.xml didn’t seem to have an effect as rebuilding did nothing and trying to re-add the platform resulted in the “Platform android already added” error message. Searching online revealed a few hacks that could be done and seems to have worked for some people but I didn’t want to pursue any hacky methods so I stopped bothering with trying to use my current project files.

In the end I decided to rebuild my PhoneGap project and target a specific version of Android so as to meet Crosswalk’s requirements. The takeaway is that yes, you’ll have to rebuild and wont be able to install CrossWalk for apps targeting pre Android 4 devices.

The easiest way to rebuild the project to target more recent versions of Android is to simply delete the Android folder out of the project and then rebuild it. While a wholesale delete works a cleaner method (presumably) is to issue the CLI command to remove the platform. Either way you don’t have to worry about reinstalling all of your plugins as Cordova will detect their prior installation and install them all for you when the new target platform is created.

So then, I deleted the Android folder using the CLI via this command…

  • cordova platform remove android

…and then reinstalled Android making sure to target a specific version using this syntax:

  • cordova platform add android@x.x.x

Where the @x.x.x represents the desired version of the OS.

An easy way to see what version numbers will work is to try to create an Android project with a version that doesn’t exist. Try Android 4.2 and Cordova will of course fail the attempted platform add but also show you the valid version numbers / install targets that it expects.

corsswalk_2

That’s a nice reference – I decided to go for Android 4.1.1 JellyBean.

  • cordova platform add android@4.1.1

In the image below you can see the result of the install followed by a list of all the installed plugins – note that it happened on its own since if you were to look in the project folder all the plugins are there – all we did was delete the platform so Cordova still knows what plugins to install.

corsswalk_3

A quick build showed my app working – all done!

Installing The SQLite PhoneGap Plugin via the CLI

30 Apr 2014

For some reason I had issues trying to install the PhoneGap SQLite plugin for Android on my Windows 8.1 laptop using the CLI. Attempting to run the install resulted in a Command failed: fatal: could not create work tree dir error. After some fruitless searching for a solution I took another look at the error message and thought that maybe the problem would be something simple to resolve.

This type of CLI command usually works:

phonegap plugin add https://github.com/brodysoft/Cordova-SQLitePlugin.git

As mentioned this resulted in the following error:

sqlite_npm_install

 

The key to solving this is in the error message – apparently the temp path can’t be created…. so… create it!

Using Explorer navigate to this path:

  • C:\Users\[YOUR USER NAME]\AppData\Local\Temp

 
Note that “AppData” is likely a hidden folder – just enter the path (use your own user name where appropriate). For example:

 

sqlite_npm_install_path

 

Once in the Temp folder create the necessary directories to recreate the following path:

  • C:\Users\[YOUR USER NAME]\AppData\Local\Temp\plugman\git

 
And once again run the CLI command for installing the plugin. This time everything runs without error:

 

sqlite_npm_install_success

 

Disable Android Back Button in InAppBrowser

21 Apr 2014

This is a quick hit – if you’re using the InAppBrowser plugin in your PhoneGap app on Android you may want the child browser to display without the location bar and the included “close” button. The PhoneGap docs explain how to do this well enough, however Android’s back button is still functional. If you tap it enough you will eventually shutdown the child web view which may not be what you wanted to happen.

You could try to over-ride the default behavior by creating an event listener for the backbutton event but once InAppBrowser launches it handles the back button on its own. The backbutton event won’t fire until **after** the InAppBrowser child view has closed which of course is too late for our purposes.

An easy way to solve this is to just comment out the InAppBrowser function that handles the backbutton behavior. Locate InAppBrowser.java in your project and search for a function called closeDialog. Once you locate it just wrap a c-style comment around the body of the function and save.

If in addition to preventing the web view from shutting down you also want to have the back button function like a web browser’s back button then you need to be a little more precise with your edit. As before, locate the closeDialog. It should look like the code sample below – note the changes:

  • Line 16: Comment out this line
  • Line 23: Comment out this line
  • Line 24: add the following: childView.goBack()
    public void closeDialog() {

        final WebView childView = this.inAppWebView;
        // The JS protects against multiple calls, so this should happen only when
        // closeDialog() is called by other native code.
        if (childView == null) {
            return;
        }
        this.cordova.getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                childView.setWebViewClient(new WebViewClient() {
                    // NB: wait for about:blank before dismissing
                    public void onPageFinished(WebView view, String url) {
                if (dialog != null) {
                    //dialog.dismiss(); // COMMENT OUT THIS LINE
                }
            }
        });
                // NB: From SDK 19: "If you call methods on WebView from any thread 
                // other than your app's UI thread, it can cause unexpected results."
                // http://developer.android.com/guide/webapps/migrating.html#Threads
                //childView.loadUrl("about:blank"); // <<< COMMENT OUT THIS LINE
	        childView.goBack(); // <<< ADD THIS LINE
            }
        });

        try {
            JSONObject obj = new JSONObject();
            obj.put("type", EXIT_EVENT);
            sendUpdate(obj, false);
        } catch (JSONException ex) {
            Log.d(LOG_TAG, "Should never happen");
        }/**/
    }

This worked for me on my HTC One M8 - but, I'm not a Java Developer so please look at the above with a critical eye. Let me know in the comment section below if you have changes to whats here!

Simple Android Back Buttons in Sencha Architect 2 & Phonegap

15 Oct 2013

As you may know Android has a back button – present as a software back button or in older devices as a capacitive button on the device itself. The question is how to hook into it and get your views to change in Sencha Touch. Sure, Sencha walks you through Routes and such, but all I want is something simple, and this technique is just that, simple and easy to understand.

This approach uses the browser’s history object and updates it with a hash comprised of the current panel’s id. As you navigate about your app the hash is updated as desired. When the user taps Android’s back button the history object’s back() method is fired. Hash changes don’t cause a page reload so your app doesn’t reload either. After firing the back() method we wait a few milliseconds and then fire our own function to update the view based on the current hash.

This works great for an app that is comprised of a single container whose children are the panels that you want to view. More complex structures would require that you get into Sencha Touch’s Routing mechanism (and to be honest, you *should* be using routes).

One Level of Navigation within a single container

Lets review a scenario that is conducive to implementing simple back button functionality – an app built with the following structure:

back_history_structure_1

As you can see this is a very simple app – a single container with one level of children.

To begin lets add 2 custom methods to our application. Start Architect, and click on the “launch” node within the Project inspector and paste the following into the code view:

Ext.define('MyApp.appHistory', {
    statics: {
        goBack: function(){
            if (location.hash.length != 0){
                var hash = location.hash.substring(1);
	            Ext.getCmp('initialView').setActiveItem(Ext.getCmp(hash));
            } else {
                MyApp.Utilities.addHashToUrl();                                      
            }
        },
        addHashToUrl: function(){
            var id = Ext.getCmp('initialView').getActiveItem().id;
            var loc = location.href;
            var hash = location.hash.substring(1);
            var root = null;

            if (loc.indexOf('#') != -1){
                root = loc.split('#');
                location.href = root[0] + '#' + id;
            } else if (id != hash){
                location.href = loc + '#' + id;
            }
        }
    }
});


Ext.define('MyApp.MyView', {
    extends: 'Ext.panel.Panel',
    requires: ['MyApp.appHistory'],
    initComponent: function() {
        MyApp.appHistory.goBack();
    }
});

Ext.define('MyApp.MyView', {
    extends: 'Ext.panel.Panel',
    requires: ['MyApp.appHistory'],
    initComponent: function() {
        MyApp.appHistory.addHashToUrl();
    }
});

What we’ve done here is add an “appHistory” object to our “MyApp” app (“MyApp” is the default namespace that Architect gives your app) and exposed two methods:

  • MyApp.appHistory.goBack() – this handles the back functionality for the app.
  • MyApp.appHistory.addHashToUrl() – this updates the location hash.

Finally we need to hook into PhoneGap’s “backbutton” event. We do so by adding an event listener within our index.html. You’ll notice the typical “deviceready” event listener wrapped by the document’s “load” listener which ensures that our code runs only when the DOM has been loaded and the device is ready:

window.addEventListener('load',function(){
	document.addEventListener('deviceready',function(e){
		// setup the back button
		document.addEventListener('backbutton', function(e){
			history.back() // go back in the browser's history
			setTimeout(function(){
				MyApp.appHistory.goBack(); // update the view against the current hash
			},100);
			return false;
		}, false);
	});
});

Looking at the above we can see that when the “backbutton” event fires we go back in the browser history then we wait a short bit of time to ensure that the location has been updated before following with the call to navigate back within the app.

The last thing to do is to update the hash from within your Sencha application. I’ve placed the ” MyApp.Utilities.addHashToUrl();” method call within my controller’s onButtonTap event which is sufficient for this example.

This is a good starting point – you’ll of course need to modify per your specific needs, have fun!

Prevent Screen Rotation in PhoneGap / Android

21 Jun 2013

You may have an app at some point that requires a set screen orientation. Using PhoneGap in Android this is done by editing your project’s manifest.xml. This file is located in your project root. Double click the file to open it within Eclipse and note the activity node:

...
 
...

You will add the following to it:

android:screenOrientation=”portrait”

or

android:screenOrientation=”landscape”

Which would look like this:

...
 
...

In PhoneGap 2.8.1 they have added a “preference” to config.xml for screen orientation, but oddly it doesn’t seem to work on the Android 4.1.1 test device I have (a Samsung Galaxy Tab 2).

The tag looks like this:

...

...

Simply add it above the feature tags in config.xml… but as I mentioned, it doesn’t work. Maybe this is forward looking or maybe its broken in PhoneGap 2.8.1, either way the first method continues to work.