GFX Phone SDK Reference (window.GFXPhone)

The JavaScript SDK connects your custom app’s page to the GFX Phone. Load it from the phone:

<script src="https://cfx-nui-gfx-phone/web/build/sdk/gfx-phone-sdk.js"></script>

TypeScript: copy sdk/gfx-phone-sdk.d.ts into your project. Plain ES2019, no dependencies.

Every call returns a Promise. A refused call rejects with an Error whose code says why.

Start-up

Call Result
GFXPhone.ready() Call first. Resolves with the context.
GFXPhone.getContext() The context again.
GFXPhone.context The latest context (null before ready()).
GFXPhone.resource Your resource’s name, for your own NUI callbacks.
GFXPhone.configure({ phoneResource }) Only if the phone resource is not called gfx-phone. Before ready().

Context

{
  app: { id, name },
  active,                               // your app is the one on screen
  theme: {
    mode: 'light' | 'dark', accent, material, fontFamily, textScale, reduceMotion,
    colors: { label, labelSecondary, labelTertiary, background, groupedBackground, fill, separator, tint, blue },
  },
  locale: { language, rtl, dateLocale, currency: { symbol } },
  device: { width: 384, height: 832, safeTop: 54, safeBottom: 34, frameWidth },
  network: { online, service, wifi, wifiName, signal, airplane, noSim },
  battery: { level, charging, lowPower },
}

GFXPhone.on('context', fn) fires (at most every 250 ms) when any of it changes.

Theme

GFXPhone.applyTheme(el?) (default <html>) sets:

  • CSS variables from theme.colors: --gfx-label, --gfx-label-secondary, --gfx-label-tertiary, --gfx-background, --gfx-grouped-background, --gfx-fill, --gfx-separator, --gfx-tint, --gfx-blue
  • --gfx-text-scale (multiply your font sizes by it)
  • color-scheme, data-theme="light|dark", lang, dir="rtl" for Arabic

Call it after ready() and on every context event.

Events

Event Data
context the new context
open the page is connected
foreground / background your app came on screen / left it (another app, home, lock)
intent why it opened: a notification’s data, { widget }, { island }, OpenCustomApp’s intent
message { action, data } from SendCustomAppMessage
islandAction { key, button }

GFXPhone.on(event, fn) returns an unsubscribe function; GFXPhone.off(event, fn) also works.

Methods

Call Result
close() back to the home screen
openApp(id) opens another installed app
setBadge(n) the red count on your icon (0 clears)
send(action, data) your client onMessage’s return value
state.get(key) / state.set(key, value) values kept while the game runs (64 KB per app)
notify({ title, body?, id?, image?, group?, data? }) { id }
island.start(key, activity) / island.update(key, activity) / island.end(key) see Lemon Pulse
widgets.update(widget, data) see Widgets
network.status() / battery.status() as in the context
camera.takePhoto() { url } - the phone’s Camera over your app, shot uploaded
gallery.pick({ max? }) [{ url }], up to 10
auth.verifyPasscode() true when the player entered their passcode (also when they have none), false on Cancel
passwords.save({ username, password, label? }) true when saved to the Passwords app
passwords.autofill() { username, password } - one of the logins saved for your app
pay({ amount, label, ref? }) / pay({ paymentId }) { id, amount, balance } - see Payments
location.get() { x, y, z, street, zone }
location.setWaypoint(x, y) sets the map waypoint
contacts.pick() { name, number }
contacts.message(number, text?) opens Messages with the text in the composer (the player sends it)
contacts.call(number, name?) true when the player confirmed and the call started
share({ text?, url?, image? }) true when shared (Messages or Copy); LemonDrop to nearby phones is offered too
ui.alert({ title, message?, button? }) resolves when dismissed
ui.confirm({ title, message?, confirm?, cancel?, destructive? }) true / false
ui.actionSheet({ title?, message?, options: [{ id, label, style? }] }) chosen id or null
ui.toast(text) a short message over your app
ui.setStatusBar('dark' \| 'light' \| null) status bar icon colour (null = automatic)

Sheets

Camera, gallery, passcode, passwords, pay, location, contacts, call, share and the ui.* dialogs are sheets the phone draws. They open only while your app is on screen and the phone is unlocked (else notActive), one at a time (else busy), and close with cancelled when the player leaves your app. They wait for the player (no timeout); pay gives up after 120 s and every other call after 15 s.

Error codes

Code When
timeout no answer in time
unknownMethod the phone does not know this call (an older phone version)
unavailable your app is not registered / the feature is off on this server
notPermitted the permission is missing from your registration
notActive a sheet was asked while your app was not on screen
busy another sheet is open
rateLimited too many calls
tooLarge the request is over 64 KB
invalid bad parameters
cancelled the player closed the sheet
denied location refused or Location Services off
notFound AutoFill: no login saved for your app
noMoney, overLimit, refused, failed payments

Automatic behaviour

  • Typing: while a text field in your page has focus, the phone keeps the keyboard, so the player does not walk.
  • Keys: Escape (put the phone away) and Backspace outside a text field (back) go to the phone.
  • Zoom: when the phone’s scale does not reach into your frame (it differs between CEF builds), the SDK zooms your page to the phone’s layout width, and again on every resize.