Two-Minute Tutorial 3 Part 2

TMT3 Part 2 Add ChildBrowser Plugin and Extend TMT3 to Handle Barcode Scanner Results

TMT3 Part 2 can be used as a stand-alone tutorial to add the PhoneGap ChildBrowser Plugin to an AppLaud project, or to extend the functionality of TMT3 Part 1: Add PhoneGap Barcode Scanner Plugin. Examples of barcode scan handling are shown, making use of the child browser methods. Depending on the value scanned and the purpose of the app, the child browser is needed for:

  • Url – open in child browser
  • Product Barcode Look Up – examples include:
    • look up product on server using Child Browser Plugin and queries/replies
    • PhoneGap Whitelist for server-side PhoneGap app
    • ChildBrowser onLocationChange() callback

Section 1 of this tutorial can be used to add the child browser plugin to any AppLaud project, regardless of the use of any other plugins (see Getting Started if new to AppLaud).
Prep

  • Complete / Verify TMT3 Part 1 – If using tutorial for Barcode Scanner App
  • Download attached source – tmt3p2.js – If using tutorial for Barcode Scanner App
  • New to PhoneGap Plugins? View the new MDS Video: How to Install ChildBrowser Plugin
  • Download the corresponding version of PhoneGap Plugins from github:
    • PhoneGap 1.4.1 and lower:
      • PhoneGap Plugin
    • PhoneGap / Cordova 1.5.0 – 1.8.1:
      • PhoneGap Plugin  (Android/ChildBrowser/1.8.1)
    • PhoneGap / Cordova 1.9.0: Not Supported
    • PhoneGap / Cordova 2.0+ (e.g. your downloaded version):
      • PhoneGap Plugin (Android/ChildBrowser/2.0.0)
  • Locate Android/ChildBrowser directory
  • Review methods and examples in its README.md

Section 1: Add the ChildBrowser Plugin to a Project

Using multiple PhoneGap Plugins in a single app poses no problems, as long as there is no java package name space conflict. Adding the ChildBrowser Plugin to TMT3 introduces no conflicts with the Barcode Scanner Plugin. The instructions below are essentially the same as the plugin README.md, with changes specific to AppLaud projects.

1. Create New Java Package for the ChildBrowser Plugin

Right click on the project’s /src directory and select New -> Package. Enter the new package name: com.phonegap.plugins.childBrowser as shown below:

Select Finish. The new package will appear as below.

2. Add the ChildBrowser Java CodeRight click on the new package, com.phonegap.plugins.childBrowser, in the Package Explorer and select Import…  Browse your local file system (or wherever the PhoneGap Plugin zipfile was unzipped) and locate the directory: Android/ChildBrowser/src/com/phonegap/plugins/childBrowser. Select only the file ChildBrowser.java to import, as shown below, and click Finish.

3. Add the ChildBrowser JavaScript and childbrowser Folder to the Project

Right click on the project’s /assets/www directory and select Import…  Browse your local file system to locate the directory Android/ChildBrowser/www.  Select childbrowser.js and import.
Import the directory (including contents) Android/ChildBrowser/www/childbrowser into /assets/www similarly.
The project files should look exactly as shown above, with the folder childbrowser/ and the file childbrowser.js in /assets/www.
4. Include the Child Browser JavaScript in the projectEdit assets/www/index.html to include childbrowser.js. The new line is in bold below, showing the correct order of the scripts. At a minimum childbrowser.js must be included after the phonegap javascript file.

<script type=”text/javascript” charset=”utf-8″ src=”phonegap-1.3.0.js”></script>
<script type=”text/javascript” charset=”utf-8″ src=”barcodescanner.js”></script>
<script type=”text/javascript” charset=”utf-8″ src=”childbrowser.js”></script>
<script type=”text/javascript” charset=”utf-8″ src=”main.js”></script>

5. Edit the Project’s AndroidManifest.xml file

Add the following activity (4 lines) to the project’s /AndroidManifest.xml file inside the application section.

<activity android:name=”com.phonegap.plugins.childBrowser.ChildBrowser” android:label=”@string/app_name”>
<intent-filter>
</intent-filter>
</activity>
</application>
Important: The end tag </application>  is shown above to clarify placement in the AndroidManifest.xml file: the activity must be included before the closing tag.
6. Edit the Project’s plugins.xml fileAdd the following line to the project’s /res/xml/plugins.xml file inside the plugins section.

<plugin name=”ChildBrowser” value=”com.phonegap.plugins.childBrowser.ChildBrowser”/>
</plugins>
Important: The end tag </plugins>  is shown above to clarify placement in the plugins.xml file: the plugin line must be included before the closing tag.
The ChildBrowser Plugin is now ready to use!
Sanity Test: add the following to index.html before the closing </head> tag:
<script type=”text/javascript” charset=”utf-8″>
document.addEventListener(“deviceready”, onDeviceReady, false);
function onDeviceReady() {
window.plugins.childBrowser.openExternal(“http://www.google.com”);
}
</script>
This will open a child browser upon deviceready event. You should see the app menu briefly, then a browser window opening the location. Hit the back button to close the child browser window and return to the app. Remove from your app after verifying.
Section 2: Replace the existing success handler for the Scan functionThe following sections give examples of handling the barcode scan() function in a manner closer to a real app. The encode functionality is not changed.

The format of the barcode scan() function is:
window.plugins.barcodeScanner.scan(successCallback, errorCallBack);

The example app code from Part 1 defines an inlined success function: an alert() shows the result values. To make the code more readable, first add a separate scanSuccess function and change the existing scan() code to be as follows:

var scanSuccess = function(result) {
    // new code will go here
}

var scanCode = function() {

    window.plugins.barcodeScanner.scan(
        scanSuccess,
        function(error) {
            alert(“Scan failed: ” + error);
        });
}

All the code discussed in this tutorial will be added to the scanSuccess function, that is, using the information in fields of the result parameter passed to it in the case of a successful scan. The scan errorCallback is left as is.

The complete javascript source for this tutorial is in tmt3p2.js (attachment). The file tmt3p2.js can replace the file main.js from TMT3 Part 1, or its contents can replace the contents of main.js.

The first two lines of the new function define the supported formats (discussed later) :

var textFormats = “QR_CODE DATA_MATRIX”;
var productFormats = “UPC_E UPC_A EAN_8 EAN_13”;

As we only care about the result when it is not cancelled, return immediately if cancelled:

if (result.cancelled) { return; }

Section 3: Implement a Handler for QR_CODE or DATA_MATRIX Format: Url

Of all the formats supported by the barcode scanner, QR_CODE and DATA_MATRIX will most likely be user-defined (as opposed to 1D, point-of-sale product codes discussed in the next section). As shown previously, textFormats defines these in a string, so use the JavaScript .match() method to easily find these formats by testing the result format provided in result.format.

    if (textFormats.match(result.format)) {
        var scanVal = result.text;
        if (scanVal.indexOf(“http”) === 0) {
            navigator.notification.confirm(
                    ‘(1) Open in Browser\n(2) Cancel’,
                    function (b) {
                        if (b === 1) {
                            window.plugins.childBrowser.openExternal(scanVal);
                        }
                    },
                    result.text,
                    ‘1, 2’
            );
        } else {
            navigator.notification.alert(
                    result.text,
                    function (){},
                    ‘Scan Value:’,
                    ‘Done’
                );
        }
    }
The result.text (value of the scan) is stored in scanVal. Next test if scanVal starts with “http”. This will catch both “http://” and “https://”, then offer the user a confirm message to either open the url in a child browser or cancel.
The final else case displays all other scan values in an alert. Implement support for values other than “http” here, for example if (scanVal.indexOf(“@” > 0)) to test for email address.

Section 4: Implement a Handler for UPC or EAN Format: Product Codes

Note: the two examples in this section discuss possible solutions to product barcode scan processing. Currently I do not have access to a server (i.e. a free one) to provide real examples.

From the wiki UPC page: “Along with the related EAN barcode, the UPC is the only barcode allowed for scanning trade items at the point of sale, per GS1 standards.”

The last block of code uses productFormats to test for the 2 UPC and 2 EAN formats currently supported by the barcode scanner plugin. If the user chooses to look up the product, the results.text (the UPC or EAN barcode value) will be used to build a url with query, searchUrl, then use the child browser method showWebPage() to open it. The server page will open in a child browser window which open “on top” of the app.

  } else if (productFormats.match(result.format)) {
      navigator.notification.confirm(
          ‘(1) Look Up Product\n(2) Cancel’,
          function (b) {
              if (b === 1) {
              // This is an example url with query – substitute your own here
                  var searchUrl = “http://example.com/urserver/search.pl?q=” + result.text;
                  window.plugins.childBrowser.showWebPage(searchUrl);
              }
          },
          result.text,
          ‘1, 2’
  );
} else { alert(“Scan format : ” + result.format +
              ” not supported. Scan value: ” + result.text);
}
The rest of the tutorial will explain by example code snippets. The code above will run, however the showWebPage call will direct you to a domain name reseller since example.com is not a real server and the query string is not real either.  A real app would define its server in searchUrl and construct the query string per server API.

Example 1: Server Continues PhoneGap App: Add Server to PhoneGap Whitelist

One way to continue handling the product look up is to have the server respond to the request by processing the product code (e.g. find merchant with lowest price) and sending a new html page as a response. This new html page will be loaded in the same child browser opened by showWebPage. The new page from the server can then use PhoneGap APIs (i.e. be a PhoneGap app) only if it comes from a server that has been whitelisted.

To whitelist a server, create (or edit) the file /res/xml/phonegap.xml. The contents should be like:

<?xml version=”1.0″ encoding=”utf-8″?>
<phonegap>
    <access origin=”http://127.0.0.1*”/>
    <access origin=”http://example.com*”/>
    <log level=”DEBUG”/>
</phonegap>

Substitute your server domain for example.com and add a “*” immediately after it. In this manner, the app indicates it trusts pages from the server, and they are allowed to use PhoneGap APIs.

After interacting with the user regarding the product, the app might direct the user to hit the back button in order to close the window and return to the app.

Example 2: Use Child Browser onLocationChange() to Handle Server Response

Another example of handling a server response is to set up the server to respond to requests with a reply similar to:

http://example.com/urserver/response?storename=foo&zip=96721&price=129.99

This example shows the server responding with a store name (foo), zip code (96721)  and price (129.99) for the product in the response query string. To capture this data (storename, zip, price) and use back in the app (not in server-delivered child browser page like Example 1), define a child browser onLocationChange callback similar to:

window.plugins.childBrowser.onLocationChange = function(loc){
var serverUrl = ‘http://example.com/urserver’;
if (loc.indexOf(serverUrl + ‘/response?storename’) === 0) {
window.plugins.childBrowser.close();
// Peel storename, zip, and price values off here here and use…
} else if (loc.indexOf(serverUrl + ‘/response?notfound’) === 0) {
window.plugins.childBrowser.close();
// Handle fail case…
}

In this example, we know the server will reply with either storename or notfound in the query string, so we simple test the loc string (new location) for either of these and proceed accordingly. Note that in both cases we immediately call the child browser close() method, returning the user to the app. This is safe to do here because we already have the data we need in the loc, and no longer need the child browser window.

This method of using onLocationChange is demonstrated with full source examples in

  • TMT5P1 Twitter: jsOAuth and ChildBrowser Plugin for Non-PIN Access
  • AppLaud App – The AppLaud Cloud companion app and demo app
    • Uses Open ID Authenication and PhoneGap-enabled HTML pages
    • Source on github
    • Free app on the Android Market

Looking for an app template that scans and does a whole lot more?

June 2012: PowerApp is a demo app that pulls several technologies into one app.
Visit the PowerApp Page for links to source code, demo video and details.