Smart platform services
Something cool is taking place in the Smart Mobile Studio RTL, namely the implementation of platform services.
What is a platform service you say? Put simply a platform service is an API that the RTL exposes for you while abstracting you from the low-level implementation. Where the existing browser-driver system is platform spesific, dealing with how the browser exposes it’s features (which is different from browser to browser), platform services are feature spesific: meaning that they present a set of features un-bound by the environment.
This means that even though browsers implement things differently (even with different names, attributes and method calls), you dont have to worry about it.
Platform services are available (read: resolved) at runtime rather than design-time. So you dont have to pick out the services from a list prior to compilation, instead the RTL will create the correct object factory – which in turn exposes the correct service-item for the browser you use. The number of services available depends on what you have used, which the compiler takes care of.
What features?
Services deal with features that the browsers may or may-not expose, hence the service architecture for querying what you can and cannot do. For instance, access to the camera or image-picker is a typical service API, because it greatly depends on the mobile-device, what JS API’s are available (phonegap or native access) – and last but not least: user interaction.
Other types of services are more low-level in nature: websocket support, rest-client support, JSONP support, data encoding mechanisms, encryption support, access to gps tracking, camera access, disk access, storage functionality, database access.
if PlatformServices.GetCameraAPI(IAccess) then begin if IAccess.ShowCamera(mediastream, [ocTakePhoto,ocPhotoPicker]) then begin //mediastream now contains picture or movie frames end else writeln('debug: camera was canceled'); end else raise exception.create('Camera not supported error');
Now in order for us to shield you from the gory details we have started to implement the most common API’s as run-time services. This means easy to use, easier for us to maintain and setting a standard for future expansion of the Smart Mobile Studio run-time library.
Working with platform services
Coding based on platform services is all about abstraction. You simply ask the system to provide you with access to a service, and if the system supports that service (or allows it) you are given an access interface. The abstraction layer and working with interfaces like this is very effective. You can of course create class instances ad-hoc if you like, but that kinda defeats the portability of your code and binds you to that spesific class (which may be webkit spesific, firefox spesific or something else). The goal of platform services is to make sure your code runs and behaves identical on all supported platforms.
Websocket example
Here is an example of how to access the websocket platform service, using the access interface to create a websocket element, initialize it and then connect to a server:
procedure TForm1.btnConnectClick(Sender: TObject); var IAccess: IW3WebSocketService; ISocket: IWebSocket; begin if PlatformServices.GetWebSocketAPI(IAccess) then begin if IAccess.CreateSocket(ISocket) then Begin //Attach connected event handler ISocket.SetOnOpenEvent( procedure (Access:IWebSocket) begin Writeln('Websocket is now open!'); end); // Attach disconnect event handler ISocket.SetOnClosedEvent( procedure (Access:IWebSocket) begin Writeln('Websocket is now closed'); end); // Attach Message handler ISocket.SetOnMessageEvent( procedure (IO:IWebSocketIO; Message:TWebSocketMessageData) begin WriteLn(message.mdText); end); // Connect to our server ISocket.Connect('ws://192.168.38.108:8080',['void']); end; end; end;
As you can see from the code above you are pretty much shielded from all the technical aspects of the WebSocket standard. You simply ask for the service and then use the service to create a websocket instance – which you access through the socket interface.
As a user you don’t have to care about the gory details here. You don’t have to worry about stuff like instance factories, if your code is running on FireFox, Chrome, MS10 or Safari. And even better is that you no longer have to care if it’s running on desktop, iOS, Android or an embedded system.
Here is the full IWebSocket interface
IWebSocketIO = interface Procedure WriteString(const value:String); procedure WriteMemory(const Value:TMemoryHandle); Procedure WriteStream(const Value:TStream); Procedure WriteBinary(Const Data:TBinaryData); function GetSocketState:TWebSocketState; function GetConnected:Boolean; function GetURL:String; function GetProtocol:String; function GetBinaryMessageDataType:TWebSocketBinaryDataType; procedure SetBinaryMessageDataType(const Value:TWebSocketBinaryDataType); procedure Disconnect; Property BinaryMessageDataType:TWebSocketBinaryDataType read GetBinaryMessageDataType write SetBinaryMessageDataType; Property SocketState:TWebSocketState read getSocketState; Property Connected:Boolean read getConnected; property URL:String read getURL; Property Protocol:String read getProtocol; end; (* Websocket service interface *) IWebSocket = interface function GetBinaryMessageDataType:TWebSocketBinaryDataType; procedure SetBinaryMessageDataType(const Value:TWebSocketBinaryDataType); function GetSocketState:TWebSocketState; function GetConnected:Boolean; function GetURL:String; function GetProtocol:String; procedure Connect(URL:String;Protocols:Array of String); procedure Disconnect; Procedure WriteString(const value:String); procedure WriteMemory(const Value:TMemoryHandle); Procedure WriteStream(const Value:TStream); Procedure WriteBinary(Const Data:TBinaryData); function GetOnOpenEvent:TWebSocketOpenEvent; function GetOnClosedEvent:TWebSocketCloseEvent; function GetOnMessageEvent:TWebSocketMessageEvent; function GetOnErrorEvent:TWebSocketErrorEvent; procedure SetOnOpenEvent(const Handler:TWebSocketOpenEvent); procedure SetOnClosedEvent(const Handler:TWebSocketCloseEvent); procedure SetOnMessageEvent(const Handler:TWebSocketMessageEvent); procedure SetOnErrorEvent(const Handler:TWebSocketErrorEvent); Property SocketState:TWebSocketState read getSocketState; Property Connected:Boolean read getConnected; property URL:String read getURL; Property Protocol:String read getProtocol; Function GetServiceElement:IServiceElement; Property BinaryMessageDataType:TWebSocketBinaryDataType read GetBinaryMessageDataType write SetBinaryMessageDataType; Property OnOpen:TWebSocketOpenEvent read GetOnOpenEvent write SetOnOpenEvent; Property OnClosed:TWebSocketCloseEvent read GetOnClosedEvent write SetOnClosedEvent; Property OnMessage:TWebSocketMessageEvent read GetOnMessageEvent write SetOnMessageEvent; Property OnError:TWebSocketErrorEvent read GetOnErrorEvent write SetOnErrorEvent; end;
Keep it simple, keep it safe
The benefit for us in terms of delivering a better Smart Mobile Studio, is that it allows us to compartmentalize our code. We get to create service classes for FireFox, Chrome and so on without having to go through hoops just to make it work identically everywhere. It works almost like a driver or plugin system, where the correct factory and service provider (sigh) is resolved at runtime. Most of the time we get away with a single implementation class, but it’s nice to know that we can isolate code for one browser in its own class, and support for the same features for another browser in another class. This helps keep the RTL sane and organized.
While no date has been set, I can at least tell you that this system will not be available until we reach at least version 2.3.x; at the very least.
Leave a reply to warleyalex Cancel reply
Calendar
M | T | W | T | F | S | S |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
Recent
The vatican vault
- September 2023
- August 2023
- March 2023
- February 2023
- December 2022
- October 2022
- January 2022
- October 2021
- March 2021
- November 2020
- September 2020
- July 2020
- June 2020
- April 2020
- March 2020
- February 2020
- January 2020
- November 2019
- October 2019
- September 2019
- August 2019
- July 2019
- June 2019
- May 2019
- April 2019
- March 2019
- February 2019
- January 2019
- December 2018
- November 2018
- October 2018
- September 2018
- August 2018
- July 2018
- June 2018
- May 2018
- April 2018
- March 2018
- February 2018
- January 2018
- December 2017
- November 2017
- October 2017
- August 2017
- July 2017
- June 2017
- May 2017
- April 2017
- March 2017
- February 2017
- January 2017
- December 2016
- November 2016
- October 2016
- September 2016
- August 2016
- July 2016
- June 2016
- May 2016
- April 2016
- March 2016
- January 2016
- December 2015
- November 2015
- October 2015
- September 2015
- August 2015
- June 2015
- May 2015
- April 2015
- March 2015
- February 2015
- January 2015
- December 2014
- November 2014
- October 2014
- September 2014
- August 2014
- July 2014
- June 2014
- May 2014
- April 2014
- March 2014
- February 2014
- January 2014
- December 2013
- November 2013
- October 2013
- September 2013
- August 2013
- July 2013
- June 2013
- May 2013
- February 2013
- August 2012
- June 2012
- May 2012
- April 2012
Reading your code, it resembles one that I’ve created once, it’s a smart wrapper jquery class to use with Smart, f.i. when I click in a button it displays a message. So I can call this jQuery-like function
myObj(‘#btn1’).on(‘click’,function(e: variant): variant
begin
WriteLn(‘Button1 was Clicked’);
end);
…but I would like to implement the same method using a neater layout of code, something like this:
procedure btn1Click(Sender: TObject);
Begin
WriteLn(‘Button1 was Clicked’);
end;
Any idea for insane usage of Delphi;
JQuery is really not needed for Smart Pascal. JQuery is great in ordinary JS where elements and their handle’s are unknown. But in a component and class driven architecture like the smart RTL provides, the component or class always know’s it’s own handle (or the handle to the visual element it manages) — so i cant really see why you would want to use jQuery at all.
But for building syntax like the stuff you describe, you should be able to do something like this:
TEventReference = Class(TObject)
private
FInstance: TW3TagObj;
FEventName: String;
public
procedure Execute(EntryPoint:TProcedureRef);
constructor Create(Obj:TW3TagObj;EventName:String);
end;
TControlReference = class(TObject)
private
FParent: TW3Component;
FInstance: TW3TagObj;
public
function Attach(EventName:String):TEventReference;
constructor Create(AParent:TW3Component;AInstance:TW3TagObj);
end;
TSelector = class abstract
public
class function &Object(Container:TW3Component;ControlName:String):TControlReference;
end;
//#############################################################################
// TEventReference
//#############################################################################
constructor TEventReference.Create(Obj:TW3TagObj;EventName:String);
begin
inherited Create;
FInstance := Obj;
FEventName := EventName;
end;
procedure TEventReference.Execute(EntryPoint:TProcedureRef);
begin
w3_AddEvent(FInstance.Handle,FEventName,Entrypoint);
end;
//#############################################################################
// TControlReference
//#############################################################################
constructor TControlReference.Create(AParent:TW3Component;AInstance:TW3TagObj);
begin
inherited Create;
FParent := AParent;
FInstance := AInstance;
end;
function TControlReference.Attach(EventName:String):TEventReference;
begin
result := TEventReference.Create(Finstance,EventName);
end;
//#############################################################################
// TSelector
//#############################################################################
class function TSelector.&Object(Container:TW3Component;ControlName:String):TControlReference;
var
x: Integer;
mObj: TObject;
begin
result := NIL;
if ContainerNIL then
begin
controlname:=controlname.trim();
if controlname.length>0 then
begin
mObj := Container.ChildByName(ControlName);
if mObjNIL then
result := TControlReference.Create(Container,TW3Component(mObj));
end;
end;
end;