Usar cupón WELCOME para guardar 20%

€ EUR
  • $ USD
  • € EUR
  • £ GBP
  • $ AUD
  • R$ BRL
  • CHF CHF
  • ¥ yenes
Crea una aplicación móvil personalizada para el FiveM.

Crea una pequeña aplicación de teléfono FiveM con NUI

Crea primero una pequeña aplicación NUI estilo teléfono para aprender el ciclo completo de abrir, enviar mensajes, ejecutar callbacks y cerrar. Este ejemplo muestra una nota de sesión que permanece mientras el recurso se ejecuta. No tiene llamadas, servicio de mensajería, base de datos o dependencia de framework; añadir eso requiere autorización y persistencia separadas del lado del servidor.

Crea tres archivos

Crea resources/[local]/tutorial_phone/ con fxmanifest.lua, client.lua e index.html. El ejemplo está pensado para el entorno de ejecución de recursos gta5 de GTA V Legacy. Consulta las indicaciones de migración a Enhanced de Cfx.re antes de adaptarlo a una instalación de Enhanced.

fxmanifest.lua:

fx_version 'cerulean'
game 'gta5'
ui_page 'index.html'
files { 'index.html' }
client_script 'client.lua'

client.lua:

local visible = false
local ready = false

local function closePhone()
    visible = false
    SetNuiFocus(false, false)
    SendNUIMessage({ action = 'close' })
end

RegisterCommand('tutorial_phone', function()
    if not ready then
        print('Phone UI is loading; try again shortly.')
        return
    end
    if visible then closePhone(); return end
    visible = true
    SetNuiFocus(true, true)
    SendNUIMessage({ action = 'open' })
end, false)

RegisterNUICallback('ready', function(_, cb)
    ready = true
    cb({ ok = true })
end)

RegisterNUICallback('close', function(_, cb)
    closePhone()
    cb({ ok = true })
end)

AddEventHandler('onClientResourceStop', function(name)
    if name == GetCurrentResourceName() and visible then
        SetNuiFocus(false, false)
    end
end)

index.html:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Session note</title>
<style>
body { margin: 0; background: transparent; font: 18px system-ui; }
#phone { position: fixed; right: 4vw; bottom: 4vh; width: min(320px, 85vw);
  padding: 24px; box-sizing: border-box; color: #fff; background: #18222d;
  border-radius: 20px; }
[hidden] { display: none !important; }
textarea { box-sizing: border-box; width: 100%; min-height: 140px; font: inherit;
  margin: 12px 0; padding: 8px; }
button { font: inherit; padding: 10px 16px; cursor: pointer; }
:focus-visible { outline: 3px solid #67d7ff; outline-offset: 3px; }
</style>
</head>
<body>
<section id="phone" role="dialog" aria-label="Session note" hidden>
  <h1>Session note</h1>
  <label for="note">What will your character do next?</label>
  <textarea id="note" maxlength="500"></textarea>
  <p>This note clears when the resource restarts.</p>
  <button id="close" type="button">Close</button>
  <p id="error" role="status"></p>
</section>
<script>
const phone = document.getElementById('phone');
const note = document.getElementById('note');
const error = document.getElementById('error');
async function call(name) {
  const response = await fetch(`https://${GetParentResourceName()}/${name}`, {
    method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}'
  });
  if (!response.ok) throw new Error('NUI callback failed');
  return response.json();
}
window.addEventListener('message', ({ data }) => {
  if (data?.action === 'open') {
    phone.hidden = false; error.textContent = ''; note.focus();
  } else if (data?.action === 'close') {
    phone.hidden = true;
  }
});
async function close() {
  try { await call('close'); }
  catch { error.textContent = 'Could not close. Check the F8 console.'; }
}
document.getElementById('close').addEventListener('click', close);
window.addEventListener('keydown', event => {
  if (event.key === 'Escape' && !phone.hidden) { event.preventDefault(); close(); }
});
call('ready').catch(() => console.error('Phone readiness callback failed.'));
</script>
</body>
</html>

Iniciar y verificar

Añade ensure tutorial_phone a la configuración activa del servidor. En tu servidor de prueba, ejecuta refresh y ensure tutorial_phone, conéctate y luego ejecuta tutorial_phone en F8. La aplicación debería abrirse y enfocar su campo de notas.

Escribe una nota, ciérrala con el botón y vuelve a abrirla. La nota debería permanecer durante esta sesión de recursos. Prueba Escape, abrir/cerrar repetidamente y detener el recurso mientras está abierto; la entrada del juego debería liberarse. Volver a conectar o reiniciar el recurso crea una nueva sesión de interfaz de usuario y borra la nota.

Inspecciona el límite de la NUI

El navegador llama a la devolución de llamada del recurso por su nombre de padre real. Lua siempre responde a través de cb, y el navegador maneja una solicitud fallida. Sigue las instrucciones de depuración de NUI de Cfx.re para inspeccionar la consola y las solicitudes de devolución de llamada en tu cliente.

Añade funciones de teléfono reales deliberadamente

Un recurso de teléfono existente puede exponer su propio SDK de aplicación; usa esa integración compatible en lugar de ejecutar un segundo teléfono completo. Los contactos persistentes necesitan comprobaciones de propiedad de los personajes en el servidor, longitudes validadas, consultas parametrizadas y una migración para el esquema instalado.

Las llamadas reales necesitan la integración compatible del recurso de voz elegido. Nunca aceptes un identificador de personaje arbitrario de la interfaz de usuario como prueba de acceso, ni afirmes que un formulario de contactos es un sistema telefónico seguro completo.

Documentación de referencia

Cfx.re — callbacks de nui · Cfx.re — manifiesto de recursos