iOS hybrid applications that use IBM Worklight

Hybrid application starter stores are accessed as an app directly installed on mobile devices. IBM Worklight is a mobile application platform that you can use to develop cross-platform hybrid applications for smartphone and tablet starter stores by using HTML, CSS, and JavaScript. Worklight provides an application programming interface (API) that enables users to create native User Interface (UI) elements and access native device functionality by using JavaScript, in addition to extending the hybrid shell application natively.

With Responsive web Design (RWD) and Commerce Composer tools, users can create pages and build layouts directly in Management Center that is supported by mobile devices that include the hybrid applications by default.

The iOS hybrid applications that use IBM Worklight deliver a native experience by wrapping the mobile web storefront with a native shell. The native shell elements are coded with the Apple iOS Software Development Kit (SDK), while the storefront is accessed by using the mobile web interface.

Hybrid iOS applications deliver design aspects and usability elements that function similar to a fully native iOS application.

To work with IBM Worklight, you must have licenses for one of the following products and versions:
  • IBM Worklight Consumer Edition Version 6.0.0
  • IBM Worklight Enterprise Edition Version 6.0.0
  • IBM Worklight Developer Edition Version 6.0.0

    IBM Worklight Developer Edition is a plug-in for the Eclipse IDE that includes the development tool and a built-in application server to test mobile applications. You do not need to install or configure a database or application server. The Developer Edition is free for evaluation purposes, and is not intended to be used in production environments. You can download Worklight Developer Edition from the IBM Worklight website.

For more information, see IBM Worklight Version 6.0.0 documentation.

Topic overview

This topic contains several sections of interest that is related to iOS hybrid applications for WebSphere Commerce that use IBM Worklight.

Environment setup

The following tasks must be performed to set up your application development environment with WebSphere Commerce:

iOS development prerequisites

Ensure that you are registered with the Apple Developer Program, which is required to access the Xcode IDE and iOS SDK, and test your application with the iOS simulator.

In addition, you must be a member of the iOS Developer Program to deploy applications on an iOS device. For more information, see Apple Developers: Which Developer Program is for you.

The iOS application that is built on IBM Worklight 6.0.0 supports iOS 5, 6 and 7.

For more information about supported operating systems, see Detailed System Requirements for IBM Worklight and IBM Mobile Foundation.

Worklight iOS development prerequisites

  1. Install Worklight Studio on Apple Mac OSX.
  2. Complete the steps in Android hybrid applications using IBM Worklight: Importing project files. The iOS hybrid application is built on-top of the common resources that are shared with the Android hybrid application. Also, the WCWorklight project must be imported before you configure the iOS hybrid application.
  3. Download the sample code: WorklightiOSHybrid-Sample-FEP7.zip
  4. Extract the sample code into a working directory. For example, extract_dir

WebSphere Commerce prerequisites

  1. Ensure that the responsive Aurora starter store (Aurora.sar) is published. It is displayed by default on all devices. There are no mobile or tablet-specific SAR files to publish.
  2. Determine your storeId for the SAR file you published. If you do not know your storeId, run the following SQL query to find the storeId that corresponds to your store:
    
    select * from store;
    

Configuring the iOS hybrid application sample assets for WebSphere Commerce

The Aurora storefront provides assets to support Worklight Android hybrid applications. More assets are included with the sample ZIP file that is required to support the iOS hybrid application. In addition, changes to the device detection and Struts framework are required to support the addition of the iOS hybrid application.
  1. Update the Aurora mobile web storefront with the iOS Hybrid application files.
    1. Merge the contents of extract_dir/WebSphereCommerce/Aurora to:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir
  2. Add a device-mapping for the Worklight iPhone Hybrid application in the wc-devices.xml file.
    1. Locate the wc-devices.xml file:
      • AIXLinuxWindowsWC_eardir/xml/config/com.ibm.commerce.foundation/wc-devices.xml
      • WebSphere Commerce DeveloperWCDE_installdir/xml/config
    2. Create a directory with com.ibm.commerce.foundation-ext filename, if it does not exist.
      Note: When you create an extensions folder, the folder name ends with -ext. Creating a folder name with that ends with -ext ensures that the default file that you are extending remains unchanged. By extending the configuration, you can override the properties of the existing wc-devices.xml file.
    3. In your new extensions folder, create a new file named wc-devices.xml.
    4. In your new wc-devices.xml file, define a device group for each of the hybrid applications. Copy and paste the following code snippet into your file:
      
      <?xml version="1.0" encoding="UTF-8"?>
      <_config:Devices
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.ibm.com/xmlns/prod/commerce/foundation/config ../xsd/wc-devices.xsd" xmlns:_config="http://www.ibm.com/xmlns/prod/commerce/foundation/config">
      	<_config:DeviceGroup internalID="-45" channelID="-6">
      		<_config:Device name="Worklight iPad Hybrid" userAgentPattern=".*iPad.*Worklight/.*"/>
      	</_config:DeviceGroup>
      	<_config:DeviceGroup internalID="-43" channelID="-6">
      		<_config:Device name="Worklight iPhone Hybrid" userAgentPattern=".*iPhone.*Worklight/.*"/>
      	</_config:DeviceGroup>
      </_config:Devices>
      
    5. Save the changes.
  3. Add the view mappings for the Worklight iOS Hybrid application to the Struts configuration file.
    1. Open the extract_dir/Samples/SampleStrutsConfig.txt file.
    2. Open the struts-config-ext.xml file:
      • AIXLinuxWindowsWC_eardir/Stores.war/WEB-INF/struts-config-ext.xml
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/WEB-INF/struts-config-ext.xml
    3. Copy and paste the following code snippet into the <global-forwards> section in the struts-config-ext.xml file, appending the snippet to the existing forward mappings. Update the sample store ID 10701 in the snippet with your store ID value.
      
      <!-- Worklight iOS Hybrid START -->
      <forward className="com.ibm.commerce.struts.ECActionForward" name="WishListDisplayView/10701/-43" path="/mobile30/UserArea/AccountSection/ServiceSection/InterestItemListSubsection/WishLists.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="AjaxOrderItemDisplayView/10701/-43" path="/mobile30/ShoppingArea/ShopcartSection/OrderItemDisplay.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="AjaxLogonForm/10701/-43" path="/mobile30/UserArea/AccountSection/MyAccountDisplay.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="AjaxStoreLocatorDisplayView/10701/-43" path="/mobile30/StoreLocatorArea/StoreLocator.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="SiteMapView/10701/-43" path="/mobile30/ShoppingArea/CatalogSection/CategorySubsection/TopCategoriesDisplay.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="ChangePassword/10701/-43" path="/mobile30/UserArea/AccountSection/PasswordSubsection/PasswordUpdateForm.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="ReLogonFormView/10701/-43" path="/mobile30/UserArea/AccountSection/LogonSubsection/UserTimeoutView.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="RememberMeLogonFormView/10701/-43" path="/mobile30/UserArea/AccountSection/LogonSubsection/logon.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="LogonForm/10701/-43" path="/mobile30/UserArea/AccountSection/LogonSubsection/logon.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="SearchLandingPage1/10701/-43" path="/ShoppingArea/CatalogSection/SearchSubsection/SearchBasedCategoryPage.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="OrderProcessErrorView/10701/-43" path="/GenericError.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="RLBadPartNumberErrorView/10701/-43" path="/GenericError.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="RLInvalidInputErrorView/10701/-43" path="/GenericError.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="iOSMorePageView/10701" path="/StoreInfoArea/iOSMore.jsp"/>
      <forward className="com.ibm.commerce.struts.ECActionForward" name="iOSLanguageCurrencyDisplayView/10701" path="/StoreInfoArea/iOSLanguageCurrencyDisplay.jsp"/>
      <!-- Worklight iOS Hybrid END -->
      
    4. Save the changes.
  4. Register the sample iOS more page in the Struts configuration file. A sample JSP file is provided to simulate the functions of the item list when the more tab is tapped in an iOS tab bar.

    New JSP files (for example, iOSMore.jsp) must be registered in the Struts configuration file to be recognized by WebSphere Commerce. Add the action mapping:

    1. Open the struts-config-ext.xml file:
      • AIXLinuxWindowsWC_eardir/Stores.war/WEB-INF/struts-config-ext.xml
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/WEB-INF/struts-config-ext.xml
    2. Add an <action> entry in the action mappings section, where 10701 is replaced by your store ID. An example code snippet:
      
      <action path="/iOSMorePageView" type="com.ibm.commerce.struts.BaseAction">
      	<set-property property="credentialsAccepted" value="10701:P"/>
      </action>
      <action path="/iOSLanguageCurrencyDisplayView" type="com.ibm.commerce.struts.BaseAction">
      	<set-property property="credentialsAccepted" value="10701:P"/>
      </action>
      
      Note: For extended sites, use the storeent_id of the Asset Store to which these JSP files are registered. Individual extended sites stores inherit these commands from the asset store because created stores do not have any JSP files of their own.
    3. Save the changes
  5. Create access control policies for the sample iOS more page JSP file. By default, only site administrators can access new views. Create access control policies for each new JSP file to allow general access.
    1. Stop WebSphere Commerce Server if it is running.
    2. Go to the following directory:
      • AIXLinuxWindowsWC_installdir\xml\policies\xml
      • WebSphere Commerce DeveloperWCDE_installdir/xml/policies/xml
    3. Create an SampleiOSAccessPolicies.xml XML file and copy and paste the following code snippet into the file:
      
      <?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
      <!DOCTYPE Policies SYSTEM "../dtd/accesscontrolpolicies.dtd">
      <Policies>
      	<Action Name="iOSMorePageView" CommandName="iOSMorePageView">
      	</Action>
      	<ActionGroup Name="AuroraStorefrontAssetStoreAllUsersViews" OwnerID="RootOrganization">
      		<ActionGroupAction Name="iOSMorePageView"/>
      	</ActionGroup>
      	<ActionGroup Name="AuroraAllUsersViews" OwnerID="RootOrganization">
      		<ActionGroupAction Name="iOSMorePageView"/>
      	</ActionGroup>
      	<Action Name="iOSLanguageCurrencyDisplayView" CommandName="iOSLanguageCurrencyDisplayView">
      	</Action>
      	<ActionGroup Name="AuroraStorefrontAssetStoreAllUsersViews" OwnerID="RootOrganization">
      		<ActionGroupAction Name="iOSLanguageCurrencyDisplayView"/>
      	</ActionGroup>
      	<ActionGroup Name="AuroraAllUsersViews" OwnerID="RootOrganization">
      		<ActionGroupAction Name="iOSLanguageCurrencyDisplayView"/>
      	</ActionGroup>
      </Policies>
      
    4. Save the file.
    5. Load the access control policies that are defined in SampleiOSAccessPolicies.xml. For more information, see Loading access control policy definitions and other policy-related elements.
    6. Start WebSphere Commerce Server.

Enabling iOS hybrid application features in the mobile web store JSP files

  1. Add the device ID detection logic to the environment setup JSPs for the Worklight iOS hybrid applications to enable device-specific rendering.
    1. Open the following file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/Common/EnvironmentSetup.jspf
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir/Common/EnvironmentSetup.jspf
    2. Locate the following code snippet:
      
      <%-- Set variables for device specific rendering --%>
      <c:if test="${EC_deviceAdapter.deviceFormatId == -44 || EC_deviceAdapter.deviceFormatId == -42}">
          <c:set var="_worklightHybridApp" value="true" scope="request"/>
          <c:set var="mobileBasePath" value="WorklightHybrid/"/>
          <c:set var="pageMax1" value="20"/>
          <c:set var="pageMax2" value="20"/>
      </c:if>
      
    3. Replace with the following code snippet:
      
      <%-- Set variables for device specific rendering --%>
      <c:if test="${EC_deviceAdapter.deviceFormatId == -45 || EC_deviceAdapter.deviceFormatId == -44 || EC_deviceAdapter.deviceFormatId == -43 || EC_deviceAdapter.deviceFormatId == -42}">
      	<c:set var="_worklightHybridApp" value="true" scope="request"/>
      	<c:set var="mobileBasePath" value="WorklightHybrid/"/>
      	<c:set var="pageMax1" value="20"/>
      	<c:set var="pageMax2" value="20"/>
      </c:if>
      <%-- Set variable for iPad and iPhone devices rendering --%>
      <c:if test="${EC_deviceAdapter.deviceFormatId == -45 || EC_deviceAdapter.deviceFormatId == -43}">
      	<c:set var="_worklightiOSHybridApp" value="true" scope="request"/>
      </c:if>
      
    4. Save the file.
  2. Update WorklightHybridSetup.jspf with new URLs required for the iOS hybrid application.
    1. Open the following file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/WorklightHybridSetup.jspf
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir/WorklightHybrid/WorklightHybridSetup.jspf
    2. Locate the following code snippet:
      
      <wcf:url var="HomePageURL" patternName="HomePageURLWLang" value="TopCategories">
      	<wcf:param name="langId" value="${langId}" />
      	<wcf:param name="storeId" value="${WCParam.storeId}" />
      	<wcf:param name="catalogId" value="${WCParam.catalogId}" />
      </wcf:url>
      
    3. Replace with the following code snippet:
      
      <wcf:url var="HomePageURL" patternName="HomePageURLWithLang" value="TopCategories1">
      	<wcf:param name="langId" value="${langId}" />
      	<wcf:param name="storeId" value="${WCParam.storeId}" />
      	<wcf:param name="catalogId" value="${WCParam.catalogId}" />
      	<wcf:param name="urlLangId" value="${urlLangId}"/>
      </wcf:url>
      <c:if test="${_worklightiOSHybridApp}">
      	<wcf:url var="iOSMorePageURL" value="iOSMorePageView">
      		<wcf:param name="langId" value="${langId}" />
      		<wcf:param name="storeId" value="${WCParam.storeId}" />
      		<wcf:param name="catalogId" value="${WCParam.catalogId}" />
      	</wcf:url>
      </c:if>
      
    4. Locate the following code snippet:
      
      if (storedLangId == null || storedLangId != '${langId}') {
                   ...
      }
      
    5. Update the code snippet with the following change:
      
      if (storedLangId == null || storedLangId != '${langId}') {
                   ...
                   <c:if test="${_worklightiOSHybridApp}">
                   storage.setItem('iOSMorePageURL','${iOSMorePageURL}');
                   </c:if>
      }
      
    6. Locate the following code snippet:
      
      <wcf:url var="ShoppingCartURL" value="AjaxOrderItemDisplayView">
      	<wcf:param name="langId" value="${langId}" />
      	<wcf:param name="storeId" value="${WCParam.storeId}" />
      	<wcf:param name="catalogId" value="${WCParam.catalogId}" />
      </wcf:url>
      
    7. Replace with the following code snippet:
      
      <wcf:url var="shopViewURL" value="AjaxOrderItemDisplayView"></wcf:url>
      <wcf:url var="ShoppingCartURL" value="OrderCalculate" type="Ajax">
      	<wcf:param name="langId" value="${langId}" />
      	<wcf:param name="storeId" value="${WCParam.storeId}" />
      	<wcf:param name="catalogId" value="${WCParam.catalogId}" />
      	<wcf:param name="URL" value="${fn:escapeXml(shopViewURL)}" />
      	<wcf:param name="errorViewName" value="AjaxOrderItemDisplayView" />
      	<wcf:param name="updatePrices" value="1" />
      	<wcf:param name="calculationUsageId" value="-1" />
      	<wcf:param name="orderId" value="." />
      </wcf:url>
      
    8. Save the file.
  3. Update WorklightJSToInclude.jspf to load iOS-specific resources on initialization.
    1. Open the following file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/WorklightJSToInclude.jspf
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir/WorklightHybrid/WorklightJSToInclude.jspf
    2. Locate the following code snippet:
      
      <c:choose>
      <c:when test="${EC_deviceAdapter.deviceFormatId == -42 || EC_deviceAdapter.deviceFormatId == -44}">
      	<c:set var="platformType" value="android"/>
      </c:when>
      <c:otherwise>
      </c:otherwise>
      </c:choose>
      
    3. Replace with the following code snippet:
      
      <c:choose>
      <c:when test="${EC_deviceAdapter.deviceFormatId == -42 || EC_deviceAdapter.deviceFormatId == -44}">
      	<c:set var="platformType" value="android"/>
      </c:when>
      <c:when test="${EC_deviceAdapter.deviceFormatId == -43 || EC_deviceAdapter.deviceFormatId == -45}">
      	<c:set var="platformType" value="ios"/>
      </c:when>
      <c:otherwise>
      </c:otherwise>
      </c:choose>
      
    4. Save the file.
  4. Update the search widget in order for the Worklight iOS hybrid app to use the web search instead of the native search by default.
    1. Open the following file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/Widgets/Search/Search_UI.jspf
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir/Widgets/Search/Search_UI.jspf
    2. Locate the following code snippet:
      
      <a id="searchButton" href="#" role="button" <c:choose><c:when test="${_worklightHybridApp}">onclick="javascript:NativeSearchJS.startSearchActivity();"</c:when><c:otherwise>data-toggle="searchBar"</c:otherwise></c:choose> aria-label="${SEARCH_CATALOG}" title="${SEARCH_CATALOG}" ><span id="searchButton_ACCE_Label" class="spanacce"><fmt:message bundle="${storeText}" key="SEARCH_CATALOG"/></span></a>
      
      <div id="searchBar" data-parent="header">
      	<c:if test="${_worklightHybridApp eq 'true'}">
      	<a id="worklightSearchButton" href="#" role="button" onclick="javascript:NativeSearchJS.startSearchActivity();"><span id="worklightSearchButtonLabel">${SEARCH_CATALOG}</span></a>
      	</c:if>
    3. Update the conditional statements to check whether _worklightiOSHybridApp is false. Replace with the following code snippet:
      
      <a id="searchButton" href="#" role="button" <c:choose><c:when test="${_worklightHybridApp && !_worklightiOSHybridApp}">onclick="javascript:NativeSearchJS.startSearchActivity();"</c:when><c:otherwise>data-toggle="searchBar"</c:otherwise></c:choose> aria-label="${SEARCH_CATALOG}" title="${SEARCH_CATALOG}" ><span id="searchButton_ACCE_Label" class="spanacce"><fmt:message bundle="${storeText}" key="SEARCH_CATALOG"/></span></a>
      
      <div id="searchBar" data-parent="header">
      	<c:if test="${_worklightHybridApp eq 'true' && !_worklightiOSHybridApp}">
      	<a id="worklightSearchButton" href="#" role="button" onclick="javascript:NativeSearchJS.startSearchActivity();"><span id="worklightSearchButtonLabel">${SEARCH_CATALOG}</span></a>
      	</c:if>
      
    4. Save the file.

Updating Worklight specific files in the mobile web storefront

The following changes are made to storefront files used by the Worklight hybrid applications. These files are common between the Android and iPhone hybrid applications, and use the device detection framework of WebSphere Commerce to display platform-specific page content.
  1. Add a container for the back button within the header widget.
    1. Open the file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/Widgets/Header/Header_UI.jspf
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir/Widgets/Header/Header_UI.jspf
    2. Replace the following code snippet:
      
      <div id="header" role="banner">
      
      With the following code snippet:
      
      <div id="header" <c:if test="${_worklightiOSHybridApp}">class="ios"</c:if> role="banner">
      	<c:if test="${(_worklightiOSHybridApp)}">
      		<div id="header_back_button_container"></div>
      	</c:if>
      
    3. Save the file.
  2. Update the common1_1.css and common1_1_rtl.css files to include the iOS WCHybrid.css file.
    1. Open the common1_1.css file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/css/common1_1.css
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir/WorklightHybrid/css/common1_1.css
    2. Add the following line:
      
      @import url("../ios/css/WCHybrid.css");
      
    3. Save the file.
    4. Open the common1_1_rtl.css file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/css/common1_1_rtl.css
      • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/storedir/WorklightHybrid/css/common1_1_rtl.css
    5. Add the following line:
      
      @import url("../ios/css/WCHybrid_rtl.css");
      
    6. Save the file.

Configuring the Worklight Project for the iOS hybrid application

  1. In Worklight Studio, add the iPhone environment.
    1. In the Project Explorer view, right-click WCWorklight and select New > Worklight Environment.
    2. Select iPhone and click Finish.
    3. Perform a build and deploy of the iPhone environment.
  2. Import the application sample source code into the development environment. The files include Aurora sample images for the application's user interface, such as icons for the tab bar and splash screens.
    1. Select File > Import > General > File System.
    2. Select the extract_dir/WCWorklight directory and click OK.
    3. Click Select All files.
    4. Ensure that your target folder is WCWorklight.
    5. Ensure that Overwrite existing resources without warning is selected.
    6. Click Finish.
      Note:
      • If you encounter a dialog warning of read-only files that are encountered, select Yes to make the files writable.
      • An issue (Bug 402263) with the file import tool in Eclipse 4.2.2 might prevent the importing of the sample source code into the WCWorklight project. To work around this issue, manually merge the contents of extract_dir/WCWorklight with the workspace_dir/WCWorklight directory.
  3. Update the WCHybrid.css to apply more iPhone-specific styling.
    1. In Worklight Studio, under the Project Explorer view, open iphone/css/WCHybrid.css.
    2. Add a CSS media query to resize the logo image displayed on the splash screen for Apple retina display devices. In Worklight Studio, open iphone/css/WCHybrid.css and copy and paste the following code snippet into your CSS file after the existing file contents:
      
      @media only screen and (-webkit-device-pixel-ratio: 2.0), only screen and (min-resolution: 192dpi) {
          .splash_logo {
              background-image: url('../images/splash_xhdpi.png');
              background-size: 45% auto;
          }
      }
      
    3. Save the changes.
  4. Add the onDeviceReady function to WCHybrid.js. This function is called once the Cordova run time is initialized, which is required to bind certain Cordova event listeners.
    1. In Worklight Studio, under the Project Explorer view, go to iphone > js and open WCHybrid.js.
    2. Below the wlEnvInit() function, append the following code snippet:
      
      var WCHybridJS = (function() {
          return {
      	    /**
      	     * Called when Cordova runtime has initialized
      	     */
      	    onDeviceReady: function() {
      	    // Functions requiring Cordova runtime to be initialized can be added here
      	    }
          };
      })();
      
    3. Save the changes.
  5. Add new strings to the Messages object. This step covers the additional English language message. Translated strings must be added as required based on this step.
    1. Open the common/js/messages.js file.
    2. In the Messages object, add a key named back, by using the existing keys as a reference. For example:
      
      back: null,
      
    3. Save the file.
    4. Open the common/js/messages_en_US.js file.
    5. In the setEn_US function, assign the value back to the Messages.back variable. For example:
      
      Messages.back = "Back";
      
    6. Save the file.
  6. Update the iPhone Cordova settings in the config.xml.
    1. Open iphone > native > config.xml.
    2. Set the whitelist of hosts that Cordova is allowed to connect to by adding an <access> tag, and set the origin attribute. If your site uses unsecure (HTTP) and secure (HTTPS) protocol, you must add an <access> tag for both protocols.
      For example, if your WebSphere Commerce Server host name is www.example.com, add the following <access> tags:
      
      <access origin="http://www.example.com/"/>
      <access origin="https://www.example.com/"/>
      
      For more information, see Project Settings for iOS.
  7. Build and deploy the iPhone environment and launch Xcode.
    1. Right-click iphone > Run-As > XCode Project. The Xcode environment opens.

Configuring WebSphere Commerce

The Worklight Hybrid application uses JavaScript APIs that call Worklight and Apache Cordova run times that are bundled in the application package. To access these run times, specific JavaScript files are required to be transferred from the Worklight project to the WebSphere Commerce server as part of your store.
  • AIXLinuxWindowsExport the files as a zip file and upload to the WebSphere Commerce Server by using the WebSphere Application Server Administration Console.
  • WebSphere Commerce DeveloperThe files can be copied into your WebSphere Commerce Development Environment.
Using the following table as a guide, perform the following steps:
  1. In Worklight Studio, go into the WCWorklight project.
  2. For each directory that is listed in the table under the From Worklight client project column, select the files in the File names column from the corresponding row.
  3. Copy the files to the directory on your WebSphere Commerce server into the path that is listed under the To WebSphere Commerce store project column.
Important:
  • Copy the JavaScript files from the Worklight environment corresponding to the platform directory in your Worklight Project. For example, for the Android application, copy files from the apps/WCHybrid/android folder.
  • Preserve the directory structure when you copy files from the Worklight project to the WebSphere Commerce store directory. For example, a Worklight project has a /wlclient/js/wlclient.js file. After you copy this file to WebSphere Commerce, the relative path to wlclient.js must be located within the /wlclient/js subdirectory. If the target directory does not exist on your WebSphere Commerce Server, create the directory first.
  • To verify that files are copied to the correct locations in the WebSphere Commerce directory, use the contents of the following JSP files:
    • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/WorklightJSToInclude.jspf
    • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/storedir/WorklightHybrid/WorklightJSToInclude.jspf
Configuring WebSphere Commerce files
File types File names From Worklight client project To WebSphere Commerce store project
Worklight generated common JavaScript files base.jswlcommon.jswljq.jswl_.min.jssjcl.min.jsstacktrace.min.js Android:
  • WC_worklight/apps/WCHybrid/android/native/assets/www/default/common/js
iPhone:
  • WC_worklight/apps/WCHybrid/iphone/native/assets/www/default/common/js
Android:
  • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/android/js
  • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/storedir/WorklightHybrid/android/js
iPhone:
  • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/ios/js
  • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/storedir/WorklightHybrid/ios/js
Worklight application files messages.jsmessages_de_DE.jsmessages_en_US.jsmessages_es_ES.jsmessages_fr_FR.jsmessages_it_IT.jsmessages_ja_JP.jsmessages_ko_KR.jsmessages_pl_PL.jsmessages_pt_BR.jsmessages_ro_RO.jsmessages_ru_RU.jsmessages_zh_CN.jsmessages_zh_TW.jsmessages_ar_EG.jsmessages_he_IL.jsmessages_iw_IL.jsmessages_tr_TR.js WC_worklight/apps/WCHybrid/android/native/assets/www/default/js
All platforms:
  • AIXLinuxWindowsWC_eardir/Stores.war/storedir /WorklightHybrid/common/js
  • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/storedir/WorklightHybrid/common/js
Worklight generated Android-specific files challengeHandlers/antiXSRFChallengeHandler.jschallengeHandlers/authenticityChallengeHandler.jschallengeHandlers/deviceAuthAutoProvisioningChallengeHandler.jschallengeHandlers/deviceAuthNoProvisioningChallengeHandler.jschallengeHandlers/remoteDisableChallengeHandler.js jsonstore/jsonstore.jschecksum.jscordova.jsdeviceAuthentication.jsdiagnosticDialog.jsencryptedcache.jsmessages.jswindow.jswlclient.jswlfragments.jswlgap.android.jsworklight.jsanalytics/analytics.jsfeatures_stubs/jsonstore_stub.jsdeviceSensors/triggers.jsdeviceSensors/acquisition.jsdeviceSensors/geo.jsdeviceSensors/wifi.jsdeviceSensors/bind.jsdeviceSensors/geoUtilities.jsevents/eventTransmitter.js WC_worklight/apps/WCHybrid/android/native/assets/www/default/wlclient/js
  • AIXLinuxWindowsWC_eardir/Stores.war/storedir /WorklightHybrid/android/wlclient/js
  • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/storedir /WorklightHybrid/android/wlclient/js
Worklight generated iOS-specific files challengeHandlers/antiXSRFChallengeHandler.jschallengeHandlers/authenticityChallengeHandler.jschallengeHandlers/deviceAuthAutoProvisioningChallengeHandler.jschallengeHandlers/deviceAuthNoProvisioningChallengeHandler.jschallengeHandlers/remoteDisableChallengeHandler.js jsonstore/jsonstore.jschecksum.jscordova.jsdeviceAuthentication.jsdiagnosticDialog.jsencryptedcache.jsmessages.jswindow.jswlclient.jswlfragments.jswlgap.ios.jsworklight.jsanalytics/analytics.jsfeatures_stubs/jsonstore_stub.jsdeviceSensors/triggers.jsdeviceSensors/acquisition.jsdeviceSensors/geo.jsdeviceSensors/wifi.jsdeviceSensors/bind.jsdeviceSensors/geoUtilities.jsevents/eventTransmitter.js WC_worklight/apps/WCHybrid/iphone/native/assets/www/default/wlclient/js
  • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/ios/wlclient/js
  • WebSphere Commerce DeveloperWCDE_installdir/workspace/Stores/WebContent/storedir/WorklightHybrid/ios/wlclient/js

Setting up the iOS hybrid application in Xcode

When the iOS environment is added to Worklight, a native application shell template is generated by default. Customizing the main application file can provide extra functionality that can help in development of your Worklight iOS hybrid application, such as, the ability to change the target WebSphere Commerce Server.
  1. Implement the development utilities into your main application file.
    1. Open Classes > AuroraWLHybrid.m.
    2. Update the didFinishWLNativeInit method. The didFinishWLNativeInit method retrieves the default values for the settings that are defined in the WCHybridSettings property list, enables the Settings option to clear the local HTML5 storage and ignoring of bad SSL certificates. In addition, the user-agent string of the web view is updated with the string defined in the WebSphere Commerce wc-devices.xml file for the Worklight iPhone Hybrid application.
      Note: Certain functions, such as clearing the local storage and ignoring bad SSL certificates are intended for development use only and must be removed prior to deploying the application to production.

      The getDefaultsFromSettingsBundle method registers the values that are specified in the WCHybridSettings property list within the Settings.bundle on application initialization. removeTargetFileAtPath method removes files, and is used to remove the application cache files. clearLocalStorage method clears application settings, such as the WebSphere Commerce host name, are stored by using the HTML5 LocalStorage for the web view. During development, it might be useful to provide a way to clear these files and reset the application settings.

      Copy and paste the following code snippet into AuroraWLHybrid.m, replacing the existing didFinishWLNativeInit method:
      
      -(void) didFinishWLNativeInit:(NSNotification *)notification {
          /*
           * If you need to do any extra app-specific initialization, you can do it here.
           * Note: At this point webview is available.
           **/
          // Set navigation bar tint color for native pages
          [[UINavigationBar appearance] setTintColor:[UIColor orangeColor]];
          
          NSUserDefaults *stdUserDefaults = [NSUserDefaults standardUserDefaults];
          
          // Load the app settings from the WCHybridSettings property list file
          NSMutableDictionary *wcHybridAppSettings = [self getDefaultsFromSettingsBundle];
          
          if (wcHybridAppSettings != nil) {
              
              // Override app variables with user settings
              for (NSString *key in wcHybridAppSettings.allKeys) {
                  NSString *value = [stdUserDefaults stringForKey:key];
                  if (value != nil && [value length] != 0) {
                      [wcHybridAppSettings setValue:value forKey:key];
                  }
              }
              
              #if DEBUG
              // Development use only - Clear the HTML5 LocalStorage if corresponding user setting is enabled
              // MUST BE REMOVED FROM PRODUCTION CODE
              BOOL clearLocalStorageEnabled = [[wcHybridAppSettings valueForKey:@"clearLocalStorage"] boolValue];
              if (clearLocalStorageEnabled) {
                  [self clearLocalStorage];
              }
          
              // Development use only - Ignore bad SSL certificate if correpsonding user setting is enabled
              // MUST BE REMOVED FROM PRODUCTION CODE
              BOOL ignoreBadSslCert = [[wcHybridAppSettings valueForKey:@"ignoreBadSslCert"] boolValue];
              if (ignoreBadSslCert) {
                  // Gets the server hostname from the corresponding user settings
                  NSString *wcServerHost = [wcHybridAppSettings valueForKey:@"wcServerHostname"];
                  if (wcServerHost == nil || [wcServerHost length] == 0) {
                      wcServerHost = @"";
                      //No WebSphere Commerce Server hostname set. Go to Settings and provide the hostname (e.g. demo.ibm.com) of the server with the invalid SSL certificate. Terminate and relaunch the app for the hostname to take effect.
                  } else {
                      [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:wcServerHost];
                  }
              }
              #endif
          
              // Append the Worklight Hybrid User-Agent to the default value
              // Create a UIWebView to retrieve the user-agent via JavaScript
              /*
              NSString *wlUserAgentSuffix = @" Worklight iPhone Hybrid"; // leading space is required
              UIWebView *tempWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
              NSString *defaultUserAgent = [tempWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
              NSString *wlUserAgent = [defaultUserAgent stringByAppendingString:wlUserAgentSuffix];
              [wcHybridAppSettings setObject:wlUserAgent forKey:@"UserAgent"];
              */
      
              // Register the settings
              [stdUserDefaults registerDefaults:wcHybridAppSettings];
          
          }
      
      }	
      
    3. Add the following interface for the NSURLRequest.
      Note: This function is intended for development use only and must be removed before you deploy the application to production.
      This code must be placed between the import statements and the @implementation directive:
      
      // Development use only - Ignore bad SSL certificate if corresponding user setting is enabled
      // MUST BE REMOVED FROM PRODUCTION CODE
      @interface NSURLRequest (Dummy)
      + (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host;
      + (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host;
      @end
      
    4. Values that are specified in the WCHybridSettings property list within the Settings.bundle must be registered by the application to apply. The following code excerpt shows an implementation of getDefaultsFromSettingsBundle. Add the following method to AuroraWLHybrid.m:
      
      - (NSMutableDictionary *)getDefaultsFromSettingsBundle {
          
          NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
          
          // Get the pathname for Settings.bundle
          NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
          
          // Get the contents of WCHybridSettings.plist
          NSDictionary *wcHybridSettings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"WCHybridSettings.plist"]];
          
          if (wcHybridSettings != nil) {
              // Get the preferences under the PreferenceSpecifiers key
              NSArray *preferences = [wcHybridSettings objectForKey:@"PreferenceSpecifiers"];
              if (preferences != nil) {
                  NSMutableDictionary *defaults = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
                  // Store default value (if set in the property list) for each key
                  for (NSDictionary *pref in preferences) {
                      NSString *key = [pref objectForKey:@"Key"];
                      if (key != nil) {
                          NSString *defVal = [pref objectForKey:@"DefaultValue"];
                          if (defVal != nil) {
                              [defaults setObject:defVal forKey:key];
                          }
                      }
                  }
                  dict = defaults;
              }
          }
          return dict;
      }
      
    5. The removeTargetFileAtPath method is used to remove files, such as the application cache files. Add the following method to AuroraWLHybrid.m:
      
      - (void)removeTargetFileAtPath:(NSString *)path :(NSString *)fileExtension
      {
          for (NSString *string in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil]) {
              if ([[string pathExtension] isEqualToString:fileExtension]) {
                  [[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil];
              }
          }
      }
      
    6. Application settings, such as the WebSphere Commerce host name, are stored by using the HTML5 LocalStorage for the web view. During development, it might be useful to provide a way to clear these files and reset the application settings. Add the following implementation of the clearLocalStorage method to AuroraWLHybrid.m:
      
      - (void)clearLocalStorage {
          NSString *LOCAL_STORAGE_EXT = @"localstorage";
          
          // Remove cookies
          NSHTTPCookieStorage *WCHybridCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
          for (NSHTTPCookie *cookie in [WCHybridCookieStorage cookies]) {
              [WCHybridCookieStorage deleteCookie:cookie];
          }
          
          // Remove the HTML5 local storage db
          NSString *appStoragePath = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"Backups"] stringByAppendingPathComponent:@"localstorage.appdata.db"];
          [[NSFileManager defaultManager] removeItemAtPath:appStoragePath error:nil];
          
          // Library/Caches folder is used for local web storage for iOS versions 5.1-6.0
          if(IsAtLeastiOSVersion(@"5.1") && !IsAtLeastiOSVersion(@"6.0")) {
              NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
              [self removeTargetFileAtPath:cachePath :LOCAL_STORAGE_EXT];
          }
          
          // Check Library/WebKit folder for iOS 6
          NSString *webKitPath = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"WebKit/LocalStorage"];
          [self removeTargetFileAtPath:webKitPath :LOCAL_STORAGE_EXT];
          
          // Reset the Clear LocalStorage toggle in Settings
          [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"clearLocalStorage"];
          
      }
      
  2. Add the Development preferences user interface controls to the Settings menu. For more information, see Implementing an iOS Settings Bundle.
    1. Open Resources > Settings.bundle > Root.plist.
    2. Create a child panel item in the Root.plist. This creates a button in the top-level application settings page that shows the child settings page. Control-click the editor pane and select Add Row. Use the following values for this key:
      Settings
      Field Type Value
      Type String Child Pane
      Title String Settings
      Filename String WCHybridSettings
    3. Create a property list that is named WCHybridSettings.plist to the Settings bundle. For more information, see Creating Additional Settings Page Files.
    4. Add a text field for the WebSphere Commerce Server host name. Control-click the editor pane and select Add Row. Assign the following values for this key:
      Server host name
      Field Type Value
      Type String PSTextFieldSpecifier
      Title String Server Hostname
      Identifier String wcServerHostname
      Default value String No default value
    5. Add a toggle switch to enable ignoring of bad SSL certificates. Control-click the editor pane and select Add Row. Use the following values for this key:
      Ignore Bad SSL Cert
      Field Type Value
      Type String Toggle Switch
      Title String Ignore Bad SSL Cert
      Identifier String ignoreBadSslCert
      Default Value Boolean YES
    6. Add a toggle switch to clear the local storage. Control-click the editor pane and select Add Row. Use the following values for this key:
      Clear local storage
      Field Type Value
      Type String Toggle Switch
      Title String Clear Local Storage
      Identifier String clearLocalStorage
      Default Value Boolean NO
    7. Add a group for Development items. Adding a group of Development items visually groups the following items in the Settings menu. Control-click the editor pane and select Add Row. Use the following values for this key:
      Development
      Field Type Value
      Type String Group
      Title String Development
    8. Save and close.
  3. Build the Xcode project.
    1. Perform a build-in Xcode and deploy to the iOS Simulator. Select the iPhone Simulator when prompted.

Configuring the application after installation

The application settings are accessible through the iOS Settings application, under the Aurora WLHybrid app. These settings are intended for development use only, and must be removed before you deploy the application to production. For example, end users must not be able to clear local storage, enable ignoring of bad SSL certificates, or other settings that can negatively alter the behavior of the application.

The configurable development settings are as follows:
Clear LocalStorage
Toggles whether the application must clear the application's HTML5 LocalStorage, to enable you to update the in-app configuration (host name, store ID, and so on).
This setting applies on the next app launch. The default value is OFF.
Ignore Bad SSL Cert
Toggles whether the application must ignore a bad SSL certificate.
The default value is ON.
Server Hostname
When you ignore bad SSL certificates, the host name of your WebSphere Commerce Server must also be specified.
If you are configuring the application for the first time, or need to update the application settings, perform the following steps:
  1. Go to your simulator or device application settings and open the Settings application. Scroll through the list of applications and select Aurora WLHybrid > Settings > Development.
  2. Update the following settings:
    • Ensure Ignore Bad SSL Cert is set to On.
    • Ensure that your WebSphere Commerce Server host name is specified in the Server Hostname field.
  3. Exit and restart the application

Integrating native device features into the Worklight iOS hybrid application

Worklight provides options to access native functionality from web applications: implementing a custom Apache Cordova plug-in, or integrating native pages with web pages. The NativePage API enables the application to switch between a web view and a native view. Similar to the Android hybrid application, the iPhone hybrid application takes the approach of integrating native pages with the web pages by using the Worklight NativePage API.

For more information. see Getting started tutorials and samples.

The NativePage API is used to implement a native class that is invoked from your web view. Data can be passed to and from the web view and native page view. For more information, see Web and native code in iPhone, iPad and Android.

The following section describes how to integrate the following features:
  • Address book integration for importing contacts into the account address book.
  • Native Maps application integration under the stores tab.

Barcode scanning requires integration with third-party libraries such as ZBar or ZXing barcode scanners. Barcode scanning can be implemented as an Apache Cordova plug-in. For more information, see Using Cordova plugins in Worklight: Native barcode scanning for iOS.

Adding the native features by using Worklight NativePage API

Following the Worklight NativePage API documentation, native features are accessed by extending the UIViewController class. The instructions assume familiarity with using Xcode, iOS programming, and Objective-C. The Aurora starter store contains sample JavaScript files that can be used to invoke the native classes, which are also common to the Worklight Android hybrid application. The files are located under the following directory:
  • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/common/js
  • WebSphere Commerce DeveloperWCDE_installdir/Stores/storedir/WorklightHybrid/common/js

Class names for the Worklight iOS hybrid application can be declared in the WCHybridAppProperties.js file. A sample implementation is provided as part of the sample source ZIP file (see Worklight iOS development prerequisites).

For example, in WCHybridAppProperties.js, the native map class name is MapViewController. Following this convention, in your Xcode project, you would create a new Objective-C class called as MapViewController containing your implementation of the native page for the map view.

Integrating the native address book

  1. In XCode, right-click Classes > New File. Select iOS > Cocoa Touch > Objective-C class. Click Next.
  2. Following the definition in WCHybridAppProperties.js, in the Class field, name the class ContactsViewController. Ensure that Subclass of is set to UIViewController. Select With XIB for user interface. Click Next.
  3. In the following window, navigate to and select the Classes folder. Click Create.
  4. In the ContactsViewController.h file, update the interface definition to include the ABPeoplePickerNavigationControllerDelegate. For more information, see ABPeoplePickerNavigationControllerDelegate Protocol Reference.
    1. Add import statements for the AddressBook frameworks:
      
      <AddressBook/AddressBook.h>
      <AddressBookUI/AddressBookUI.h>
      
    2. Locate the following line:
      
      @interface ContactsViewController : UIViewController
      
      Update the line to include the delegate:
      
      @interface ContactsViewController : UIViewController <ABPeoplePickerNavigationControllerDelegate>
    3. Save the changes.
  5. In the ContactsViewController.m file, add the methods that are required to implement the ABPeoplePickerNavigationControllerDelegate.

    The peoplePickerNavigationControllerDidCancel method closes the people picker when the user taps the cancel button in the user interface and returns to the web view. The peoplePickerNavigationController:shouldContinueAfterSelectingPerson method displays the contact, when one is selected by the user and the picker is dismissed. The peoplePickerNavigationController:shouldContinueAfterSelectingPerson:property:identifier method returns data to the web view when the user selects a contact's properties, and closes the view.

    Copy and paste the following code snippet:
    
    -(void)setDataFromWebView:(NSDictionary *)data {
    }
    
    #pragma mark - ABPeoplePickerNavigationControllerDelegate
    
    - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
    	[self dismissViewControllerAnimated:NO completion:nil];
    	[NativePage showWebView:nil];
    }
    
    - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
    	return YES;
    }
    
    - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {
    NSMutableDictionary *address = [[NSMutableDictionary alloc] init];
    NSString *nickName = (NSString *)ABRecordCopyValue(person, kABPersonNicknameProperty);
    NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
    ABMultiValueRef addressMVR = ABRecordCopyValue(person, property);
    CFIndex index = ABMultiValueGetIndexForIdentifier(addressMVR, identifier);
    CFDictionaryRef addressDR = ABMultiValueCopyValueAtIndex(addressMVR, index);
    NSString *street = (NSString *)CFDictionaryGetValue(addressDR, kABPersonAddressStreetKey);
    NSString *city = (NSString *)CFDictionaryGetValue(addressDR, kABPersonAddressCityKey);
    NSString *state = (NSString *)CFDictionaryGetValue(addressDR, kABPersonAddressStateKey);
    NSString *country = (NSString *)CFDictionaryGetValue(addressDR, kABPersonAddressCountryKey);
    NSString *zipcode = (NSString *)CFDictionaryGetValue(addressDR, kABPersonAddressZIPKey);
    ABMultiValueRef phoneMVR = ABRecordCopyValue(person, kABPersonPhoneProperty);
    NSArray *phones = (NSArray *)ABMultiValueCopyArrayOfAllValues(phoneMVR);
    ABMultiValueRef emailMVR = ABRecordCopyValue(person, kABPersonEmailProperty);
    NSArray *emails = (NSArray *)ABMultiValueCopyArrayOfAllValues(emailMVR);
    [address setObject:(nickName != nil ? nickName : @"") forKey:@"nickName"];
    [address setObject:(firstName != nil ? firstName : @"") forKey:@"firstName"];
    [address setObject:(lastName != nil ? lastName : @"") forKey:@"lastName"];
    [address setObject:(street != nil ? street : @"") forKey:@"street"];
    [address setObject:(city != nil ? city : @"") forKey:@"city"];
    [address setObject:(state != nil ? state : @"") forKey:@"state"];
    [address setObject:(country != nil ? country : @"") forKey:@"country"];
    [address setObject:(zipcode != nil ? zipcode : @"") forKey:@"postCode"];
    [address setObject:(phones != nil ? phones : [NSNull null]) forKey:@"phone"];
    [address setObject:(emails != nil ? emails :[NSNull null]) forKey:@"email"];
    CFRelease(emailMVR);
    CFRelease(phoneMVR);
    CFRelease(addressDR);
    CFRelease(addressMVR);
    [self dismissViewControllerAnimated:NO completion:nil];
    [NativePage showWebView:address];
    return NO;
    }
    
  6. In the ContactsViewController.m file, update activity lifecycle methods to call and close the people picker.
    1. Add import statements for the following files:
      • AuroraWLHybrid.h
      • CDVAppDelegate.h
      • NativePage.h
    2. Create the following instance variables:
      
      ABPeoplePickerNavigationController *peoplePicker;
      MyAppDelegate *myAppDelegate;
      
    3. Add the init, onBeforeShow, and onAfterShow methods. Copy and paste the following code snippet:
      
      - (id)init {
      peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
      myAppDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
      return [super init];
      }
      - (void)onBeforeShow {
      }
      - (void)onAfterShow {
          [self presentViewController:peoplePicker animated:NO completion:nil];
      }
      
    4. In the viewDidLoad method, configure the ABPeoplePickerNavigationController and add the view to the delegate. Add the following lines to viewDidLoad:
      
      [peoplePicker setDisplayedProperties:[[NSArray alloc] initWithObjects:[[NSNumber alloc] initWithInt:kABPersonAddressProperty], nil]];
      [peoplePicker setPeoplePickerDelegate:self];
      [self.view setAlpha:0.0];
      [myAppDelegate.window addSubview:self.view];
      
  7. Save the changes to the ContactsViewController.m file.

Integrating the native map display

  1. In Xcode, create a new MapViewController class. Ensure that With XIB for user interface is selected when you create the class. This creates the header file, application class, and Interface Builder file (.xib).
  2. Add the MapKit framework to the Xcode project.
  3. In MapViewController.h, add import statements for the MapKit framework and update the interface to include the MapViewDelegate.
    1. Add an import statement for <MapKit/MapKit.h>.
    2. Update the interface definition to include the MKMapViewDelegate. Locate the following line:
      
      @interface MapViewController : UIViewController
      
      Update it to include the delegate:
      
      @interface MapViewController : UIViewController <MKMapViewDelegate>
      
    3. Define the following list of properties between the @interface and @end lines:
      
      @property (nonatomic, retain) IBOutlet MKMapView *mapView;
      @property (nonatomic, retain) IBOutlet UINavigationBar *navBar;
      @property (nonatomic, retain) IBOutlet UIBarButtonItem *backButton;
      @property (nonatomic, copy) NSString *mapCenterLat;
      @property (nonatomic, copy) NSString *mapCenterLong;
      @property (nonatomic, copy) NSString *storeName;
      @property (nonatomic, copy) NSString *storeLat;
      @property (nonatomic, copy) NSString *storeLong;
      @property (nonatomic, copy) NSString *storeCity;
      @property (nonatomic, copy) NSString *storeState;
      @property (nonatomic, copy) NSString *storeAddr1;
      @property (nonatomic, copy) NSString *storeAddr2;
      @property (nonatomic, copy) NSString *storeAddr3;
      @property (nonatomic, copy) NSString *headerTitle;
      @property (nonatomic, copy) MKPointAnnotation *physicalStore;
      
    4. Save the changes.
  4. In the MapViewController.m, update and add activity lifecycle methods to call and close the native map.
    1. Add import statements for:
      • NativePage.h
      • CDVAppDelegate.h
      • MapKit/MapKit.h
    2. Add synthesize statements for each of the properties that are defined in the MapViewController.h file. For example, after the @implementation MapViewController statement, add @synthesize mapView;.
    3. In viewDidLoad, add the following code after the super call:
      
      [mapView setDelegate:self];
      if (self.headerTitle != nil) {
              [[navBar topItem] setTitle:self.headerTitle];
              [[navBar topItem] setIsAccessibilityElement:YES];
              [[navBar topItem] setAccessibilityLabel:self.headerTitle];
      }
      NSString *backButtonLabel = @"Back";
      [backButton setTitle:backButtonLabel];
      [backButton setIsAccessibilityElement:YES];
      [backButton setAccessibilityLabel:backButtonLabel];
      
    4. Implement the view lifecycle and data methods in viewDidUnload by adding the following methods to the class: The viewDidAppear method is called when the map view is displayed, and refreshes the annotations (pin icons that represent the physical store) and centers the map that is centered over the selected physical store. The setDataFromWebView method sets the physical store properties from the data that is sent from the web view. The createSubtitle method displays the map annotations when clicked. The hideMapView method action is called when the map view is dismissed.
      Copy and paste the following code snippet into MapViewController.m:
      
      - (void)viewDidUnload {
      	[super viewDidUnload];
      	self.mapView = nil;
      }
      
      - (void)viewDidAppear:(BOOL)animated {
       
          [super viewDidAppear:animated];
          
          // Remove previous physical store annotations from the MapView
          NSArray *annotations = [self.mapView annotations];
          for (id annotation in annotations) {
              if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
                  [self.mapView removeAnnotation:annotation];
              }
          }
          
          CLLocationCoordinate2D userLocation = {[self.mapCenterLat floatValue], [self.mapCenterLong floatValue]};
          MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation, 2000, 2000);
          [self.mapView setRegion:region animated:NO];
          
          physicalStore = [[MKPointAnnotation alloc] init];
          [physicalStore setCoordinate:CLLocationCoordinate2DMake([self.storeLat floatValue], [self.storeLong floatValue])];
          [physicalStore setTitle:self.storeName];
          [physicalStore setSubtitle:[self createSubtitle]];
          [physicalStore setIsAccessibilityElement:YES];
          [physicalStore setAccessibilityLabel:physicalStore.subtitle];
          [self.mapView setCenterCoordinate:physicalStore.coordinate animated:YES];
          [self.mapView addAnnotation:physicalStore];
          
          // Selecting the annotation to automatically open the callout does not have an effect on iOS 5.1
          [self.mapView selectAnnotation:physicalStore animated:YES];
      }
      
      - (void)setDataFromWebView:(NSDictionary *) data {
          self.mapCenterLat = (NSString *) [data valueForKey:@"mapCenterLatitude"];
          self.mapCenterLong = (NSString *) [data valueForKey:@"mapCenterLongitude"];
          self.storeName = (NSString *) [data valueForKey:@"storeName"];
          self.storeLat = (NSString *) [data valueForKey:@"storeLatitude"];
          self.storeLong = (NSString *) [data valueForKey:@"storeLongitude"];
          self.storeCity = (NSString *) [data valueForKey:@"storeCity"];
          self.storeState = (NSString *) [data valueForKey:@"storeState"];
          self.storeAddr1 = (NSString *) [data valueForKey:@"storeAddress1"];
          self.storeAddr2 = (NSString *) [data valueForKey:@"storeAddress2"];
          self.storeAddr3 = (NSString *) [data valueForKey:@"storeAddress3"];
          self.headerTitle = (NSString *) [data valueForKey:@"storeLocatorTitle"];
      }
      
      - (NSString *)createSubtitle {
          NSMutableString *subtitle = [[NSMutableString alloc] init];
          [subtitle appendString:self.storeAddr1];
          [subtitle appendString:@", "];
          [subtitle appendString:self.storeCity];
          [subtitle appendString:@", "];
          [subtitle appendString:self.storeState];
          return subtitle;
      }
      
      
      - (IBAction)hideMapView:(id)sender {
          [NativePage showWebView:nil];
      }
      
    5. Save the changes.
  5. Use Xcode's Interface Builder to add a navigation bar and map view to the MapViewController.xib file. For more information, see Creating View Objects from Interface Builder.
    1. Add a Navigation Bar to the top of the view.
    2. Add a Bar Button Item to the Navigation Bar.
    3. Add a MapView to the view and size it so that it occupies the remaining area below the Navigation Bar.
    4. From File's Owner, assign the outlets for the user interface objects:
      1. Assign the backButton outlet to the Bar Button Item
      2. Assign the mapView outlet to the Map View.
      3. Assign the navBar outlet to the Navigation Bar.
      4. Assign the Received Actions for hideMapView to the Bar Button Item.
    5. Save the changes.

Updates to storefront files to invoke native features

The responsive Aurora and mobile stores contain sample JavaScript files that can be used to invoke the native classes, which are also common between the Worklight Android and iOS hybrid applications. The files are located under the following directory:
  • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/common/js
  • WebSphere Commerce DeveloperWCDE_installdir/Stores/storedir/WorklightHybrid/common/js
After you implement the native features, Aurora mobile storefront JSP files require extra configuration to enable the web elements to invoke the native iOS functionality.
  1. Update the iOS hybrid application properties files with the native class names corresponding to your classes.
    1. Open the following file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/ios/js/WCHybridAppProperties.js
      • WebSphere Commerce DeveloperWCDE_installdir/Stores/storedir/WorklightHybrid/ios/js/WCHybridAppProperties.js
    2. In the default WCHybridAppProperties.js file, the native map class name is defined as MapViewController. This assumes that in your Xcode project has an Objective-C class that is named MapViewController with your implementation of the native page. Add or change the properties in WCHybridAppProperties.js.
  2. Update the DisplayMap.js file to pass an extra store locator title parameter from the web view to the native view.
    1. Open the following file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/WorklightHybrid/common/js/DisplayMap.js
      • WebSphere Commerce DeveloperWCDE_installdir/Stores/storedir/WorklightHybrid/common/js/DisplayMap.js
    2. In the invokeNativeMap function, locate the localInfo variable and add a parameter to pass in the store title by using the JSON string:
      
      var localInfo = {
      ...
      storeAddress3: address3
      };
      
    3. Add storeLocatorTitle: document.title so that the resulting code resembles the following:
      
      var localInfo = {
      ...
      storeAddress3: address3,
      storeLocatorTitle: document.title
      };
      
    4. Save the file.

Troubleshooting

  • When you update the files in Worklight Studio under the WCHybrid > iphone > native path, followed by a Run-As > XCode project, files in the Xcode project might not be refreshed until the project is reloaded. Do the following:
    1. Exit Xcode.
    2. Return to Worklight Studio, perform a build of the iPhone environment.
    3. Right-click the iphone environment, select Run-As > XCode project to relaunch Xcode.
  • 302 redirects are not handled correctly in the Worklight iPhone hybrid app and the webViewDidFinishLoad method might never be called. This is a known issue In Apache Cordova version 2.6, which is packaged with Worklight 6.0. For more information about this known issue, see Device ready is not fired in IOS after receiving a 302 temporary redirect from remote server.
    One workaround is to update affected JSP files so that the redirect is triggered earlier in the page load:
    1. Open the following file:
      • AIXLinuxWindowsWC_eardir/Stores.war/storedir/mobile30/ShoppingArea/CheckoutSection/OrderBillingAddressSelection.jsp
      • WebSphere Commerce DeveloperWCDE_installdir/Stores/storedir/mobile30/ShoppingArea/CheckoutSection/OrderBillingAddressSelection.jsp
    2. Locate the following line:
      
      <html xmlns="http://www.w3.org/1999/xhtml" lang="${shortLocale}" xml:lang="${shortLocale}">
      
    3. Add the JavaScript redirect to the order billing details page, when valid addresses are not associated with the current user and the user is not in the My Account flow. Copy and paste the following code snippet above the line in the preceding step:
      
      <c:set var="hasValidAddresses" value="false"/>
      <c:forEach var="payment" items="${usablePayments.usablePaymentInformation}">
      	<c:if test="${fn:length(payment.usableBillingAddress) > 0 && !hasValidAddresses}">
      		<c:set var="hasValidAddresses" value="true"/>
      	</c:if>
      </c:forEach>
      <c:choose>
      <c:when test="${_worklightiOSHybridApp && !hasValidAddresses && fromPage != 'MyAccount'}">
      <wcf:url var="OrderBillingDetailsURL" value="m30OrderBillingDetails">
      	<wcf:param name="langId" value="${langId}" />
      	<wcf:param name="storeId" value="${WCParam.storeId}" />
      	<wcf:param name="catalogId" value="${WCParam.catalogId}" />
      	<wcf:param name="orderId" value="${WCParam.orderId}" />
      	<wcf:param name="fromPage" value="${WCParam.fromPage}" />
      </wcf:url>
      <html xmlns="http://www.w3.org/1999/xhtml" lang="${shortLocale}" xml:lang="${shortLocale}">
      	<head>
      		<meta http-equiv="refresh" content="0;url=${OrderBillingDetailsURL}"/>
      	</head>
      	<body>
      	</body>
      </html>
      </c:when>
      <c:otherwise>
      
    4. Add the closing <c:otherwise> and <c:choose> tags to the newly added code snippet. The closing tag must be placed at the end of the existing </html> block.
    5. Save the file.