Registering a Custom App (AddCustomApp)

exports['gfx-phone']:AddCustomApp(def) puts your app on the GFX Phone. It returns true, or false, err.

Fields

Field Meaning
id a-z, 0-9, _, starts with a letter, up to 32 characters. Never one of the phone’s own app ids.
label The app’s name (up to 24). A string, or one per language: { en = 'Bank', tr = 'Banka' }. English, then any, is the fallback.
ui The page: ui/index.html, nui://<your resource>/... or https://cfx-nui-<your resource>/.... Another resource’s page is refused. A dev server (http://localhost:<port>/) only with set gfx-phone_dev 1.
icon https://... or a file of your resource.
color Icon tile colour when there is no icon (CSS colour or gradient).
ground Colour under the page while it loads: '#fff' or { light = '#fff', dark = '#000' }.
darkSurface true when the app is always dark (white status bar icons).
offline true = opens without a signal (no “No Connection” screen).
defaultApp true = installed on every phone and cannot be deleted. false = listed in the Apps store.
subtitle, description, developer, version, ageRating Apps store texts (subtitle / description can be per language like label).
category social, utility, finance, media or game.
permissions What the page may use (below). Default { 'notifications', 'island' }.
widgets Home-screen widgets - see Widgets.
onOpen() / onClose() The page was loaded / closed (or the phone put away).
onMessage(action, data) GFXPhone.send(action, data) from the page; the return value goes back.
onIslandAction(key, button) A button on your Lemon Pulse activity was tapped.

Server registration only:

Field Meaning
price Apps store price.
serverPaymentsOnly true = the page can only pay payments your server created.
onPayment(src, payment) A payment went through; return false to refund it at once. See Payments.

Errors: invalidId, reserved (a built-in app id), noLabel, invalidUi, ownedByOther (another resource registered this id), tooMany (64 apps).

Permissions

Permission Unlocks
notifications GFXPhone.notify, SendCustomAppNotification
island GFXPhone.island.*, Start/Update/EndCustomAppIsland
camera GFXPhone.camera.takePhoto
photos GFXPhone.gallery.pick
passcode GFXPhone.auth.verifyPasscode
passwords GFXPhone.passwords.save / autofill (servers with the Passwords vault)
payments GFXPhone.pay
location GFXPhone.location.get - the player is asked once; Settings > your app changes it
contacts GFXPhone.contacts.pick

Alerts, toasts, share, waypoints, opening Messages / calling a number, widgets, state, network and battery need no permission. A call the app has no permission for fails with notPermitted.

Client or server registration?

  • Client only - the simplest: an app that needs nothing from the server.
  • Client + server (same id, same resource) - adds an app store price, the admin panel’s App access switch, server-charged payments and the server exports (SendCustomAppNotification(src, ...), UpdateCustomAppWidget(src, ...)…). The server’s fields win; callbacks stay on the side that registered them.

Server side, register when gfx-phone starts:

local function register()
    exports['gfx-phone']:AddCustomApp({ id = 'myapp', label = 'My App', ui = 'ui/index.html', price = 9.99 })
end
AddEventHandler('onResourceStart', function(res)
    if res == 'gfx-phone' or res == GetCurrentResourceName() then register() end
end)

When your resource stops

Its app disappears from every phone. Its place on the home screen (and its widgets) is kept, and it comes back there when the resource starts again. RemoveCustomApp(id) does the same on purpose.