Feed the label with data from an OData stream.
So far the tutorial have assigned a static text to the label. This task feeds the label with data coming from an OData stream, fetched via the Internet from a server.
This example uses the NorthWind endpoint: http://services.odata.org/Northwind/Northwind.svc/
The OData feed contains a set of collections; this example uses only the "Customers" collection.
<?xml version="1.0" encoding="UTF-8"?> <MAF xmlns="http://schemas.sap.com/maf/2012/cfg"> <!-- Define a binding ID - you can name it as you wish - it's recommended to keep it in synch with the collection name --> <!-- We are going to use this binding ID to refer to this collection throughout the XML --> <Binding bindingId="CustomersCollection" type="collection"> <!-- the boType must match the collection href in the OData feed: ?xml version="1.0" encoding="utf-8" standalone="yes"?> <service xml:base="http://services.odata.org/Northwind/Northwind.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app"> <workspace> ...skipped for brevity <collection href="Customers"> <atom:title>Customers</atom:title> --> <P pid="boType" value="Customers"></P> </Binding> <!-- Define a "tile" - it translates to UIViewController --> <Tile tileId="First Extensible Screen"> <!-- skipped for brevity --> This example displays the customer's name from the OData entry identified by the CompanyName property, which is part of the Customers collection. Next, add the binding reference to the tile: <!-- Define a "tile" - it translates to UIViewController --> <Tile tileId="First Extensible Screen"> <!-- This is our root view --> <P pid="isRoot" value="true"/> <!-- Reference to the data binding which provides data for this tile --> <!-- Note that we are using the bindingId here --> <BindingRef ref="CustomersCollection"/>
The label's text is fed with data coming from the binding:
<!-- Define a label which shows the customer company name --> <UIElement type="label"> <!-- The label text is showing real data coming from the OData feed http://services.odata.org/Northwind/Northwind.svc/Customers: <link rel="self" title="Customers" href="Customers" /> ...details skipped for brevity <entry> <category term="NorthwindModel.Customer" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> <content type="application/xml"> <m:properties> <d:CustomerID m:type="Edm.String">ALFKI</d:CustomerID> <d:CompanyName m:type="Edm.String">Alfreds Futterkiste</d:CompanyName> <d:ContactName m:type="Edm.String">Maria Anders</d:ContactName> <d:ContactTitle m:type="Edm.String">Sales Representative</d:ContactTitle> <d:Address m:type="Edm.String">Obere Str. 57</d:Address> <d:City m:type="Edm.String">Berlin</d:City> <d:Region m:type="Edm.String" m:null="true" /> <d:PostalCode m:type="Edm.String">12209</d:PostalCode> <d:Country m:type="Edm.String">Germany</d:Country> <d:Phone m:type="Edm.String">030-0074321</d:Phone> <d:Fax m:type="Edm.String">030-0076545</d:Fax> </m:properties> </content> </entry>
Note that the company name is retrieved from the first entry.
--> <P pid="text" value="Company: {$CustomersCollection.CompanyName}"></P> <P pid="halign" value="center"></P> <P pid="margin_top" value="20pt"></P> <P pid="style" value="CustomLabel"></P> </UIElement>
The {$CustomersCollection.CompanyName} syntax refers to the company name. Curly brackets indicate that the content must be evaluated by the Extensibility Framework. The $ sign denotes a binding (or expression), followed by the collection and the entry name separated by a period.
The layout_phone.xml you have now:
<?xml version="1.0" encoding="UTF-8"?> <MAF xmlns="http://schemas.sap.com/maf/2012/cfg"> <!-- Define a binding ID - you can name it as you wish - it's recommended to keep it in synch with the collection name --> <!-- We are going to use this binding ID to refer to this collection throughout the XML --> <Binding bindingId="CustomersCollection" type="collection"> <!-- the boType must match the collection href in the OData feed: ?xml version="1.0" encoding="utf-8" standalone="yes"?> <service xml:base="http://services.odata.org/Northwind/Northwind.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app"> <workspace> ...skipped for brevity <collection href="Customers"> <atom:title>Customers</atom:title> --> <P pid="boType" value="Customers"></P> </Binding> <!-- Define a "tile" - it translates to UIViewController --> <Tile tileId="First Extensible Screen"> <!-- This is our root view --> <P pid="isRoot" value="true"/> <!-- Reference to the data binding which provides data for this tile --> <!-- Note that we are using the bindingId here --> <BindingRef ref="CustomersCollection"/> <!-- Define the layout container. All UI elements included in a layout container will be auto-arranged --> <LinearContainer layout="vertical"> <!-- Define our label --> <UIElement type="label"> <!-- Assign a static text to be displayed --> <P pid="text" value="Hello World! This is Extensibility!"></P> <P pid="halign" value="center"></P> <P pid="margin_top" value="20pt"></P> <P pid="style" value="CustomLabel"></P> </UIElement> <!-- Define a label which shows the customer company name --> <UIElement type="label"> <!-- The label text is showing real data coming from the OData feed http://services.odata.org/Northwind/Northwind.svc/Customers ...details skipped for brevity Note that the company name is retrieved from the first entry. The remaining entries could be visualized as well using a ListContainer (UITableViewController), see Chapter 4.2.6 'Managing Lists' --> <P pid="text" value="Company: {$CustomersCollection.CompanyName}"></P> <P pid="halign" value="center"></P> <P pid="margin_top" value="20pt"></P> <P pid="style" value="CustomLabel"></P> </UIElement> </LinearContainer> </Tile> </MAF>
#import <UIKit/UIKit.h> @class ViewController; // SDMDataSource forward declaration @class SDMDataSource; @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow* window; // our data source facade @property (strong, nonatomic) SDMDataSource* dataSource; @end Add these headers to your AppDelegate.m: #import "MAFSDMDataSourceAdapter.h" #import "SDMDataSource.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // set the path for our custom styling XML [MAFCore sharedInstance].applicationSpecificStylePath = [[NSBundle mainBundle] pathForResource:@"CustomStyles" ofType:@"xml"]; // Configure the data source // Set the endpoint URL [SDMDataSource setBaseURL:@" http://services.odata.org/Northwind/Northwind.svc/"]; // If the server requires authentication, set the username and the password // Commented out since the server used in this example does not require authentication // [SDMDataSource setUsername:@"username"]; // [SDMDataSource setPassword:@"password"]; // Set request type to plain HTTP [SDMDataSource setRequestType:SDMHTTPRequestType]; self.dataSource = [[SDMDataSource alloc] init]; // establish connection with the OData Server, fetch and parse the OData Service Doc and metadata - see odata.org for details [self.dataSource loadModel:^(NSError* error) { // OData SVC and metadata fetched and parsed if( !error ) { // instantiate the data source adapter MAFSDMDataSourceAdapter* datasourceAdapter = [[MAFSDMDataSourceAdapter alloc] init]; // Start the Extensibility engine [[MAFCore sharedInstance] loadWithWindow:self.window datasourceAdapter:datasourceAdapter andCompletionBlock:^(NSError* error) { // Extensibility engine started successfully if( !error ) { // Display an alert view [[[UIAlertView alloc] initWithTitle:@"Success!" message:@"Extensibility is Up and Running!" delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil, nil] show]; NSLog( @"Extensibility is Up and Running!" ); } // Extensibility engine failed to start! else { NSLog( @"Extensibility load failure. Details:%@", error.description ); } }]; } else { NSLog( @"Could not load OData model. Details: %@", error.description ); } }]; return YES; }
This example uses another API to instantiate and load the extensibility engine, and this API requires a valid data source adapter instance. This approach allows passing in a custom data source adapter, but the default implementation works correctly for OData.
This setup is all you need to build an extensible app that does not require custom hooks or mixing native UIs with UIs that are defined via metadata. From this point on, you need only enhance the layout_phone.xml to define new tiles, UI elements, bindings and so on.
Running the app shows this screen:
Loading time increases slightly because the app is fetching data from a remote server, however, depending on your network speed and OData endpoint load, the increase should not be more than a couple of seconds.