Delphi Mobile Point of Sale Software - Felix John COLIBRI. Using FireBase, FireDac, DataSnap, Rest, Wifi, and FireMonkey abstract : Android tablet or smartphone point of sale application using a WIFI connection to a DataSnap REST Server connected with FireDac to a FireBird database



: Android tablet or smartphone point of sale application using a WIFI connection to a DataSnap REST Server connected with FireDac to a FireBird database key words : Android, WIFI, point of sale device, REST Client, REST Server, JSON, DataSnap methods, FireDac, FireBird



: Android, WIFI, point of sale device, REST Client, REST Server, JSON, DataSnap methods, FireDac, FireBird software used : Windows XP Home, Delphi XE7, Android 4.3



: Windows XP Home, Delphi XE7, Android 4.3 hardware used : Pentium 2.800Mhz, 512 M memory, 140 G hard disc, Samsung Galaxy Nexus, Android 4.3



: Pentium 2.800Mhz, 512 M memory, 140 G hard disc, Samsung Galaxy Nexus, Android 4.3 scope : Delphi Xe6 to Xe8, Delphi Seattle, Delphi Berlin



: Delphi Xe6 to Xe8, Delphi Seattle, Delphi Berlin level : Delphi developer



: Delphi developer plan :

WIFI Point of Sale devices

The Rest Server

The Desktop VCL Rest Client

The Mobile Rest Client

Download the Sources



: 1 - WIFI Point of Sale devices For Shop management, data is usually centralized in some database, but the shop workers move around the shop and must have access to this database. Wifi is quite adapted to solve this kind of problem. From a Delphi point of view, this can be implemented using Firemonkey for the Client mobile device (smartphone, tablet, dedicated mobile device)



REST services for communications between the client and the server



to offer those services from the server, FireBase as a database, FireDac for data access, DataSnap as a REST server and Json for packet formatting





The objective is to display on a tablet the content of one or several table contents. The mobile device will interrogate a Server who which will load the data and send it over to the Client.



In this article we will present the structure of such a REST Server / REST clients architecture : the Rest Server



a Rest Client on a PC using the VCL



a Rest Client using FireMonkey for the shop workers





2 - The Rest Server 2.1 - The choice of the components The Database can be any database. We chose FireBase which is installed in 3 minutes sharp and, according to some surveys, is the most popular database for Delphi users. But you can use Oracle, Sql Server, Postgres, Interbase, MySql etc. To communicate with the Clients, the Server can use any transfer protocol. However this protocol must be compatible with the mobile devices, and, in this case, Rest is a good solution. To implement Rest services, a Tcp Server could be used. We would have to handle the marshalling / unmarshalling of the objects ourselves. Here comes JSon, which was just created for this very purpose: transfer objets from one place to the other. And for JSon, FireDac offers an out of the box library. Finally the Client must be able to request the data. If the data is in the form of objects, DataSnap with methods (function returning objects in our case) can be used.



2.2 - Building the DataSnap Rest Server Four your comfort, initialize the folder of your projects: start delphi

select "Tools | Options" and in "Default Project:", fill the project folder name and click "Ok"





To create the Rest Server select "File | New Other"

Delphi displays all the projects available select "DataSnap Server"

all available servers are displayed select "DataSnap Rest Application" and click "Ok"

Delphi asks what kind of WebBroker Application we want to create we prefer to use the Indy Tcp Server. So select "Stand Alone" and click "Next"

Delphi ask us if we want "Vcl" or "FireMonkey" for the Rest Server, keep "Vcl" selected and click "Next"

Delphi asks about the Port of this Web Server when clicking "test port", in our case 8080 was used. So we selected 8081 and click "test port" again:

the port can be used click "Ok" and "Next"

Delphi asks us which features we want in our case, no authentication, and we keep, for this tutorial, the sample DataSnap method (a "reverse string" method). So keep the defaults and click "Next"

Delphi can add a tDataModule select "tDataModule" and click "Next"

Delphi proposes the project folder navigate to your projects folder and click "Finish"

Delphi builds the necessary files and presents the Server Form





2.3 - The WebBroker Rest Server Units The first step is to save all the generated files click "Save Project"

save "FormUnit1.Pas" as "u_server_main.pas". This is the tForm that will be displayed on the desktop, allowing the user to start and stop the server

save "WebModuleUnit1.pas" as "u_web_module.pas"

save "ServerMethodsUnit1.pas" as "u_server_methods.pas"

save "Project1.dproj" as "p_12_rest_server.dproj"

And u_server_main.pas will start / stop the server, and can be used to launch a web browser for test purposes





u_web_module.pas contains all the components which manage the Rest Server. It contains the basic DataSnap Server components, plus the components used by the Rest type of Server





u_server_methods.pas is a tDataModule containing all the methods the Rest Server will offer to its clients. In Our case, the Wizard has prepared two functions, EchoString and ReverseString . Unit u_server_methods ;

Interface

Uses System . SysUtils , System . Classes , System . Json ,

Datasnap . DSServer , Datasnap . DSAuth ,

DataSnap . DSProviderDataModuleAdapter ;

Type

{$METHODINFO ON}

TServerMethods1 =

Class ( TDataModule )

Private

Public

Function EchoString ( Value : string ): string ;

End ;

{$METHODINFO OFF}

Implementation

{$R *.dfm}

Uses System . StrUtils ;

Function TServerMethods1 . EchoString ( Value : string ): string ;

Begin

Result := Value ;

End ; // EchoString

End .

Notice the tDataModule ancestor

the $METHODINFO compiler directive which enables the Server to call our methods



containing all the methods the Rest Server will offer to its clients. In Our case, the Wizard has prepared two functions, and .



Compile the project. Since we changed the Server Methods unit name, we must change the same name in the u_web_module.pas So change all ServerMethodsUnit1 identifiers into u_server_methods (3 occurences)





Eventually unblock the Windows lock :



2.4 - Test the Rest Server The main form can be used to start the server and open a browser to test all DataSnap methods. To test "reverse string" run the project

the server form is displayed click "Start"

the Tcp Server is started ("start" and the port are grayed)

click "Open Browser"

the default browser is opened with the

http://localhost:8081/

URL clicking on "Reverse String" calls the WebBroker default action and reverses the string

to see the other available functions, click the "Server Functions" hyper link

two groups of methods are displayed; Admin and ServerMethods click ON THE PLUS before "TServerMethods" (yes, it is a pale gray on a pale blue plus button) all the available methods are displayed to test the "ReverseString" method, click the "+" before "ReverseString" (just as difficult to see as the other "+" on this form) an edit for typing the parameter of the function are presented type a string, say abcd the result of the method are presented





Note it would have been hard to better hide the test functions then they did. We did not see the "+" sign, until we read about them in the doc



to stop the server, you cannot use "Ctrl F2". Use the "Stop" button and then close the Server form



the test .HTML pages have been generated by the two tPageProducers which are on the tWebModule. Those .HTML page also use all the css\, images\ js\ and templates\ displayed in the project manager. Those files would not be necessary for a simple REST server.





2.5 - The DataSet transfer Rest method Our Rest Server is going to send the content of some Table to its clients. We chose the Delphi "MastApp" database, and will use the CUSTOMER table



the ORDERS table (with a CUSTNO foreign key)



the ITEMS table (with an ORDERNO foreign key)

You can dowload the .ZIP of this Database If you select another database, just find 2 or 3 tables with a master / detail relationship. We added the Sql Scripts to allow you to create and fill those tables.



Copy the database near the Server: create a _data\ folder

copy the MASTAPP_25.FDB base there





We will start with a client which will display the CUSTOMER ( CUSTNO, COMPANY ) table.



2.6 - The Firedac components To read and write the tables, we will use FireDac. First we initialize the link to the FireBird driver : select the u_server_methods unit from the Tool Palette, drop a tFDGUIxWaitCursort on the DataModule then drop a tFDPhysIBDriverLink

double click on the DataModule to create its OnCreate method and initialize the driver's DriverId, VendorHome and VendorLib Properties by code : Procedure TServerMethods1 . DataModuleCreate ( Sender : TObject );

Begin

With FDPhysIBDriverLink1 Do

Begin

DriverId := 'FB25' ;

VendorHome := 'C:\Program Files\Firebird\Firebird_2_5' ;

VendorLib := 'fbclient.dll' ;

End ; // with ADPhysIBDriverLink1

End ; // DataModuleCreate



Please note: we hard coded the location of our FireBird 2.5 fbclient.dll location



if you use another version of Firebird, or Firebird was installed in another folder, adjust the code accordingly



we also assume a 32 bit PC. If you use a 64 bit PC, you should change the Firebird Client .DLL also



you could also initialize the FireDac driver using the FdDrivers.Ini file. This has been explained in great detail in the following Delphi FireDac Connection article



article of course, if you use another database engine, you should use the matching initialization code





To initialize the database connection drop a tFdConnection on the DataModule

in the DataModuleCreate event, add this code which essential fills the tFdConnection Params property: Procedure TServerMethods1 . DataModuleCreate ( Sender : TObject ) ; //

Begin

// o o o

With FdConnection1 Do

Begin

Close ;

With Params Do

Begin

Add ( 'DriverID=IB' );

Add ( 'Server=localhost' );

Add ( 'Database= C:\prog\delphi_6\2014_xe7\13_mobile_pos\_data\Mastapp_25.fdb' );

Add ( 'User_Name=SYSDBA' );

Add ( 'Password=masterkey' );

End ; // with Params do

LoginPrompt := False ;

Open ;

End ; // with FdConnection1

End ; // DataModuleCreate







Note that the connection cannot be tested, but we will create a Server Method to test it





Finally, we add a tDataSet drop a tFdQuery on the DataModule, rename it fd_customer_query, and in it's Sql property type

SELECT custno, company

FROM customer



2.7 - Test of the Database Connection The easiest way to test the connection and the query is to build a DataSnap function : in the u_server_methods unit, in the tServerMethods Class add the following definition: Function f_test_connection : string ;

type Shift Ctrl C to create the implementation and fill the body: Function TServerMethods1 . f_test_connection : string ;

Begin

FDConnection1 . Open ;

If FDConnection1 . Connected

Then Begin

Result := 'connected' ;

FdQuery1 . Open ;

If FDQuery1 . Active

Then Result := Result + ' fdQuery Open'

Else Result := Result + ' *** fdQuery Closed' ;

End

Else Result := '*** connection pb' ;

End ;

run, start the server, open the browser, click on the function invoker link, open the TServerMethod, click on the "+" before f_test_connection, click "EXECUTE" the database is connected and the query opened:





2.8 - The Server Method returning a tDataSet The Client will ask for the CUSTOMER dataset. This resource will be sent over as the result of a DataSnap function. To marshall (send over as a stream) the dataset, we will use the Json formatting. Our CUSTOMER ( CUST_NO, COMPANY ) table will be formatted as : For the illustration, we indented the JSON text, but usually it does not contain spaces (the punctuation is enough to parse the format) :



This dataset formatting will be performed by FireDac components : select the u_web_module

from the Tool Palette

select a tTFDStanStorageBin and drop it on the module



and drop it on the module select a tFDStanStorageJSON and drop it on the module





Now we will add the DataSnap Method: select the u_server_methods datamodule

in the tTServerMethods1 Class, add this function : Function f_c_get_customer_name_list : TFDJSONDataSets ;

since the tFDJSONDataSets is unknown (the red wriggles), add the Data.FireDACJSONReflect to the Interface Uses clause: with the cursor between Class and End, press Shif Ctrl Click to create the function body, and type this code: Function TServerMethods1 . f_c_get_customer_name_list : TFDJSONDataSets ;

Begin

// -- Clear active so that query will reexecute.

fd_customer_query . Active := False ;

Result := TFDJSONDataSets . Create ;

// -- convert the Query Answer Set into a JSON DataSet

TFDJSONDataSetsWriter . ListAdd ( Result , fd_customer_query );

End ; // f_c_get_customer_name_list







To explain the function content : FireDac has a tFDJSONDataSetsWriter Class with a ListAdd Class function.



with a ListAdd function. we can add one or several queries to this Class



when requested, the writer will convert the queries Answer Sets into the tFDJSONDataSet using RTTI (Reflection, in Java parlance).





2.9 - Keep the Server running So the server is running. To be able to import the tDataSet in a Rest client, the server must be running. So start the server with "Run Without Debugging", or alternately from the File Explorer (the .EXE is located in Win32\Debug\ path (relative to the .DPR)



3 - The Desktop VCL Rest Client 3.1 - The first Client We will start with a standard Windows VCL Client. To build the client launch Delphi, and select "File | New | Vcl Application"

a standard VCL application is created

save the project and unit in a Client_VCL\ folder under u_client_vcl and p_13_rest_vcl_client

run the project to make sure everything is ok





3.2 - The Client Rest import unit To build the Rest import unit make sure the Rest Server is running. The server will be called by the Delphi IDE to import the classes and method definitions

add the import units by selecting "File | New | Other | DataSnap Server"

the Rest components are displayed. Since we are not creating a DataSnap server (we started a standard VCL project), the dialog now presents the DataSnap client units: select the "DataSnap Rest Client Module" and click "Ok"

the wizard asks to select the local or remote server for this VCL client located on the same PC, we keep the "Local Server" and click "Next"

the wizard asks what kind of server to use we keep the "DataSnap Stand Alone Server" and click "Next"

the wizard asks what the connection parameters are : we change the port to 8081 and click "test"

the parameters are correct we click "Ok" and "Finish"

the wizard has created the two import units.





The import units are the ClientClassesUnit1 which generates the DataSnap methods proxies



which generates the DataSnap methods proxies the ClientModuleUnit1 tDataModule with a TDSRestConnection component which will be uses as a TCP client





Rename both units change ClientClassesUnit1 into u_client_classes

add Data.FireDACJSONReflect to the Interface Uses clause

change ClientModuleUnit1 into u_client_datamodule. In this Unit, replace ClientClassesUnit1 with u_client_classes

Run the client and close it





And we must also add the FireDac JSON components to unmarshall the dataset: select the u_client_datamodule form

from the Tool Palette

select a tTFDStanStorageBin and drop it on the module



and drop it on the module select a tFDStanStorageJSON and drop it on the module





3.3 - Fetch the Customer from the Client To get the CUSTOMER ( CUSTNO, COMPANY ) from the Server, we must add a tDataSet to the client Form. In this case a memory dataset, since the content will be provided by the Rest Server



to the client Form. In this case a memory dataset, since the content will be provided by the Rest Server call the f_c_get_customer_name_list Function to fill the dataset.

Therefore, for the memory dataset ; select the u_client_form

from the Tool Palette, select a tFdMemTable, drop it on the form and rename it fd_customer_list_dataset

and for the filling procedure ; add the u_server_methods to the Implementation Uses clause

also add the Data.FireDACJSONReflect which contains the TFDJSONDataSets Class

in the Private section of tForm1 Class, add this Procedure declaration : Procedure get_customer_name_list ;

create the body (Shift Ctrl C) and type its content: Procedure TForm1 . get_customer_name_list ;

Var l_c_json_dataset_list : TFDJSONDataSets ;

Begin

// -- clear the dataset

fd_customer_list_dataset . Close ;

// -- fetch the dataset list from the Rest Server

l_c_json_dataset_list := ClientModule1 . ServerMethods1Client . f_c_get_customer_name_list ;

// -- read the first dataset of this list into the memory dataset

fd_customer_list_dataset . AppendData (

TFDJSONDataSetsReader . GetListValue ( l_c_json_dataset_list , 0));

// -- opent the customer_list dataset

fd_customer_list_dataset . Open ;

End ; // get_customer_name_list

compile the project (or





This procedure will be called from a tButton, and the result of the dataset displayed. Since the tFdMemDataSet is a tDataSet descendent, it is compatible with a tDataSource / tDbGrid. Therefore from the Tool PalEtte

drop a tDataSource component and set its DataSet to fd_customer_list_dataset



component and set its to drop a tDbGrid component and set its DataSource property to DataSource1

drop a tButton, fetch the data and display it in the grid : Procedure TForm1 . display_customer_list_Click ( Sender : TObject );

Begin

get_customer_name_list ;

End ; // display_customer_list_Click

run the Client and click display_customer_list_

here is the glorious result :





4 - The Mobile Rest Client 4.1 - The SmartPhone DataSnap Rest Client We will now add another Client which will run on a mobile device. We will demonstrate the case with an Android Smartphone (Samsung Nexus), but any other Android phone or tablet, or Apple iPhone or tablet would work, thanks to the "single code base" Delphi principle.



4.2 - The Mobile check This is not a paper about starting with Delphi Mobile programming. However just a couple of reminders check your Java pathes. We installed Delphi Xe7 asking to install the Java files. So they were all downloaded and copied into Program Files\ for the Java SDK

C:\Documents and Settings\All Users\Documents\Embarcadero\Studio\15.0\PlatformSDKs

for the Android SDK and NDK

You can check that Delphi can use those files with "Tools | Options | Environment Options | SDK Manager", where no combo should display a yellow triangle warning



You can check that Delphi can use those files with "Tools | Options | Environment Options | SDK Manager", where no combo should display a yellow triangle warning to deploy the Delphi build ARM code, the smartphone must be linked to the PC using an USB cable. When this cable is plugged into the PC, the phone asks whether you want to use USB debugging, which you should accept





4.3 - Testing the Android WIFI and connection 4.3.1 - WIFI connection Our smartphone uses WIFI to connect to our DataSnap Rest Server (USB for deployment, but WIFI for execution). Before diving into the FireMonkey code, it is important to test the connection.



Our REST Server and REST client behave in a classical Client / Server mode: the Server is started at some known IP, Port



the Client connects to this fixed IP, Port, and sends some request



the Server sends some answer back





4.3.2 - Assigning a Fixed IP to the Server The first thing is to assign a fixed IP, Port to the Server. Our server is located on a PC linked to a switch. This switch has a manager which displays the WIFI password



contains a DHCP server which allocates the devices IP.

The manager can be used to freeze the IP of one or several connected devices. The other devices are allocated random IPs. So we froze the Server IP, setting its value to 198.168.1.14. We can check this using IPCONFIG : The Port of our REST Server application was set when we created this Server with Delphi. It is 8081.



4.3.3 - Adding the Android device to the network The mobile device must be hooked to the WIFI network: the switch WIFI manager has a dialog displaying its WIFI parameters. In our case security WPA etc

password : some value, in our case a 26 byte Hex number, like 439F5 etc



we typed this password on the Android device, by selecting "settings | WIFI", in the WIFI servers in the area, selecting our WIFI network, and then entering the WIFI password





4.3.4 - Testing the Android connection Knowing the Client IP is not important. We can optionnally check it the Switch displays the IP of all WIFI connected devices. In our case the dynamically assigned IP was 192.168.1.20



we can also display the WIFI information including the device's IP on the smartphone itself. Those WIFI settings can be tested by a Delphi application using JNI (Java Native Interface) Classes. This not obvious, but Stack Overflow and Google allowed us to find the solution. Here is our Delphi Android app displaying the Android IP:

Knowing the Client IP, we can PING the device from the switch or from the Server;



4.3.5 - Testing the TCP Connection The most important is to be check that the Client can connect to the Server and send some requests. This test was performed using a tIdTcpClient which tries to Connect.



We used a small FireMonkey project with a tIdTcpClient, 2 edits, a button and a memo. Here is the main FireMonkey form code : Unit u_test_android_connection_to_server ;

Interface

Uses System . SysUtils , ...

, IdBaseComponent , IdComponent , IdTCPConnection , IdTCPClient

...

, FMX . Edit ;

Type TForm1 =

Class ( TForm )

Memo1 : TMemo ;

connect_ : TButton ;

IdTCPClient1 : TIdTCPClient ;

ip_edit_ : TEdit ;

port_edit_ : TEdit ;

Procedure connect_Click ( Sender : TObject );

Private

Public

End ;

Var Form1 : TForm1 ;

Implementation

{$R *.fmx}

{$R *.NmXhdpiPh.fmx ANDROID}

Procedure display ( p_text : String );

Begin

Form1 . Memo1 . Lines . Add ( p_text );

End ; // display

Procedure TForm1 . connect_Click ( Sender : TObject );

Var l_ip_port : String ;

Begin

With IdTCPClient1 Do

Begin

Host := ip_edit_ . Text ;

Port := StrToInt ( port_edit_ . Text );

ConnectTimeout := 2000; //2 secs

l_ip_port := Format ( 'Host %s : %s is ' ,

[ ip_edit_ . Text , port_edit_ . Text ]);

Try

Connect ;

display ( l_ip_port + 'reachable' );

Except

On e : Exception Do

display ( '*** ' + l_ip_port + 'UNreachable' );

End ;

Disconnect ;

End ; // with IdTCPClient1

End ; // connect_Click

End



And here is the successful result :



4.4 - The FireMonkey DataSnap REST Client 4.4.1 - The steps We must run the server



create the FireMonkey application



add the DataSnap method import units



write the user code





First, make sure the Rest Server is running. The server will be called by the Delphi IDE to import the classes and method definitions.



The FireMonkey client application steps are quite similar to the VCL client applications steps, with a couple of differences we must assign the Server IP



to display the data, we cannot use a tDbGrid which is Windows VCL specific, but will use FireMonkey controls





4.4.2 - The FireMonkey application To create the FireMonkey REST Client : start Delphi

select "File | New | Multi Device Application"

the FireUi multi device dialog is presented select "Blank Application" and click "Ok"

the Windows Master page of the multi designer is displayed (both left and right panel have been shrinked to display the central Master / View part) select the "Views" combo, display the available formats, and select "

all available form factors are presented select the "Android 4" form factor (or whatever view matching your Android device)

the phone look is displayed : select "File | Save Project As", create a folder client_Firemonkey\ and type u_android_client



zz_pos_client

We use the "zz_" prefix for our Delphi Android projects to display them at the end of the Android Application pages





To allow Delphi to send the Android ARM executable to the mobile device, connect the device to your developpment machine : connect the USB cable of your android device to the Delphi PC

the android device asks you to confirm the debug mode : "Allow Usb Debugging ?" touch "ok"

the status line displays the debugging icon brushing the finger down on the status line confirms this debugging mode : and the phone is displayed in the windows explorer Delphi can now deploy any FireMonkey to the Android device





Check that everything is Ok by running the project drop a Button on the Form

select the Android platform. In the project run the application (F9)

the compiler will display "compiling, linking, deploying, stripping symbols, packaging, installing" If the device is active, you will see our page with Button1. If the phone is in sleep mode, pushing "Power" will display the same thing. and the application is at the end of the application pages:





4.4.3 - The REST Client application We now add the REST import units: make sure the Rest Server is running. The server will be called by the Delphi IDE to import the classes and method definitions

add the import units by selecting "File | New | Other | DataSnap Server"

the Rest components are displayed. Since we are not creating a DataSnap server (we started a standard VCL project), the dialog now presents the DataSnap client units: select the "DataSnap Rest Client Module" and click "Ok"

the wizard asks to select the local or remote server for this FireMonkey client connected by WIFI, select the "Remote Server" and click "Next"

the wizard asks what kind of server to use we keep the "DataSnap Stand Alone Server" and click "Next"

the wizard asks what the connection parameters are : we type the 192.168.1.14 IP and change the port to 8081. Then click "test"

the parameters are correct we click "Ok" and "Finish"

the wizard has created the two import units.





Rename both units change ClientClassesUnit1 into u_client_classes

add Data.FireDACJSONReflect to the Interface Uses clause

change ClientModuleUnit1 into u_client_datamodule. In this Unit, replace ClientClassesUnit1 with u_client_classes

compile the client by typing Shift F9 (or "Project | Build")





Please note : the Android cross-compilation and Android deployment is rather lengthy. This is the reason we used "Build" rather than "Run"



even then, the compiling is still longer then the Windows compilation. It is possible to return to the Windows target platform until the project is complete, and then shift back to the Android target platform



as far as the import units are concerned, we could have copied the VCL DataSnap import unit, and changed the DsRestConnection1 host address. We can even test the connection by double clicking on this component :





4.4.4 - Add the FireDac JSON components And we must also add the FireDac JSON components to unmarshall the dataset: select the u_client_datamodule form

from the Tool Palette

select a tTFDStanStorageBin and drop it on the module



and drop it on the module select a tFDStanStorageJSON and drop it on the module





4.5 - Fetch the Customer from the Client We now must add a tDataSet to the client Form. Therefore : select the u_android_client_form

from the Tool Palette, select a tFdMemTable, drop it on the form and rename it fd_customer_list_dataset

To test the fetching of the data, we first will use a Memo : drop a tMemo on the tForm

write the display global Procedure which simply adds the text to the Form's Memo1 : Procedure display ( p_text : String );

Begin

Form1 . Memo1 . Lines . Add ( p_text );

End ; // display



and for the filling procedure : add the u_server_methods to the Implementation Uses clause

also add the Data.FireDACJSONReflect which contains the TFDJSONDataSets Class

in the Private section of tForm1 Class, add this Procedure : Procedure get_customer_name_list ;

create the body (Shift Ctrl C) and type its content: Procedure TForm1 . get_customer_name_list ;

Var l_c_json_dataset_list : TFDJSONDataSets ;

Begin

// -- clear the dataset

fd_customer_list_dataset . Close ;

// -- fetch the dataset list from the Rest Server

l_c_json_dataset_list := ClientModule1 . ServerMethods1Client . f_c_get_customer_name_list ;

// -- read the first dataset of this list into the memory dataset

fd_customer_list_dataset . AppendData (

TFDJSONDataSetsReader . GetListValue ( l_c_json_dataset_list , 0));

// -- opent the customer_list dataset

fd_customer_list_dataset . Open ;

End ; // get_customer_name_list

Both the definition and the body can be copied from the VCL u_client_form Unit drop a tButton and write the code which fetches the data and displays it in the tMemo : Procedure TForm1 . display_customer_list_Click ( Sender : TObject );

Begin

get_customer_name_list ;

With fd_customer_list_dataset Do

While Not Eof Do

Begin

display ( Format ( '%6s %s' ,

[ Fields [0]. AsString , Fields [1]. AsString ] ));

Next ;

End ; // while not Eof

End ; // display_customer_list_Click

for the first test, change the platform target to "Windows" ("Project Manager | zz_pos_project | Target Platform"

run the VCL project

this is the output :





Note that the form has been displayed in "Windows Format" (not the phone width and height).



4.6 - Bind the DataSet to Visual Controls Our memo display was just to check the fetching. For production applications, we will use FireMonkey controls, and bind them visually to the tFdMemDataSet.



To bind the tFdMemDataSet fields to the columns of the tListView, we must create dataset fields. Creating tFields is difficult at design time, but creating FieldDefs is possible To create the tFieldDefs select the tFdMemDataSet

in the Object Inspector, select the FieldDefs property and click on the Ellipsis ( ... ) this is a standard sub-item editor add a tFieldDefs by clicking on the top-left yellow icon "Add New"

a new tFieldDef has been created and is displayed in the Object Inspector

change the Name property into CUSTNO

do the same for the second tFieldDef, with name COMPANY

here is the result :





Now add a tListView and bind it : drop a tListView on the form

select the "Detail" listview, by selecting in the Object Inspector "Listview | ItemAppearance | ListItemRightDetail" The listview will display a .INI kind of two "key-value" columns list open the LiveBindings Designer by selecting "View | LiveBindings Designer" (or by selecting the ListView1, selecting it's LiveBindings the LiveBindings Designer is opened, displaying all the bindable objects bind "Listview Item.Text" to "MemDataSet CUSTNO" (drag the mouse from the Item.Text to the CUSTNO

bind the Item.Detail to the COMPANY

this is the current situation : run the (VCL) project and click on the Button

opening the DataSet automatically displays the values in the ListView :





Please note in our Delphi XE7 version, the LiveBindings Designer would not display the tFdMemDataSet fieldefs we just created. Closing the app and reloading it did the trick.





4.7 - Run on the Android Mobile Device Since the syntax is correct, we will now adjust to Android. Therefore change the Designer view back to "Android 4 inches" change the Target Platform to "Android" run the application

this is the result





Please note in our case, the "Run" took between 2 and 3 minutes. This is the reason why we preferred to first run in Windows mode



let's stress again that it is the "single code base" which allowed us to code in Windows Mode and then run in Android mode we also encountered a "F2039" error, because we added an incorrect second "]" in the Format of the fields

our display is quite primitive, to say the least. For customer applications, we would resize the controls, add shading, more sophisticated controls etc.







5 - Remarks The FireUi Multi device Designer "File | New | Multi Device Application" automatically calls the multi device designer. This wizard works with a "Master View" which contains the common elements of the design, and one or several device specific views. This explains why properties like the Name of controls are in the Master View, and to change a Name, we must switch to the Master View



of controls are in the Master View, and to change a Name, we must switch to the Master View if we move the controls in the Master View, the changes are not propagated to the other Views. Each view manages the graphic properties. Those properties are saved in a separate .DFM, named called in our case "u_android_client_form.NmXhdpiPh.fmx". This .DFM obviously contains the values for the phone :

Inherited Form1_NmXhdpiPh : TForm1_NmXhdpiPh

ClientHeight = 615

ClientWidth = 400

DesignerMasterStyle = 0

Inherited display_customer_list_ : TButton

Size . Width = 225.000000000000000000

End

Inherited customer_memo_ : TMemo

Size . Width = 385.000000000000000000

Size . Height = 73.000000000000000000

End

Inherited ListView1 : TListView

Size . Width = 385.000000000000000000

Size . Height = 457.000000000000000000

End

Inherited fd_customer_list_dataset : TFDMemTable

Left = 264

End

Inherited BindSourceDB1 : TBindSourceDB

Left = 136

Top = 64

End

Inherited BindingsList1 : TBindingsList

Left = 36

Top = 61

End

End



we think that this multi-device designer is a good tool for similar size devices, but for building applications targeted to phones, tablets and desktop devices, the design will have to be separated

for our first Android trials we used the Windows Target Platform because of round trip speed. Of course the resulting FireMonkey Windows layout is not adapted. The goal was NOT to build a desktop application. When the code was working as expected, we switched to the Android Platform. This also demonstrate that the Design Views and the Target Platform are two separate concerns. In the end, however, we selected at the same time an Android view and an Android target platform





5.1 - What's Next ? We presented the case of a simple table in read-only mode. There are many possible extensions and improvements : add an "update" function. The user can enter data which is then sent back to the Server



operate on many table : our single table example is quite simplistic. At least we should be able to use Master / Detail relationships



in a multi user environment, we should take care of the threads



finally a Business Object organization can simplify the Business Rules handling.





5.2 - What kind of devices / applications We simply sketched the structure of a POS software. The detailed content of the applications depends on the specific application. It could be as simple as retrieving a list of products or as complex as a full fledged ERP. In the case of more complex software, the big applications like accounting or order processing would be handled on desktop PC's, not on mobile devices. Those PCs can still be connected via WIFI, an can use REST and FireMonkey. But the benefit is less obvious than for hand held mobile devices.



And different devices can be used for different kind of applications phones for simple requests / entries with simple screens



tablets for more elaborate reports, computations, advertising or guides



desktop devices for application with richer screen designs : cash register, accounting etc





In the case of Point of Sale software, FireMonkey is particularly well suited. Il allows attractive simple touch screen design for applications like restaurant ordering, cash register, payment terminal etc



5.3 - The Datasnap Wizards Special congratulations to Delphi (Embarcadero ? Idera ?) for the two DataSnap wizards. Without them it would be nearly impossible to set up the REST Servers and Clients. Not only for the components and their links, but also for the generated code.



5.4 - Proxy Generation As with SOAP Web Services, the Server Application uses some objects (a tDataSet in our case) and this object's data has to be sent over to the Client. The general solution is to build a proxy object on the Client side. Then the DataSnap framework generates the units containing the proxies



at run time, the Client works with the proxy, and the REST Client communicates with the REST Server to get information or other objects from the Server.



the code of the proxy was completely handled by the DataSnap framework. All we had to do was call the method to retrieve and instantiate the client proxy.

We used a tDataSet object, and FireDac handled the marshalling using JSON. If we switch to Business Objects, DataSnap directly creates the proxies, and data can be exchanged using JSON.



5.5 - The article title Could we add other buzzwords to our "Using FireBase, FireDac, DataSnap, Rest, Wifi, and FireMonkey" title ? No problem here, what about "Android, LiveBindings, JSON, FireUi, JNI, DHCP, WebBroker". Well, piling up buzzwords was not the objective of this paper, and does not guarantee readership. As this story demonstrates: a survey showed that the three best selling books were about Abraham Lincoln, doctors and dogs. So one feller wrote a book "Dr Lincoln's dog". Which was a total flop.



5.6 - References About REST web services : the Delphi WIKI contains several tutorials and demos about REST services



contains several tutorials and demos about REST services Pawel GLOWACKI wrote a series of 11 Delphi Labs: DataSnap code samples, ranging form a simple calculator to authentication and callbacks





For displaying the Smarphone screen : we used Jim MCKEETH screen grabber Android Screen View.

As explained in the "readme", it simply uses the ADB (Android Debug Bridge) to fetch the screen image and display in the grabber's Form.





For testing the WIFI connection those tests involve JNI (Java Native Interface). We used two sources

Brian LONG was the first to post about the topic

Matthew MEAD posted 3 articles about Using the Java Native Interface with Delphi



Remy LEBEAU wrote about Delphi XE6 and Android Ping

Whenever we had any Tcp / Ip problem, this is the man who always provided, in Embarcadero's forums or StackOverflow, an answer, usually with a piece of code which solved the problem.



wrote about Whenever we had any Tcp / Ip problem, this is the man who always provided, in Embarcadero's forums or StackOverflow, an answer, usually with a piece of code which solved the problem. also many thanks to Alexis FRUHINSHOLZ, co founder of SocialCompare, who helped us with the WIFI connection diagnostic tools





6 - Download the Sources Here are the source code files: delphi_point_of_sale_software.zip the delphi project group containing the Server, the VCL Client and the Android FireMonkey Client (268K)



firebird_mastap_database_sql_script.zip the Sql Script to rebuild the Mastapp database (6 K)



mastapp_firebird_25.zip the binary of the MastApp demo database, in FireBird 2.5 (88 K)

The .ZIP file(s) contain: the main program (.DPR, .DOF, .RES), the main form (.PAS, .DFM), and any other auxiliary form



any .TXT for parameters, samples, test data



all units (.PAS) for units

Those .ZIP are self-contained: you will not need any other product (unless expressly mentioned).



for Delphi 6 projects, can be used from any folder (the pathes are RELATIVE)



will not modify your PC in any way beyond the path where you placed the .ZIP (no registry changes, no path creation etc).

To use the .ZIP: create or select any folder of your choice



unzip the downloaded file



using Delphi, compile and execute

To remove the .ZIP simply delete the folder. The Pascal code uses the Alsacian notation, which prefixes identifier by program area: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lasse etc. This notation is presented in the Alsacian Notation paper.





As usual: please tell us at fcolibri@felix-colibri.com if you found some errors, mistakes, bugs, broken links or had some problem downloading the file . Resulting corrections will be helpful for other readers



. Resulting corrections will be helpful for other readers we welcome any comment, criticism, enhancement, other sources or reference suggestion . Just send an e-mail to fcolibri@felix-colibri.com.



. Just send an e-mail to fcolibri@felix-colibri.com. or more simply, enter your (anonymous or with your e-mail if you want an answer) comments below and clic the "send" button Name : E-mail : Comments * :

and if you liked this article, talk about this site to your fellow developpers, add a link to your links page ou mention our articles in your blog or newsgroup posts when relevant. That's the way we operate: the more traffic and Google references we get, the more articles we will write.





7 - The author Felix John COLIBRI works at the Pascal Institute. Starting with Pascal in 1979, he then became involved with Object Oriented Programming, Delphi, Sql, Tcp/Ip, Html, UML. Currently, he is mainly active in the area of custom software development (new projects, maintenance, audits, BDE migration, Delphi Xe_n migrations, refactoring), Delphi Consulting and Delph training. His web site features tutorials, technical papers about programming with full downloadable source code, and the description and calendar of forthcoming Delphi, FireBird, Tcp/IP, Web Services, OOP / UML, Design Patterns, Unit Testing training sessions.

