Vous êtes sur la page 1sur 54

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
key words : 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
hardware used : 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
level : Delphi developer
plan :
o WIFI Point of Sale devices
o The Rest Server
o The Desktop VCL Rest Client
o The Mobile Rest Client
o 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
o the tDataModule ancestor
o the $METHODINFO compiler directive which enables the Server to call our methods

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
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


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.


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


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


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
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


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
o Program Files\ for the Java SDK
o 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

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
o security WPA etc
o 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


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
o we also encountered a "F2039" error, because we added an incorrect second "]" in the Format of the fields
o 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
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 delta values :

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
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
o Brian LONG was the first to post about the topic
o 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.
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
we welcome any comment, criticism, enhancement, other sources or reference suggestion. 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.

Created: sep-16. Last updated: sep-16 - 107 articles, 228 .ZIP sources, 1174 figures
Copyright Felix J. Colibri http://www.felix-colibri.com 2004 - 2016. All rigths reserved

Back: Home Papers Training Delphi developments Links Download

Vous aimerez peut-être aussi