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.
- 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
- Configuring the iOS hybrid application sample assets for WebSphere Commerce
- Enabling iOS hybrid application features in the mobile web store JSP files
- Updating Worklight specific files in the mobile web storefront
- Configuring the Worklight Project for the iOS hybrid application
- Configuring WebSphere Commerce
- Setting up the iOS hybrid application in Xcode
- Configuring the application after installation
- Integrating native device features into the Worklight iOS hybrid application
- Adding the native features by using Worklight NativePage API
- Integrating the native address book
- Integrating the native map display
- Updates to storefront files to invoke native features
- Troubleshooting
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
- Install Worklight Studio on Apple Mac OSX.
- 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.
- Download the sample code: WorklightiOSHybrid-Sample-FEP7.zip
- Extract the sample code into a working directory. For example, extract_dir
WebSphere Commerce prerequisites
- 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.
- Determine your
storeId
for the SAR file you published. If you do not know yourstoreId
, run the following SQL query to find thestoreId
that corresponds to your store:select * from store;
Configuring the iOS hybrid application sample assets for WebSphere Commerce
- Update the Aurora mobile web storefront with the iOS Hybrid application files.
- Merge the contents of
extract_dir/WebSphereCommerce/Aurora to:
- WC_eardir/Stores.war/storedir
- WCDE_installdir/workspace/Stores/storedir
- Merge the contents of
extract_dir/WebSphereCommerce/Aurora to:
- Add a device-mapping for the Worklight iPhone Hybrid application in the
wc-devices.xml file.
- Locate the wc-devices.xml file:
- WC_eardir/xml/config/com.ibm.commerce.foundation/wc-devices.xml
- WCDE_installdir/xml/config
- 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.
- In your new extensions folder, create a new file named wc-devices.xml.
- 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>
- Save the changes.
- Locate the wc-devices.xml file:
- Add the view mappings for the Worklight iOS Hybrid application to the Struts configuration file.
- Open the extract_dir/Samples/SampleStrutsConfig.txt file.
- Open the struts-config-ext.xml file:
- WC_eardir/Stores.war/WEB-INF/struts-config-ext.xml
- WCDE_installdir/workspace/Stores/WebContent/WEB-INF/struts-config-ext.xml
- 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 -->
- Save the changes.
- 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:
- Open the struts-config-ext.xml file:
- WC_eardir/Stores.war/WEB-INF/struts-config-ext.xml
- WCDE_installdir/workspace/Stores/WebContent/WEB-INF/struts-config-ext.xml
- 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. - Save the changes
- Open the struts-config-ext.xml file:
- 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.
- Stop WebSphere Commerce Server if it is running.
- Go to the following directory:
- WC_installdir\xml\policies\xml
- WCDE_installdir/xml/policies/xml
- 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>
- Save the file.
- 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.
- Start WebSphere Commerce Server.
Enabling iOS hybrid application features in the mobile web store JSP files
- Add the device ID detection logic to the environment setup JSPs for the Worklight iOS hybrid
applications to enable device-specific rendering.
- Open the following file:
- WC_eardir/Stores.war/storedir/Common/EnvironmentSetup.jspf
- WCDE_installdir/workspace/Stores/storedir/Common/EnvironmentSetup.jspf
- 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>
- 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>
- Save the file.
- Open the following file:
- Update WorklightHybridSetup.jspf with new URLs required for the iOS hybrid application.
- Open the following file:
- WC_eardir/Stores.war/storedir/WorklightHybrid/WorklightHybridSetup.jspf
- WCDE_installdir/workspace/Stores/storedir/WorklightHybrid/WorklightHybridSetup.jspf
- 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>
- 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>
- Locate the following code
snippet:
if (storedLangId == null || storedLangId != '${langId}') { ... }
- Update the code snippet with the following
change:
if (storedLangId == null || storedLangId != '${langId}') { ... <c:if test="${_worklightiOSHybridApp}"> storage.setItem('iOSMorePageURL','${iOSMorePageURL}'); </c:if> }
- 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>
- 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>
- Save the file.
- Open the following file:
- Update WorklightJSToInclude.jspf to load iOS-specific resources on initialization.
- Open the following file:
- WC_eardir/Stores.war/storedir/WorklightHybrid/WorklightJSToInclude.jspf
- WCDE_installdir/workspace/Stores/storedir/WorklightHybrid/WorklightJSToInclude.jspf
- 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>
- 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>
- Save the file.
- Open the following file:
- Update the search widget in order for the Worklight iOS hybrid app to use the web search instead
of the native search by default.
- Open the following file:
- WC_eardir/Stores.war/storedir/Widgets/Search/Search_UI.jspf
- WCDE_installdir/workspace/Stores/storedir/Widgets/Search/Search_UI.jspf
- 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>
- 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>
- Save the file.
- Open the following file:
Updating Worklight specific files in the mobile web storefront
- Add a container for the back button within the header widget.
- Open the file:
- WC_eardir/Stores.war/storedir/Widgets/Header/Header_UI.jspf
- WCDE_installdir/workspace/Stores/storedir/Widgets/Header/Header_UI.jspf
- 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>
- Save the file.
- Open the file:
- Update the common1_1.css and common1_1_rtl.css files
to include the iOS WCHybrid.css file.
- Open the common1_1.css file:
- WC_eardir/Stores.war/storedir/WorklightHybrid/css/common1_1.css
- WCDE_installdir/workspace/Stores/storedir/WorklightHybrid/css/common1_1.css
- Add the following
line:
@import url("../ios/css/WCHybrid.css");
- Save the file.
- Open the common1_1_rtl.css file:
- WC_eardir/Stores.war/storedir/WorklightHybrid/css/common1_1_rtl.css
- WCDE_installdir/workspace/Stores/storedir/WorklightHybrid/css/common1_1_rtl.css
- Add the following
line:
@import url("../ios/css/WCHybrid_rtl.css");
- Save the file.
- Open the common1_1.css file:
Configuring the Worklight Project for the iOS hybrid application
- In Worklight Studio, add the iPhone environment.
- In the Project Explorer view, right-click WCWorklight and select .
- Select iPhone and click Finish.
- Perform a build and deploy of the iPhone environment.
- 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.
- Select .
- Select the extract_dir/WCWorklight directory and click OK.
- Click Select All files.
- Ensure that your target folder is WCWorklight.
- Ensure that Overwrite existing resources without warning is selected.
- 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.
- Update the WCHybrid.css to apply more iPhone-specific styling.
- In Worklight Studio, under the Project Explorer view, open iphone/css/WCHybrid.css.
- 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; } }
- Save the changes.
- 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.
- In Worklight Studio, under the Project Explorer view, go to and open WCHybrid.js.
- 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 } }; })();
- Save the changes.
- 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.
- Open the common/js/messages.js file.
- In the Messages object, add a key named
back
, by using the existing keys as a reference. For example:back: null,
- Save the file.
- Open the common/js/messages_en_US.js file.
- In the setEn_US function, assign the value
back
to the Messages.back variable. For example:Messages.back = "Back";
- Save the file.
- Update the iPhone Cordova settings in the config.xml.
- Open .
- 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:
For more information, see Project Settings for iOS.<access origin="http://www.example.com/"/> <access origin="https://www.example.com/"/>
- Build and deploy the iPhone environment and launch Xcode.
- Right-click . The Xcode environment opens.
Configuring WebSphere Commerce
- Export the files as a zip file and upload to the WebSphere Commerce Server by using the WebSphere Application Server Administration Console.
- The files can be copied into your WebSphere Commerce Development Environment.
- In Worklight Studio, go into the WCWorklight project.
- 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.
- 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.
- 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:
- WC_eardir/Stores.war/storedir/WorklightHybrid/WorklightJSToInclude.jspf
- WCDE_installdir/workspace/Stores/WebContent/storedir/WorklightHybrid/WorklightJSToInclude.jspf
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:
|
Android:
|
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:
|
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 |
|
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 |
|
Setting up the iOS hybrid application in Xcode
- Implement the development utilities into your main application file.
- Open .
- Update the
didFinishWLNativeInit
method. ThedidFinishWLNativeInit
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]; } }
- 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 theimport
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
- 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; }
- 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]; } } }
- 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"]; }
- Add the Development preferences user interface controls to the Settings
menu. For more information, see Implementing an iOS Settings Bundle.
- Open .
- 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 - Create a property list that is named WCHybridSettings.plist to the Settings bundle. For more information, see Creating Additional Settings Page Files.
- 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 - 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 - 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 - 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 - Save and close.
- Build the Xcode project.
- 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.
- 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).
- Ignore Bad SSL Cert
- Toggles whether the application must ignore a bad SSL certificate.
- Server Hostname
- When you ignore bad SSL certificates, the host name of your WebSphere Commerce Server must also be specified.
- Go to your simulator or device application settings and open the Settings application. Scroll through the list of applications and select .
- 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.
- 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.
- 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
- WC_eardir/Stores.war/storedir/WorklightHybrid/common/js
- WCDE_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
- In XCode, right-click . Select . Click Next.
- 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.
- In the following window, navigate to and select the Classes folder. Click Create.
- In the ContactsViewController.h file, update the interface definition to
include the
ABPeoplePickerNavigationControllerDelegate
. For more information, see ABPeoplePickerNavigationControllerDelegate Protocol Reference.- Add import statements for the AddressBook
frameworks:
<AddressBook/AddressBook.h> <AddressBookUI/AddressBookUI.h>
- Locate the following
line:
Update the line to include the delegate:@interface ContactsViewController : UIViewController
@interface ContactsViewController : UIViewController <ABPeoplePickerNavigationControllerDelegate>
- Save the changes.
- Add import statements for the AddressBook
frameworks:
- 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. ThepeoplePickerNavigationController:shouldContinueAfterSelectingPerson
method displays the contact, when one is selected by the user and the picker is dismissed. ThepeoplePickerNavigationController: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; }
- In the ContactsViewController.m file, update activity lifecycle methods to
call and close the people picker.
- Add import statements for the following files:
- AuroraWLHybrid.h
- CDVAppDelegate.h
- NativePage.h
- Create the following instance
variables:
ABPeoplePickerNavigationController *peoplePicker; MyAppDelegate *myAppDelegate;
- Add the
init
,onBeforeShow
, andonAfterShow
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]; }
- In the
viewDidLoad
method, configure theABPeoplePickerNavigationController
and add the view to the delegate. Add the following lines toviewDidLoad
:[peoplePicker setDisplayedProperties:[[NSArray alloc] initWithObjects:[[NSNumber alloc] initWithInt:kABPersonAddressProperty], nil]]; [peoplePicker setPeoplePickerDelegate:self]; [self.view setAlpha:0.0]; [myAppDelegate.window addSubview:self.view];
- Add import statements for the following files:
- Save the changes to the ContactsViewController.m file.
Integrating the native map display
- 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). - Add the MapKit framework to the Xcode project.
- In MapViewController.h, add import statements for the MapKit framework and
update the interface to include the
MapViewDelegate
.- Add an import statement for
<MapKit/MapKit.h>
. - Update the interface definition to include the
MKMapViewDelegate
. Locate the following line:
Update it to include the delegate:@interface MapViewController : UIViewController
@interface MapViewController : UIViewController <MKMapViewDelegate>
- 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;
- Save the changes.
- Add an import statement for
- In the MapViewController.m, update and add activity lifecycle methods to
call and close the native map.
- Add import statements for:
- NativePage.h
- CDVAppDelegate.h
- MapKit/MapKit.h
- 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;
. - 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];
- Implement the view lifecycle and data methods in
viewDidUnload
by adding the following methods to the class: TheviewDidAppear
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. ThesetDataFromWebView
method sets the physical store properties from the data that is sent from the web view. ThecreateSubtitle
method displays the map annotations when clicked. ThehideMapView
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]; }
- Save the changes.
- Add import statements for:
- 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.
- Add a Navigation Bar to the top of the view.
- Add a Bar Button Item to the Navigation Bar.
- Add a MapView to the view and size it so that it occupies the remaining area below the Navigation Bar.
- From File's Owner, assign the outlets for the user interface objects:
- Assign the backButton outlet to the Bar Button Item
- Assign the mapView outlet to the Map View.
- Assign the navBar outlet to the Navigation Bar.
- Assign the Received Actions for hideMapView to the Bar Button Item.
- Save the changes.
Updates to storefront files to invoke native features
- WC_eardir/Stores.war/storedir/WorklightHybrid/common/js
- WCDE_installdir/Stores/storedir/WorklightHybrid/common/js
- Update the iOS hybrid application properties files with the native class names corresponding to
your classes.
- Open the following file:
- WC_eardir/Stores.war/storedir/WorklightHybrid/ios/js/WCHybridAppProperties.js
- WCDE_installdir/Stores/storedir/WorklightHybrid/ios/js/WCHybridAppProperties.js
- 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 namedMapViewController
with your implementation of the native page. Add or change the properties in WCHybridAppProperties.js.
- Open the following file:
- Update the DisplayMap.js file to pass an extra store locator title
parameter from the web view to the native view.
- Open the following file:
- WC_eardir/Stores.war/storedir/WorklightHybrid/common/js/DisplayMap.js
- WCDE_installdir/Stores/storedir/WorklightHybrid/common/js/DisplayMap.js
- 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 };
- Add
storeLocatorTitle: document.title
so that the resulting code resembles the following:var localInfo = { ... storeAddress3: address3, storeLocatorTitle: document.title };
- Save the file.
- Open the following file:
Troubleshooting
- When you update the files in Worklight Studio under the
- Exit Xcode.
- Return to Worklight Studio, perform a build of the iPhone environment.
- Right-click the iphone environment, select to relaunch Xcode.
path, followed by a , files in the Xcode project might not be refreshed until the project is reloaded. Do
the following: - 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:- Open the following file:
- WC_eardir/Stores.war/storedir/mobile30/ShoppingArea/CheckoutSection/OrderBillingAddressSelection.jsp
- WCDE_installdir/Stores/storedir/mobile30/ShoppingArea/CheckoutSection/OrderBillingAddressSelection.jsp
- Locate the following
line:
<html xmlns="http://www.w3.org/1999/xhtml" lang="${shortLocale}" xml:lang="${shortLocale}">
- 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>
- 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. - Save the file.
- Open the following file: