Wednesday Mar 04, 2015

Oracle MAF 2.1 Now in Eclipse Too

We are happy to announce the release of a new version of Oracle Enterprise Pack for Eclipse (OEPE)- the Oracle Eclipse tooling offering - with support for the latest Oracle MAF 2.1.

Download the new OEPE 12.1.3.4 with MAF 2.1 Support Here.

This new version of OEPE is based on the latest Eclipse Luna SR2, and adds support for the full set of MAF 2.1 features including support for Java 8 compact profile 2, the new Xcode  and Android SDKs, and Cordova 3 plugin integration.

One unique feature added to the OEPE design time experience is a simplified way to interact with REST/JSON services. REST/JSON services are the preferred way to exchange information between your mobile application and remote server. A new wizard based interface in OEPE allows you to easily test REST URLs and then generate a simple set of POJO Java classes that access those services and working with the data types they use. You can then expose those classes as data controls and simply drag and drop them to the AMX pages to create the mobile UI.

Here is a 5 minutes demo that shows you the new REST features in action:

For more about this new version see the OEPE blog entry.

Thursday Feb 19, 2015

Integrating a custom Cordova plugin into a MAF app

In this earlier post, I demonstrated how to create a simple Cordova plugin for each of Android and iOS.  In this post, I’ll describe how to include that plugin into a MAF 2.1.0 app and how to invoke it from Java, from AMX and from local HTML.

You can follow these same instructions to integrate any 3rd party or custom Cordova plugin into your MAF app.

How do I include a custom Cordova plugin into my MAF app?

To include a custom Cordova plugin into a MAF app, you specify the location of the plugin’s top-level folder (on your local hard drive) in the app’s maf-application.xml > Plugins UI in JDeveloper, as described in the MAF 2.1.0 Documentation.

The path to the plugin will be stored in maf-plugins.xml and will be relative to that file’s location. To avoid any deploy-time issues, make sure the plugin’s top-level folder is on the same drive as your app and that there are no spaces in its path. If your plugin is specific to your MAF app, you probably want to include it within the app’s source tree.

The plugin will appear in the maf-application.xml > Plugins UI as follows:

Note: If you want to use a 3rd party plugin, you must first download it (as a zip file) and extract it to your local hard drive as described in Step 7 of this blog post.

How do I invoke the plugin’s methods?

As described in the earlier post, a Cordova plugin includes a JavaScript interface that defines its available functions. You must write your own JavaScript in your MAF application to call the plugin’s JavaScript interface so your MAF application can interact with the plugin.

In the example “Alert” plugin created in the earlier post, we defined the following JavaScript interface in the alert.js file:

module.exports = {
  alert: function(title, message, buttonLabel, successCallback) {
    cordova.exec(successCallback,
                 null, // No failure callback
                 "Alert",
                 "alert",
                 [title, message, buttonLabel]);
  }
};

Our plugin’s manifest file, plugin.xml, defined the JavaScript module as follows:

  <js-module src="www/alert.js" name="Alert">
    <clobbers
target="Alert" />
  </js-module>

This means that the alert function will be exported as part of the Alert JavaScript module within the consuming MAF application, which enables you to call this function from JavaScript as follows:

  Alert.alert(“My title”, “My message”, “My button label”, myCallbackFunction);

As per the plugin design, this code would cause a native popup dialog to be displayed with “My title” as the title, “My message” as the message and a single button with the label “My button label”. When the user taps the button to dismiss the dialog, the JavaScript callback function myCallbackFunction will be executed with an input parameter of 0.

For more information on using JavaScript callback functions, refer to this helpful blog post by Michael Vollmer.

Note: If you want to use a 3rd party plugin, the JavaScript interface and how to call it should be described in the plugin’s README.md file, typically found in the plugin’s top-level folder.

How do I invoke the plugin from a Local HTML page?

You could invoke the plugin’s JavaScript interface methods directly from your HTML code, but it’s more common to provide a wrapper function that simplifies your code and abstracts you from possible changes to the plugin’s interface.

Let’s take a look at a local HTML page that calls our “Alert” plugin:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport"

          content="width=device-width, initial-scale=1, maximum-scale=1"/>
    <title>Plugin Demo</title>
    <script type="text/javascript">if (!window.adf) window.adf = {};
                                   adf.wwwPath = 
"../../../../www/";</script>
    <script type="text/javascript" src="../../../../www/js/base.js"></script>
    <script type="text/javascript">
      function showAlert(frm) {
        Alert.alert(frm.title.value,
                    frm.message.value,
                    frm.buttonLabel.value,
                    function(button) {
                      console.log("User tapped button:" + button);
                    });
      }
    </script>
  </head>
  <body>
    <form>
      <br>Title: <input type="text" name="title" value="Title">
      <br>Message: <input type="text" name="message" value="Message">
      <br>Button Label: <input type="text" name="buttonLabel" value="Button">
      <br><input type="button" value="Alert" onclick="showAlert(this.form);">
    </form>
  </body>
</html>

The <meta> tag is included here to avoid the user seeing the components on the page increase or decrease in size as she interacts with it.

You must include the two lines of JavaScript that define the window.adf object and include base.js. There is no need to explicitly include the plugin’s JavaScript file here, since at deploy-time it will be injected into base.js.

A simple showAlert function has been defined to wrap the call to Alert.alert, which in turn simplifies the calling code within the HTML form.

The showAlert function is called when the user taps on the “Alert” button. The “title”, “message” and “button label” input text values are read from the form and passed to Alert.alert, along with an anonymous callback function that will be called when the user taps on the dialog’s button. This callback function will be passed a value for the input parameter button, which we know will be 0, since that was hard-coded in our plugin’s native code.

How do I invoke the plugin from an AMX page?

AMX components cannot call JavaScript methods directly, so you must implement a Java method that is called from an AMX component, which in turn executes some JavaScript that calls the plugin’s JavaScript interface.

Let’s take a look at an AMX page that is similar to the local HTML page described above:

<?xml version="1.0" encoding="UTF-8" ?>
<amx:view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:amx="http://xmlns.oracle.com/adf/mf/amx"
          xmlns:dvtm="http://xmlns.oracle.com/adf/mf/amx/dvt">
  <amx:panelPage id="pp1">
    <amx:facet name="header">
      <amx:outputText value="Plugin Demo" id="ot1"/>
    </amx:facet>
    <amx:inputText label="Title" id="it1"
                   value="#{applicationScope.PluginBean.alertTitle}"/>
    <amx:inputText label="Message" id="it2"
                   value="#{applicationScope.PluginBean.alertMessage}"/>
    <amx:inputText label="Button Label" id="it3"
                   value="#{applicationScope.PluginBean.alertButtonLabel}"/>
    <amx:commandButton text="Alert" id="cb1"
                       actionListener="#{PluginBean.popupAlertDialog}"/>
  </amx:panelPage>
</amx:view>

The three inputText components store their values in three attributes of an bean called PluginBean. When the user taps the commandButton component, it calls the popupAlertDialog method of PluginBean.

Let’s take a look at the PluginBean:

package mobile;

import oracle.adfmf.amx.event.ActionEvent;
import oracle.adfmf.framework.api.AdfmfContainerUtilities;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;

public class PluginBean {
  private String alertTitle"Title";
  private String alertMessage"Message";
  private String alertButtonLabel"Button";

  public PluginBean() {
  }

  public void popupAlertDialog(ActionEvent actionEvent) {
    AdfContainerUtilities.invokeContainerJavaScriptFunction(
      AdfmfJavaUtilities.getFeatureId(),
      "showAlert",
      new Object[] {
        alertTitle,
        alertMessage,
        alertButtonLabel
      });
  }

  public void setAlertTitle(String alertTitle) {
    this.alertTitle = alertTitle;
  }

  public String getAlertTitle() {
    return alertTitle;
  }

  public void setAlertMessage(String alertMessage) {
    this.alertMessage = alertMessage;
  }

  public String getAlertMessage() {
    return alertMessage;
  }

  public void setAlertButtonLabel(String alertButtonLabel) {
    this.alertButtonLabel = alertButtonLabel;
  }

  public String getAlertButtonLabel() {
    return alertButtonLabel;
  }
}

The popupAlertDialog method calls AdfmfContainerUtilities.invokeContainerJavaScriptFunction to invoke a JavaScript function called showAlert, passing the alertTitle, alertMessage and alertButtonLabel attributes as input parameters to the JavaScript function.

You may wonder why the plugin’s alert JavaScript method is not invoked directly and we call the showAlert function instead. The reason is that the plugin’s alert method requires a JavaScript function callback to be passed as an input parameter and there is no way to do this from Java. Passing a null value may have unwanted side effects, so that is not recommended.

For this reason, we need to write a JavaScript function that wraps the call to the plugin’s alert method. There are two options for this.

One option is to create a JavaScript file and include it into each feature that wishes to invoke the plugin via the app’s maf-feature.xml UI as follows:


The JavaScript file would look similar to the following:

showAlert = function(title, message, buttonLabel) {
  Alert.alert(title,
              message,
              buttonLabel,
              function(button) {
                console.log("User tapped button: " + button);
              });
};

This JavaScript file defines a global function variable called showAlert, which accepts 3 input parameters and calls the plugin’s alert method with those 3 parameters, along with an anonymous callback function that will be executed when the user taps on the dialog’s button. The native code will pass a return value of 0 to the anonymous callback function as the input parameter button.

The other option, if the plugin is to be invoked from a single AMX page, is to include the wrapper function as verbatim JavaScript within the AMX page, similar to the following:

<?xml version="1.0" encoding="UTF-8" ?>
<amx:view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:amx="http://xmlns.oracle.com/adf/mf/amx"
          xmlns:dvtm="http://xmlns.oracle.com/adf/mf/amx/dvt">
  <amx:panelPage id="pp1">
    <amx:verbatim id="v1">
      <![CDATA[
        <script type="text/javascript">
          function showAlert(title, message, buttonLabel) {
            Alert.alert(title,
                        message,
                        buttonLabel,
                        function(button) {
                          console.log("User tapped button: " + button);
                        });
          }
        </script>
      ]]>
    </amx:verbatim>
    <amx:facet name="header">
      <amx:outputText value="Plugin Demo" id="ot1"/>
    </amx:facet>
    <amx:inputText label="Title" id="it1"
                   value="#{applicationScope.PluginBean.alertTitle}"/>
    <amx:inputText label="Message" id="it2"
                   value="#{applicationScope.PluginBean.alertMessage}"/>
    <amx:inputText label="Button Label" id="it3"
                   value="#{applicationScope.PluginBean.alertButtonLabel}"/>
    <amx:commandButton text="Alert" id="cb1"
                       actionListener="#{PluginBean.popupAlertDialog}"/>
  </amx:panelPage>
</amx:view>

In either case, there is no need to include the plugin’s JavaScript file in the calling feature(s), since at deploy-time it will be injected into base.js.

Conclusion

You now have the knowledge required to create your own custom Cordova plugin and integrate it into your MAF 2.1.0 app, invoking it from local HTML, an AMX page, or from Java code.

Once you’ve tested your code successfully, you might consider publishing the plugin to make it available to the greater Cordova community. This can be achieved by calling plugman as follows:

$ plugman publish path-to-plugin-top-level-folder

Thursday Feb 12, 2015

Introduction to custom Cordova plugin development

Oracle Mobile Application Framework (MAF) v2.1.0 uses Cordova version 3.6.3 on Android and 3.7.0 on iOS to provide access to native device functionality.  The MAF 2.1.0 extension to JDeveloper 12.1.3 enables you to easily include any of the hundreds of published 3rd party Cordova plugins into your MAF app.

But what if you can’t find a suitable 3rd party plugin? You could elect to write your own, which, depending on the functionality required, may not be as difficult as you think.

In this post I’ll provide an introduction to developing a Cordova plugin by creating a very simple plugin for each of Android and iOS.

How does a Cordova plugin work?

In a nutshell, Cordova provides a bridge between JavaScript and native code, enabling you to write native code that gets exposed to your app via a common JavaScript interface.

Each method exposed by a plugin’s JavaScript interface is mapped to a method in the plugin’s native code via the Cordova bridge, which also enables you to pass parameters back and forth between the JavaScript and native methods.

What comprises a Cordova plugin?

A Cordova plugin typically consists of:

  • Native code for each supported platform
  • A common JavaScript interface
  • A manifest file called plugin.xml

The conventional structure for a Cordova plugin supporting both Android and iOS is:

  - Plugin top-level folder
     - plugin.xml
     - src/
        - android/
           - <Java source code>
        - ios/
           - <Objective-C source code>
     - www/
        - <JavaScript interface>

Ideally, community-published plugins also include release notes, author and license information, and a README file.  

A plugin may also include additional native resources and these are identified in the plugin.xml manifest file. This manifest file is read by the plugman command-line tool, which is used by the Cordova command-line interface and also by the MAF extension for JDeveloper.

In some rare cases, a plugin may be created that simply executes some native code on initialization and requires no JavaScript interface.

For more detailed information about the plugin.xml manifest file, refer to the Cordova Plugin Specification.

How do I create my own custom Cordova plugin?

To create your own custom Cordova plugin, you must write:

  • JavaScript that provides the interface for calling your plugin from within a Cordova-based app, such as a MAF app.
  • Native code that provides the functionality you need.  Since MAF supports both Android and iOS, you should write native code for both platforms.
  • A plugin.xml manifest file that defines your plugin and how plugman should incorporate it into a MAF app (or any Cordova-based app).

What tools do I need to create my own custom Cordova plugin?

You really only need a text editor to create your own custom Cordova plugin, which is all I’ve used to create the custom plugin described in this post.

For more complex plugins, you may wish to develop and test the plugin’s native code in each platform’s native IDE, which means downloading and installing the Android Studio and/or Apple’s Xcode.

You don’t need Cordova installed to develop a Cordova plugin.  Once you have developed your Cordova plugin, you can incorporate it directly into your MAF app for testing. However, if you wish to test your plugin within a Cordova app, you must download and install Cordova using the Cordova Command-Line Interface.

How do I write the plugin’s JavaScript interface?

We start with the JavaScript interface since it provides a common interface to both the Android and iOS native code.  This interface effectively defines what is required in the native code.

The JavaScript interface must call the cordova.exec method to invoke a native plugin method, as follows: 

cordova.exec(successCallback, failureCallback, service, action, [args]);

This call invokes the action method on the service class on the native side, passing the arguments in the optional args array.  If the native code completes successfully, the successCallback function is executed, along with any return parameters.  If the native code fails, the failureCallback function is executed, with an optional error parameter.  For more information on JavaScript callback functions, refer to this helpful blog post by Michael Vollmer.

Let’s create a very simple plugin that displays a native popup dialog.  Thus plugin shall present one method that takes 3 parameters – title, message and button label – and shall return the result in the ‘success’ callback. No ‘failure’ callback will be implemented. The service class shall be named “Alert” and we shall call the sole method “alert”. 

The following JavaScript defines the interface:

module.exports = {
  alert: function(title, message, buttonLabel, successCallback) {
    cordova.exec(successCallback,
                 null, // No failure callback
                 "Alert",
                 "alert",
                 [title, message, buttonLabel]);
  }
};

The call to module.exports exports the JavaScript function alert as part of the JavaScript module that will be defined in the plugin manifest file, plugin.xml

Your app will call this alert JavaScript function, which will invoke the alert method on the Alert class in the plugin’s native code.

Save this JavaScript into a file called alert.js, within a www subfolder of your plugin’s top-level folder.

How do I write the plugin’s native code?

Android

Based on the JavaScript interface, we must define a class called Alert in a Java source file called Alert.java.  Let’s take a look at the Alert.java source file:

package com.acme.plugin.alert;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class Alert extends CordovaPlugin {
  protected void pluginInitialize() {
  }

  public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
      throws JSONException {
    if (action.equals("alert")) {
      alert(args.getString(
0), args.getString(1), args.getString(2), callbackContext);
      return true;
    }
    return false;
  }

  private synchronized void alert(final String title,
                                  final String message,
                                  final String buttonLabel,
                                  final CallbackContext callbackContext) {
    new AlertDialog.Builder(cordova.getActivity())
    .setTitle(title)
    .setMessage(message)
    .setCancelable(
false)
    .setNeutralButton(buttonLabel,
new AlertDialog.OnClickListener() {
      public void onClick(DialogInterface dialogInterface, int which) {
        dialogInterface.dismiss();
        callbackContext.sendPluginResult(
new PluginResult(PluginResult.Status.OK, 0));
      }
    })
    .create()
    .show();
  }
}

The Alert class should be part of a package that will be referenced in the manifest file, plugin.xml.

The Alert class must extend the CordovaPlugin class, the definition of which you can find here.

The Alert class must override the execute method, since this will be called each time the JavaScript cordova.exec method is called, providing the name of the plugin method, the input parameters and a callback context.  The execute method should return true if a valid action was passed in, otherwise false.

Once the code has completed, it should return a result and optional return parameters to the calling JavaScript by invoking the sendPluginResult method on the callbackContext object.   Returning a result of PluginResult.Status.OK will cause the JavaScript ‘success’ callback to be executed.  Any other result (apart from PluginResult.Status.NO_RESULT) will cause the JavaScript ‘failure’ callback to be executed.

In our plugin, a ‘success’ result is returned when the user taps the button on the popup dialog and a value of 0 is returned.

The Alert class may override the pluginInitialize method if any initialization logic is required when the plugin is first constructed.

Save this code into a file called Alert.java, within a src/android subfolder of your plugin’s top-level folder.

For more detailed information on aspects such a threading and event handling, refer to the Cordova page Android Plugins.

iOS

For our example, we must define a class called Alert in an Objective-C source file called Alert.m and corresponding header file Alert.h

Let’s take a look at the Alert.h header file:

#import <Cordova/CDV.h>

@interface Alert : CDVPlugin <UIAlertViewDelegate> {}
- (void)alert:(CDVInvokedUrlCommand*)command;
@end

@interface
MyAlertView : UIAlertView {}
@property (nonatomic, copy) NSString* callbackId;
@end

The Alert class must be a sub-class of CDVPlugin, the definition of which you can find here.

The Alert class must provide an alert method, since this will be called each time the plugin’s JavaScript alert method executes the cordova.exec method.

Save this code into a file called Alert.h, within a src/ios subfolder of your plugin’s top-level folder.

Let’s take a look at the Alert.m source file:

#import "Alert.h"

@implementation Alert
- (void)pluginInitialize
{
}

- (void)alert:(CDVInvokedUrlCommand*)command
{
  NSString* callbackId = command.callbackId;
  NSString* title = [command argumentAtIndex:
0];
  NSString* message = [command argumentAtIndex:
1];
  NSString* button = [command argumentAtIndex:
2];

  MyAlertView *alert = [[MyAlertView alloc]
                        initWithTitle:title
                        message:message
                        delegate:
self
                        cancelButtonTitle:button
                        otherButtonTitles:
nil];
                        alert.callbackId = callbackId;
  [alert show];
}

- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
  MyAlertView* myAlertView = (MyAlertView*)alertView;
  CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                             messageAsInt:
0];
  [
self.commandDelegate sendPluginResult:result callbackId:myAlertView.callbackId];
}
@end

@implementation
MyAlertView
@synthesize callbackId;
@end

The alert method receives the input parameters and a callback id.

Once the code has completed, it should return a result and optional return parameters to the calling JavaScript by invoking the sendPluginResult method on the commandDelegate object. Returning a result of CDVCommandStatus_OK will cause the JavaScript ‘success’ callback to be executed. Any other result will cause the JavaScript ‘failure’ callback to be executed.

In our plugin, a ‘success’ result is returned when the user taps the button on the popup dialog and a value of 0 is returned.

The Alert class may implement the pluginInitialize method if any initialization logic is required when the plugin is first constructed.

Save this code into a file called Alert.m, within a src/ios subfolder of your plugin’s top-level folder.

For more detailed information on aspects such a threading and event handling, refer to the Cordova page iOS Plugins.

How do I write the plugin’s manifest file (plugin.xml)?

The manifest file, called plugin.xml, is an XML document that defines the plugin and tells plugman how to incorporate the plugin into your MAF app (or any Cordova-based app) for each platform it supports.

The Cordova Plugin Specification is comprehensive, but we will focus on the manifest file used for our “Alert” plugin:

<?xml version="1.0" encoding="UTF-8"?>
<plugin 
xmlns="http://apache.org/cordova/ns/plugins/1.0"
        id="com.acme.plugin.alert"
        version="0.0.1">

  <name>
Alert</name>
  <description>
A Cordova plugin that displays an alert popup dialog</description>

  <engines>
    <engine
name="cordova" version=">=3.6.0" />
  </engines>

  <js-module
src="www/alert.js" name="Alert">
    <clobbers
target="Alert" />
  </js-module>

  <!-- android -->
  <platform name="android">
    <config-file
target="res/xml/config.xml"
parent="/*">
      <feature name="Alert"/>
        <param name="android-package" value="com.acme.plugin.alert.Alert" />
      </feature>
    </config-file>
    <source-file src="src/android/Alert.java" target-dir="src/com/acme/plugin/alert" />
  </platform>

  <!-- ios -->
  <platform name="ios">
    <config-file target="config.xml" parent="/*">
      <feature name="Alert"/>
        <param name="ios-package" value="Alert" />
      </feature>
    </config-file>
    <header-file src="src/ios/Alert.h" />
    <source-file src="src/ios/Alert.m" />
  </platform>

</plugin>

The plugin element must contain the plugin’s XML namespace (xmlns), id and version.

The name and description elements should always be defined.  If you intend to publish your plugin for public use, you should include additional elements such as those identifying the author, license, keywords and repository.

The child elements of the engines element define which version(s) of the Cordova framework the plugin supports.  Since this plugin has been developed based on Cordova 3.6.0 documentation and will be tested within a MAF 2.1.0 app, we should set the minimum required Cordova version to 3.6.0.

The JavaScript interface is defined by including a js-module tag for each JavaScript file.  Any file defined here is automatically copied into your MAF app and injected into any HTML using a <script> tag so that you don’t have to specifically add this tag yourself, or include the JavaScript as content in your AMX features.  The clobbers tag indicates that the module shall be inserted into the window object as Alert, so your MAF app code should call the JavaScript method Alert.alert to execute the plugin’s alert method.

If your plugin has a dependency on another Cordova plugin, you can define this using a dependency tag.  Since our plugin does not have any dependencies, there is no such tag defined.

The platform tag is used to define the platforms that are supported by the plugin.  Within each platform tag, you specify the native source files, changes required to configuration files, any additional native resources or frameworks and any platform-specific JavaScript files.

For Android, it is important to specify the full package name of the plugin as the value for the android-package parameter, for example “com.acme.plugin.alert.Alert”, and to specify the target-dir for any source files (since this indicates the location to which the source file should be copied and it must match the package name), for example “src/com/acme/plugin/alert”.

Save this XML into a file called plugin.xml, within your plugin’s top-level folder.

Conclusion

We have now developed a custom Cordova plugin that can be incorporated into a MAF 2.1.0 app, or any app based on Cordova 3.6.0 or above.  In a follow-up post [Edit: here], I’ll describe how to integrate this plugin into a MAF app.

For developers looking for more detailed information about how to create a Cordova plugin, refer to the Cordova Plugin Development Guide, which contains specific guides for each native platform.

Wednesday Feb 04, 2015

Migrating MAF apps with 3rd party Cordova plugins

Cordova is used in Oracle Mobile Application Framework (MAF) to provide access to device features.   MAF 2.1.0 uses Cordova version 3.6.3 on Android and 3.7.0 on iOS, dramatically increasing the number of available plugins that developers can leverage.

MAF 2.1.0 greatly simplifies the process of adding 3rd party Cordova plugins into a MAF app by internally using the plugman command-line interface to build the plugin and incorporate all the required artifacts into your MAF app.

So how do you migrate an existing MAF app that uses a 3rd party Cordova plugin to MAF 2.1.0?

The following steps and screenshots show the process of migrating the BarcodeDemo sample app from MAF 2.0.1 to MAF 2.1.0 using JDeveloper.

Step 1 – Download JDK 8 and update MAF extension

MAF 2.1.0 requires JDK 8. Download JDK 8 before updating the MAF extension to 2.1.0 via Check for Updates in JDeveloper. Following a restart, you will be prompted to enter the JDK 8 location on your local machine and to reconfigure the Android and iOS Platform Preferences in JDeveloper. Please refer to the Installation Guide for more detailed information.

Step 2 – Automatic app migration

Open your MAF app within JDeveloper and you will be prompted to allow JDeveloper to automatically migrate your app. The Installation Guide describes this process in more detail. 



Step 3 – Remove the old plugin code

In a later step, you will point JDeveloper to the location of the plugin’s source code on your local machine and JDeveloper will use plugman to build the plugin and incorporate it into your MAF app.

Before doing that, you should remove the plugin artifacts that you had manually added to your MAF app previously.  This includes:

  • Android native code found in Projects > ApplicationController > Application Sources > plugins.BarcodeScanner.Android
  • iOS native code found in Projects > ApplicationController > ApplicationSources > plugins.BarcodeScanner.iOS
  • JavaScript files found in Projects > ViewController > Web Content > plugins



Step 4 – Remove unnecessary iOS app icons and launch images

This is an optional step to reduce the size of your app. You can remove the following iOS app icons and launch images for unsupported devices and operating system versions, found in Application Resources > Resources > ios:

  • Default-1135h@2x.png
  • Default-Land.png
  • Default-Landscape-Ipad.png
  • Default-Landscape.png
  • Default-Landscape@2x.png
  • Default-Landscape@2x~Ipad.png
  • Default-Portrait-Ipad.png
  • Default-Portrait.png
  • Default-Portrait @2x.png
  • Default-Portrait @2x~Ipad.png
  • Default.png
  • Default@2x-Landscape.png
  • Icon-50.png
  • Icon-50@2x.png
  • Icon-57.png
  • Icon-57@2x.png
  • Icon-72@2x.png
  • Icon-80.png
  • Icon-144.png
  • icon-72.png
  • icon.png
  • icon@2x.png


Step 5 – Remove old plugin details from the Plugins UI

To complete the removal of the old plugin, you should remove the references to it from within the maf-application.xml Plugins UI, by selecting each reference and clicking the red ‘x’ icon.


Step 6 – Save all, Clean all

At this point, save all modifications and then do a ‘clean all’.

Step 7 – Download a new version of the plugin

MAF 2.1.0 requires you to have the plugin source code residing on your build machine, located on the same drive as your app source code, in a path that contains no spaces.

It is likely that there is a later version of the plugin that you have used previously which is compatible with the Cordova versions used by MAF.  You may even find that more recently someone has written a plugin that provides a better match to your requirements.

Anyone can build a Cordova plugin and they can choose to keep it to themselves or to publish it for use by others. The most common way to publish a Cordova plugin is to store it in a Git repository and to register it with the Cordova plugin registry.  Launch your browser and open http://plugins.cordova.io.


To find a barcode scanner plugin, type in “barcode” and search.


Click on com.phonegap.plugins.barcodescanner to view the details of this plugin.


You can see that this plugin requires Cordova version 3.0.0 or greater, works on Android and iOS, and was last updated 3 months ago to version 2.0.1. This page also provides a description and API documentation.

To access this plugin, click on the link to its Git repository.


To download this plugin, click on the link to Download Zip.

Once the plugin has been downloaded, extract the zip file contents into a location relative to your app’s source code which does not contain spaces. For example, you wish to extract the plugin into your app’s src folder as follows:


Step 8 – Add the plugin via the Plugins UI

To import the downloaded version of the plugin into your MAF app, return to the maf-application.xml Plugin UI in JDeveloper and click the green ‘+’ icon. Navigate to the location of the plugin’s top-level folder and click the Select button.


The details of the plugin, which are read from the plugin.xml file, will be displayed in the Plugins UI.


Step 9 – Update the JS that calls the plugin API

In most cases, you will need to update the JavaScript that calls the plugin API. Firstly, you no longer need to include the plugin’s JavaScript file because plugman will include this into your application at deploy-time. Secondly, the manner in which you invoke the plugin’s JS API may have changed.

For the BarcodeDemo sample app, this means editing the scanner.amx file to remove the inclusion of barcodescanner.js and to change window.plugins.barcodeScanner.scan to cordova.plugins.barcodeScanner.scan as described in the plugin’s README.md file.


Step 10 – Save all, deploy and test

All that’s left now is to save all modifications, deploy your app (most likely to a device, since many plugins won’t work on a simulator or emulator) and test it.

A tip for anyone using plugins with dependencies

If a 3rd party Cordova plugin has a dependency on another plugin, this will be defined in the plugin.xml file. At deploy-time, JDeveloper calls plugman to build and incorporate the 3rd party plugins defined in the maf-application.xml Plugins UI. If one of these plugins has a dependency, plugman will automatically attempt to download the required plugin's source code so it can be built and incorporated into your MAF app.

If your build machine is behind a firewall, this attempted download may cause the JDeveloper deployment to hang for a while before reporting error messages similar to the following:

[10:21:35 AM] Fetching plugin "https://github.com/apache/cordova-plugin-device" via git clone

[10:21:35 AM] Deployment Successful

[10:21:35 AM] Failed to install 'de.appplant.cordova.plugin.local-notification':Error: Command failed: Cloning into '/var/folders/h9/84x8qcsj391c355v3v137n580000gn/T/plugman/git/1423102819927'...

[10:21:35 AM] fatal: unable to access 'https://github.com/apache/cordova-plugin-device/': Failed to connect to github.com port 443: Operation timed out

[10:21:35 AM] at ChildProcess.exithandler (child_process.js:648:15)

[10:21:35 AM] at ChildProcess.emit (events.js:98:17)

[10:21:35 AM] at maybeClose (child_process.js:756:16)

[10:21:35 AM] at Socket.<anonymous> (child_process.js:969:11)

[10:21:35 AM] at Socket.emit (events.js:95:17)

[10:21:35 AM] at Pipe.close (net.js:465:12)

[10:21:35 AM] Command failed: Cloning into '/var/folders/h9/84x8qcsj391c355v3v137n580000gn/T/plugman/git/1423102819927'...

[10:21:35 AM] fatal: unable to access 'https://github.com/apache/cordova-plugin-device/': Failed to connect to github.com port 443: Operation timed out

The solution for this is:

  • Download and extract the required plugin as per Step 7 above.
  • Remove the dependent plugin from the Plugins UI.
  • Add the required plugin to the Plugins UI.
  • Add the dependent plugin to the Plugins UI. 

This will ensure that each plugin is built and incorporated into your MAF app in the correct order.

Monday Jan 26, 2015

Announcing Oracle Mobile Application Framework 2.1 - Now Available

The Oracle Mobile Team is happy to announce the release of Oracle Mobile Application Framework 2.1 - a major update to Oracle's mobile development framework.

This new version focuses on upgrading the framework's infrastructure and includes the following new features:

  • Support for Java 8 - Java is the language used for business logic development on Oracle MAF, in fact Oracle MAF is the only solution out there that will run the same Java code on both iOS and Android.  Now developers can leverage the latest features of the Java language - such as Lambda expressions, Collections with Generics and more - while running on a 64bit JVM that supports the Java 8 Compact2 profile.
  • Cordova 3 support - Cordova is used in Oracle MAF to provide access to device features. Oracle MAF 2.1 updates the Cordova version to 3.6.3 on Android and 3.7 for iOS, dramatically increasing the number of available plugins that developers can leverage.
  • Simpler Cordova Plugin integration - Oracle MAF leverages the plugman command line to build and incorporate plugins into Oracle MAF apps.
  • Xcode 6 and Android 5 support - use the latest SDKs to compile and deploy your MAF applications across multiple devices.

You can get Oracle MAF 2.1 by downloading the new Oracle MAF extension through the JDeveloper Help->Check for Updates functionality.

We highly recommend that you read the installation guide and migration guide before you start your upgrade process. The setup might be a bit tricky because you'll need JDK7 to run JDeveloper but JDK8 to use the extension - so follow the instructions carefully. 

Have questions? - join us on the Oracle MAF discussion forum on OTN

Friday Dec 12, 2014

Interview with Northumbrian Water

Earlier in the year Grant Ronald, from the Oracle Mobile Product Management team, went up to Durham in the UK to interview James Robbins the CIO of Northumbrian Water on their mobile strategy and their use of Oracle's mobile framework. This video is a nice insight into a key utilities company's mobile strategy and how Oracle technology supported them.
About

This blog is is dedicated to announcements,tips and tricks and other items related to developing, integrating, securing, and managing mobile applications using Oracle's Mobile Platform. It is created and maintained by the Oracle Mobile product development team.

Archive of past entries

Even More Mobile Development Blogs

Oracle A-Team Site - Mobile Related Entries

Code samples from the Community

Fusion Middleware Blogs

Search

Categories
Archives
« March 2015
SunMonTueWedThuFriSat
1
2
3
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    
       
Today