Mobile applications / Deploying mobile apps |
From the mobile device, programs can be started remotely on an application server, and displayed on the device.
Server applications can only be started through the Genero Application Server (GAS), by using the UA protocol available since version 3.00. You must set up and configure the GAS for the programs you want to start remotely. See the GAS documentation for more details.
Create a small application to be deployed on the mobile device, which then starts the application(s) on an GAS server.
The server application is started from the embedded application through the runOnServer front call. The embedded mobile application can be a very simple MAIN / END MAIN program, only performing the "runOnServer" front call.
MAIN CALL ui.interface.frontcall("mobile","runOnServer", ["http://myappserver:6394/ua/r/myapp"],[]) END MAIN
When the remote application starts, the graphical user interface displays on the mobile device.
The runOnServer front call returns when the called application ends, control goes back to the initial application executing on the mobile device.
The application executed on the server-side is identified by the first parameter of the runOnServer front call. This application must be delivered by the Genero Application Server. The parameter must contain an "ua/r" URL syntax (the UA protocol introduced with the GAS 3.00).
For example: http://myappserver:6394/ua/r/myapp
The URL may contain a query string, with parameters for the application to be executed by the GAS.
If needed, you can add a second argument to define a timeout as a number of seconds. The embedded application will wait for the remote application to start, until the timeout expired. If no timeout parameter is specified, or when zero is passed, the timeout is infinite.
MAIN TRY CALL ui.interface.frontcall("mobile","runOnServer", ["http://myappserver:6394/ua/r/myapp"],[]) CATCH ERROR err_get(STATUS) END TRY END MAIN
Subsequent server-side application runs are allowed; the last active application will display on the device. However, it is not possible to navigate between started applications. Therefore, an application started with the runOnServer front call must only use the RUN instruction to start sub-programs. RUN WITHOUT WAITING is not supported.
DEFINE params, base, complete_url STRING LET params = "Arg=verbose&Arg=5677" LET url = "http://myappserver:6394/ua/r/myapp" LET complete_url = base || "?" || params
The remote program can retrieve the parameters with the arg_val() built-in function.
See the GAS documentation (AllowUrlParameters attribute) about passing parameters in the application URL.
IMPORT util MAIN DEFINE arr DYNAMIC ARRAY OF STRING, x INT MENU "test" COMMAND "runOnServer" CALL arr.clear() LET arr[1] = "first argument" LET arr[2] = "second argument" LET x = do_run("http://10.0.40.29:6394/ua/r/test1", 10, arr) COMMAND "exit" EXIT MENU END MENU END MAIN FUNCTION do_run(url,timeout,params) DEFINE url STRING, timeout SMALLINT, params DYNAMIC ARRAY OF STRING DEFINE i, r INTEGER, tmp STRING LET r = 0 LET tmp = url FOR i=1 TO params.getLength() LET tmp = tmp || IIF(i==1,"?","&") || "Arg=" || params[i] END FOR TRY CALL ui.interface.frontcall("mobile","runOnServer",[tmp,timeout],[]) CATCH ERROR err_get(STATUS) LET r = -1 END TRY RETURN r END FUNCTION
MAIN MENU "Prog1" COMMAND "arg1" MESSAGE "Arg 1 = ", arg_val(1) COMMAND "arg2" MESSAGE "Arg 2 = ", arg_val(2) COMMAND "arg3" MESSAGE "Arg 3 = ", arg_val(3) COMMAND "Quit" EXIT MENU END MENU END MAIN
If files need to be shared between the embedded application and the server application, the application running on the GAS can only access the data-directory directory, in the sandbox of the embedded application that executes the "runOnServer" front call.
This matters when using file handling APIs such as fgl_putfile() and fgl_getfile() or front calls like takePhoto and launchURL.
The data-directory on the mobile device can be found with the feInfo/dataDirectory front call. In both the embedded app and the app running on the server, this front-call will return the same directory.
IMPORT os ... CALL mobile_copy_to_data_dir("myfile.txt") ... FUNCTION mobile_copy_to_data_dir(fn) DEFINE fn, dd, dst STRING, r INT CALL ui.interface.frontcall("standard","feInfo",["dataDirectory"],[dd]) -- Always use / as path sep for Android/iOS dirs. LET dst = dd || "/" || os.Path.basename(fn) IF base.Application.isMobile() THEN -- Executing on device: make a simple copy to data-dir LET r = os.Path.copy(fn, dst) MESSAGE SFMT("COPY status = %1", r) ELSE -- Executing on dev server: make a file transfer to data-dir CALL fgl_putfile(fn, dst) END IF END FUNCTION
IMPORT os ... CALL server_get_from_data_dir("myfile.txt", "/tmp/server_file.txt") ... FUNCTION server_get_from_data_dir(fn, dst) DEFINE fn, dst, dd, src STRING CALL ui.interface.frontcall("standard","feInfo",["dataDirectory"],[dd]) -- Use / as path sep for Android/iOS dirs! LET src = dd || "/" || fn CALL fgl_getfile(src, dst) END FUNCTION
IMPORT os ... CALL server_put_to_data_dir("/tmp/server_file.txt", "myfile.txt") ... FUNCTION server_put_to_data_dir(src, fn) DEFINE src, fn, dd, dst STRING CALL ui.interface.frontcall("standard","feInfo",["dataDirectory"],[dd]) -- Use / as path sep for Android/iOS dirs! LET dst = dd || "/" || fn CALL fgl_putfile(src, dst) END FUNCTION