Professional Documents
Culture Documents
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
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 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.
start delphi
select "Tools | Options" and in "Default Project:", fill the project folder name and click "Ok"
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:
Delphi builds the necessary files and presents the Server Form
2.3 - The WebBroker Rest Server Units
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
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
Type
{$METHODINFO ON}
TServerMethods1 =
Class(TDataModule)
Private
Public
Function EchoString(Value: string): string;
End;
{$METHODINFO OFF}
Implementation
{$R *.dfm}
Uses System.StrUtils;
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)
The main form can be used to start the server and open a browser to test all DataSnap methods.
click "Start"
the Tcp Server is started ("start" and the port are grayed)
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
click ON THE PLUS before "TServerMethods" (yes, it is a pale gray on a pale blue plus button)
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.
Our Rest Server is going to send the content of some Table to its clients.
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.
We will start with a client which will display the CUSTOMER ( CUSTNO, COMPANY ) table.
double click on the DataModule to create its OnCreate method and initialize the driver's DriverId, VendorHome and VendorLib Properties by code :
Please note:
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
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:
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 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) :
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:
Result := TFDJSONDataSets.Create;
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)
save the project and unit in a Client_VCL\ folder under u_client_vcl and p_13_rest_vcl_client
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:
change ClientModuleUnit1 into u_client_datamodule. In this Unit, replace ClientClassesUnit1 with u_client_classes
And we must also add the FireDac JSON components to unmarshall the dataset:
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.
from the Tool Palette, select a tFdMemTable, drop it on the form and rename it fd_customer_list_dataset
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));
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
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.
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
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:
Our server is located on a PC linked to a switch. This switch has a manager which
The manager can be used to freeze the IP of one or several connected devices. The other devices are allocated random IPs.
The Port of our REST Server application was set when we created this Server with Delphi. It is 8081.
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
Knowing the Client IP, we can PING the device from the switch or from the Server;
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;
Implementation
{$R *.fmx}
{$R *.NmXhdpiPh.fmx ANDROID}
End
We must
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
start Delphi
(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 "
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 :
the android device asks you to confirm the debug mode : "Allow Usb Debugging ?"
touch "ok"
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:
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"
for this FireMonkey client connected by WIFI, select the "Remote Server" and click "Next"
we type the 192.168.1.14 IP and change the port to 8081. Then click "test"
change ClientModuleUnit1 into u_client_datamodule. In this Unit, replace ClientClassesUnit1 with u_client_classes
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:
from the Tool Palette, select a tFdMemTable, drop it on the form and rename it fd_customer_list_dataset
write the display global Procedure which simply adds the text to the Form's Memo1 :
Procedure get_customer_name_list;
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));
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 :
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"
Note that the form has been displayed in "Windows Format" (not the phone width and height).
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
in the Object Inspector, select the FieldDefs property and click on the Ellipsis ( ... )
this is a standard sub-item editor
a new tFieldDef has been created and is displayed in the Object Inspector
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
bind "Listview Item.Text" to "MemDataSet CUSTNO" (drag the mouse from the Item.Text to the CUSTNO
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.
Therefore
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
"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 :
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
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.
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
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.
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
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.
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
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
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
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 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).
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