App Registration & Lifecycle

Learn how to register your custom app with 5M Phone and handle start/restart lifecycles reliably.


RegisterApp API Specification

Custom apps register via exports['5M_Phone']:RegisterApp(data) on the client:

Lua
local ok, err = exports['5M_Phone']:RegisterApp({
    id = 'my-custom-app',           -- (string, required) Unique ID
    name = 'My Custom App',         -- (string, required) Display title
    description = 'My custom app',  -- (string, optional) App Store description
    developer = 'Developer Studio', -- (string, optional) Studio author name
    defaultApp = true,              -- (boolean, optional) Auto-install on home screen
    ui = 'ui/dist/index.html',      -- (string, required) HTML path or https:// URL
    icon = 'ui/dist/icon.svg',      -- (string, required) Icon path or URL
    color = '#6366f1',              -- (string, optional) HEX accent color
    screenshots = {                 -- (table, optional) Gallery images for App Store
        'ui/dist/store/shot1.svg',
        'ui/dist/store/shot2.svg',
    },
})

Parameter Reference

FieldTypeRequiredDescription
idstringYesUnique app slug (e.g. 'crypto-tracker'). Letters, digits, hyphens, and underscores.
namestringYesDisplay title rendered beneath the app icon and on the App Store card.
descriptionstringNoDescription displayed on the App Store product details page.
developerstringNoStudio or author name.
defaultAppbooleanNoDefault false. If true, the app is pre-installed on the home screen. If false, it appears in the App Store.
uistringYesPath to the built HTML file relative to your resource, or a remote https:// URL.
iconstringYesPath to the icon image (.svg or .png) relative to your resource, or a remote URL.
colorstringNoHEX color string (e.g. '#3b82f6') used for app badges and accent highlights.
screenshotstableNoArray of relative asset paths or URLs displayed in the App Store screenshot carousel.

Production Lifecycle Pattern (client/main.lua)

To ensure your app registers cleanly regardless of start order or resource restarts, implement the following pattern:

Lua
local PHONE = '5M_Phone'

local function phoneReady()
    return GetResourceState(PHONE) == 'started'
end

local function register()
    if not phoneReady() then return false end

    local ok, err = exports[PHONE]:RegisterApp({
        id = Config.AppId,
        name = Config.Name,
        description = Config.Description,
        developer = Config.Developer,
        defaultApp = Config.DefaultApp == true,
        ui = Config.UiPath,
        icon = Config.IconPath,
        color = Config.Color,
        screenshots = Config.Screenshots,
    })

    if not ok then
        print(('[5M_CustomApp] RegisterApp failed: %s'):format(tostring(err)))
        return false
    end

    print(('[5M_CustomApp] Successfully registered on %s as "%s"'):format(PHONE, Config.AppId))
    return true
end

-- 1. Initial startup: wait until 5M_Phone is started
CreateThread(function()
    while not phoneReady() do
        Wait(400)
    end
    Wait(800)
    register()
end)

-- 2. Phone restarted in-game: re-register automatically
AddEventHandler('onResourceStart', function(res)
    if res == PHONE then
        CreateThread(function()
            Wait(1000)
            register()
        end)
    end
end)

-- 3. App resource stopping: unregister cleanly from phone home screen
AddEventHandler('onResourceStop', function(res)
    if res == GetCurrentResourceName() and phoneReady() then
        pcall(function()
            exports[PHONE]:UnregisterApp(Config.AppId)
        end)
    end
end)

Unregistering an App

If you need to dynamically remove an app from the phone:

Lua
exports['5M_Phone']:UnregisterApp('my-custom-app')

Startup Order in server.cfg

Always start 5M_Phone before custom developer apps:

Config
ensure 5M_Phone
ensure 5M_CustomApp