Running mobile apps on an application server
From the mobile device, programs can be started remotely on an application server, and displayed on the device.
Purpose of remote application execution for mobile devices
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.
Implementing the embedded mobile app
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 MAINWhen 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.
runOnServer front call. Because starting remote GAS applications is
                done with a front call, this configuration mimics an embedded starter app running on
                the device. Using the runOnServer front call
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.
TRY/CATCH block to check if the execution
                the server application was successful:
                MAIN
  TRY
    CALL ui.interface.frontcall("mobile","runOnServer",
         ["http://myappserver:6394/ua/r/myapp"],[])
  CATCH
    ERROR err_get(STATUS)
  END TRY
END MAINSubsequent 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.
Passing parameters to the server application
?Arg=value1&Arg=value1&...
                notation:DEFINE params, base, complete_url STRING
LET params = "Arg=verbose&Arg=5677"
LET url = "http://myappserver:6394/ua/r/myapp"
LET complete_url = base || "?" || paramsThe remote program can retrieve the parameters with the arg_val() built-in function.
runOnServer front call.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 FUNCTIONMAIN
    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 MAINSharing files between embedded and server app
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.
- Before starting the server application with a 
runOnServerfront call, the embedded app must copy files to the data-directory. - While executing, the server application can retrieve files from the
                            data-directory with 
fgl_getfile(), and send its own files to the data-directory, withfgl_putfile(). - When the server application terminates, the embedded app can read files the server application left in the data-directory.
 
RUN instruction, make sure to not overwrite files
                    written by other server programs.In order to write code for the embedded app, that can be executed in development mode
                (running on a server) and on the mobile device, you can adapt to the execution
                context: Make a simple file copy when executing on the mobile device, or do an
                    fgl_putfile() call, when running on the development server.
                Check the execution context with the base.Application.isMobile()
                method.
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 FUNCTIONos.Path.join() method here because it would add
                the path separator for the operating system where the application is executed. This
                would not be a problem when executing on the mobile device or Unix-like platforms.
                However, when running on a Windows® platform, the os.Path.join() method would join
                the directory and the file name with a backslash, and the resulting path would not
                fit Android™ or iOS
                directory path specification for the data-directory.fgl_getfile() function, to
                transfer a file from the mobile device data-directory to the
                local server
                disk: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 FUNCTIONfgl_putfile()
                function, to copy a file from the server application to the
                    data-directory of the embedded
                app: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