Manual synchronization can be set as the Synchronization criteria for Offline Native Mobile applications with the Data Receive Criteria property.
Note: This document aims to explain how to perform a full manual synchronization between the device and the server tables, which means, avoiding the synchronization programs automatically generated by GeneXus (first bits of GeneXus Tilo does not include this option). So, before continuing with this approach, consider using
Automatic Sync or
Manual sync with automatically generated programs To explain how to do this synchronization some code example was taken from the
Sales with manual synch example
The following are the main actions to complete the synchronization.
- Master Tables Service Layer.
- Invoke Master Services.
- Triggering of the Synchronization process.
- Event Tables Service Layer
- Send Events to the Server.
This is the Rest services exposed on the Web Server so that the devices can get the Master data they need to start working.
For example, to expose the Customer Master table the following is needed:
- SDT based on the Customer Transaction.
- Data Provider which will return all or a part of the registers of this TRN
SDTCustomer
{
CustomerId
CustomerName
CustomerAddress
CustomerPhone
CustomerLocation
CustomerDistanceToMe
}
This Data Provider will return a collection of SDTCustomers; in this case, returns all the registers of the Customers.
To enable this data provider to be exposed as a Rest service it is needed to set a property explained here. Lastly set the Web Service Protocol to REST Protocol.
These are the Objects needed to execute the services of the Master data service layer and insert the data into the device. This code will be executed 100% on the device.
A procedure with the following code can be created.
For each Customer
delete
Endfor
Delete all the Customers on the local database. Other strategies may vary and can do incremental synchronizations. In this case, the tables are deleted before the Master Synchronizations.
GetParameters.Call(&serverprotocol, &serverHost, &serverBaseURL, &serverRestBaseURL, &serverPort)
The GetParameters procedure retrieves the parameters of the HttpClient data type. The values can be as the following:
&serverprotocol = "http"
&serverHost = "apps3.genexusx.com"
&serverBaseURL= "/Idfe4nFfdfFwf4jf442nvanaf4r3rn904Faf/"
&serverRestBaseURL = "/Idfe4nFfdfFwf4jf442nvanaf4r3rn904Faf/rest/"
&serverPort = 80
Initial set up of the HTTPClient Object in order to consume rest services from the service layer.
&httpclient.Host = &serverHost.Trim()
&httpclient.Port = &serverPort
&httpclient.BaseUrl = &serverRestBaseURL.Trim()
&httpclient.AddHeader(!'Content-type',!'application/json')
&httpclient.Execute(!'GET', !'GetAllCustomers?fmt=json')
The Rest Service is invoked, GET method is used to retrieve the resource GetAllCustomers created in step 1. The String returned, in json format, is going to be stored on the &httpclient variable.
&customerslist.FromJson(&httpclient.ToString())
&customerlist is a variable based on the SDT created on 1.a. The FromJson method will load the variable with all the registers brought by the server, this can only be done because the rest service returns a json representation of the same SDT.
For &Customer in &CustomersList
&CustomerBC = new()
&CustomerBC.CustomerId = &Customer.CustomerId
&CustomerBC.CustomerName = &Customer.CustomerName
&CustomerBC. CustomerAddress = &Customer.CustomerAddress
&CustomerBCCustomerPhone = &Customer.CustomerPhone
&CustomerBC.CustomerLocation = &Customer.CustomerLocation
&CustomerBC.CustomerDistanceToMe = &customer.CustomerDistanceToMe
&CustomerBCCustomerVisited = False
&CustomerBC.Save()
endfor
Iterate through the &CustomersList and insert via BusinessComponent all the Customers on the local database.
The reasons for using Business Component can be seen on the Best Practices for Manual Synchronization.
commit
The final instruction to commit the changes of the insertion on the local database.
As seen before the synchronization is always started by the device. The developer has to choose whether the user can consciously trigger this action (for example by tapping on a Load Data or Synchronize button) or unconsciously (for example, by entering to a screen the synchronization is triggered). Either way there this code is triggered on the Smart Device (the client side).
The User Event to Load Data can be like the following:
Event 'Load Master Data'
Composite
ProgressIndicator.Title = "Data synchronization..."
ProgressIndicator.Description = "Checking connectivity..."
ProgressIndicator.Type = 0
ProgressIndicator.Show()
&server = getServerFromParameters() // returns the URL of the server host where the synchronization is going to be made
&IsConnected = NetWorkAPI.IsServerAvailable(&server)
if &isConnected
ProgressIndicator.Description = "Retrieving data from server..."
&result = SyncReceive()
/******************************************************************************************************
Note: If the device is connected to the server then the synchronization can be done. In some
scenarios, you will also want to check which connection is used to see if there are synchronizations
which need or not wifi or 3g, etc. This can be done using [[Network external object]]
*******************************************************************************************************/
else
&result = "No connection detected"
endif
ProgressIndicator.Hide()
msg(&result)
Endcomposite
Endevent
The Transactions that generate the Event Tables are also going to be on the web server application. So the easiest way to generate the service to insert/update registers online is the Transaction itself. This is done with the expose as web service property of the Transaction which will expose the Transaction's CRUD services for the REST protocol.
The insert service for PurchaseOrder will be:
<host>/<baseUrl>/rest/PurchaseOrder/0
example:
http://apps3.genexusx.com/Idfe4nFfdfFwf4ja42nvanaf4r3rn904Faf/rest/PurchaseOrder/0
This step is going to send to the web server (and insert there ) the data saved locally to the Event Tables. Following the sample and in order to do that, a POST to the PurchaseOrder REST service has to be executed for each record of that transaction.
After the &httpclient variable is initialized like in step 2, code the following:
&ServerPOrder = LoadPurchaseOrder()
Load all the Purchases Orders that were added to the offline database. &ServerPOrder is based on an SDT based on the Transaction ServerPOrder.
For &ServerPOrderItem in &ServerPOrder // Iterate through the Purchase Orders loaded from the local database.
&body = &ServerPOrderItem.ToJson() // Get the JSON representation of the Purchase Orders.
&httpclient.AddString(&body) // Attach the body to the HTTP POST.
&httpclient.Execute(!'POST', !'PurchaseOrderSrv/0') // Execute to insert the purchase order on the server
If &httpclient.StatusCode = 201 or &httpclient.StatusCode = 200
//Succesfull Post
else
//Error in Post
Endif
Endfor
The rest of the code can be found on Sales with manual synch example
Note: Sales Force Offline Example also shows how to synch Multimedia, specifically Image data type fields.