Monday, July 16, 2018

Convert iOS app bundle (.app file) to ipa file

When xcode builds a project, it generates an app bundle as output. In order to install the app bundle to iOS device, the app bundle file needs to be converted to a ipa file.

The following steps can be used to convert app bundle to ipa file
1. Create a folder named as "Payload"
2. drag and drop the app bundle file (myapp.app file) into Payload folder. You can get the .app file from xcode derived folder
3. Compress the payload folder to a zip file
4. Rename the zip file to ipa file


Saturday, July 7, 2018

Understanding SAP UI5 view navigation and routing

SAP UI5 application manifest.json file defines targets and routes to manage page (view) navigation.

Usually, there is a root xml view, which does not contain any UI content, its only purpose is define an App id for holding other xml views

Root.view.xml

<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" controllerName="ui5.test.ui5.controller.Root"
xmlns:html="http://www.w3.org/1999/xhtml">
<App id ="root">
<pages/>
</App>
</mvc:View>  

The real UI are defined in several xml views. For example, an app may define three views
MainView.view.xml
SecondView.view.xml
ThirdView.view.xml

For each view, a target should be defined, which has below properties:
name:
target name is used by route to identify a unique target.
viewName:
indicates when this target is selected, which view will be displayed.

Then for each navigation operation, a route should be defined. Route name is used by navTo method to navigate the application to different xml view.

Route has the below properies
name:
unique name.
Target:
The target to show for the route.
Pattern:
the matched url pattern for selecting a particular route. The first pattern should be empty, so the route will be used to load the default xml view if not url available to select a particular route. Pattern can also include parameter, which can be set and got by view controller.

In view controller, javascript code can call navTo on router object to load a particular route based on name. For example: the below code load "ThirdViewTarget"
onShowThirdView: function (oEvent) {
//This code was generated by the layout editor.
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("ThirdViewTarget");
},

navTo method can also include parameter for passing context information to the target view as below
onListItemPressed: function (evt) {
 
// Get Property of the Clicked Item. i.e. PO number of the item which was clicked
var selectPO = evt.getSource().getBindingContext().getProperty("ProductID");
 
// Now Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
 
// Tell the Router to Navigate To Route_PODetail which is linked to V_PODetail view
oRouter.navTo("SecondTarget", { ProductID: selectPO});
}


The sample manifest.json is attached below:
{
"_version": "1.8.0",
"sap.app": {
"id": "ui5.test.ui5",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"sourceTemplate": {
"id": "servicecatalog.connectivityComponentForManifest",
"version": "0.0.0"
},
"dataSources": {
"Northwind.svc": {
"uri": "/John/NorthwindDest/v2/Northwind/Northwind.svc/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone@2": "",
"tablet": "",
"tablet@2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": ["sap_hcb", "sap_belize"]
},
"sap.ui5": {
"rootView": {
"viewName": "ui5.test.ui5.view.Root",
"type": "XML"
},
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "ui5.test.ui5.i18n.i18n"
}
},
"": {
"uri": "/John/NorthwindDest/v2/Northwind/Northwind.svc/",
"type": "sap.ui.model.odata.v2.ODataModel",
"settings": {
"defaultOperationMode": "Server",
"defaultBindingMode": "OneWay",
"defaultCountMode": "Request"
},
"dataSource": "Northwind.svc",
"preload": true
}
},
"resources": {
"css": [{
"uri": "css/style.css"
}]
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "ui5.test.ui5.view",
"controlAggregation": "pages",
"controlId": "root",
"clearControlAggregation": false,
"viewLevel": 0,
"bypassed": {
"target": []
}
},
"routes": [{
"name": "MainTarget",
"pattern": "",
"titleTarget": "",
"greedy": false,
"target": ["MainTarget"]
}, {
"name": "SecondTarget",
"pattern": "second/{ProductID}",
"titleTarget": "",
"greedy": false,
"target": ["SecondTarget"]
}, {
"name": "ThirdViewTarget",
"pattern": "third",
"titleTarget": "",
"greedy": false,
"target": ["ThirdViewTarget"]
}],
"targets": {
"SecondTarget": {
"viewType": "XML",
"transition": "slide",
"clearControlAggregation": true,
"viewName": "SecondView",
"viewLevel": 2,
"routerClass": "sap.m.routing.Router",
"async": true,
"viewPath": "ui5.test.ui5.view",
"controlAggregation": "pages",
"controlId": "root",
"bypassed": {
"target": []
}
},
"MainTarget": {
"viewType": "XML",
"transition": "slide",
"clearControlAggregation": true,
"viewName": "MainView",
"viewLevel": 1,
"routerClass": "sap.m.routing.Router",
"async": true,
"viewPath": "ui5.test.ui5.view",
"controlAggregation": "pages",
"controlId": "root",
"bypassed": {
"target": []
}
},
"ThirdViewTarget": {
"viewType": "XML",
"transition": "slide",
"clearControlAggregation": true,
"viewName": "ThirdView",
"viewLevel": 2
}
}
}
}
}