Usar cupom WELCOME para salvar 20%

$ USD
  • $ USD
  • € EUR
  • £ GBP
  • $ AUD
  • R$ BRL
  • Franco suíço Franco suíço
  • ¥ ienes
Crie um aplicativo personalizado para celular no FiveM

Crie um pequeno aplicativo de telefone FiveM com NUI

Crie primeiro um pequeno aplicativo NUI com aparência de telefone para aprender o ciclo completo de abertura, mensagem, callback e fechamento. Este exemplo mostra uma nota de sessão que permanece enquanto o recurso está em execução. Ele não tem chamadas, serviço de mensagens, banco de dados nem dependência de framework; adicionar essas funções exige autorização e persistência separadas no servidor.

Crie três arquivos

Crie resources/[local]/tutorial_phone/ com fxmanifest.lua, client.lua e index.html. O exemplo foi desenvolvido para o ambiente de execução de recursos gta5 do GTA V Legacy. Consulte as orientações de migração para Enhanced do Cfx.re antes de adaptá-lo a uma instalação 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 e verificar

Adicione ensure tutorial_phone à configuração ativa do servidor. No servidor de teste, execute refresh e ensure tutorial_phone, conecte-se e execute tutorial_phone no F8. O aplicativo deve abrir e colocar o foco no campo de notas.

Digite uma nota, feche pelo botão e abra novamente. A nota deve permanecer durante esta sessão do recurso. Teste Escape, abertura e fechamento repetidos e a parada do recurso enquanto estiver aberto; a entrada do jogo deve ser liberada. Reconectar ou reiniciar o recurso cria uma nova sessão da interface e apaga a nota.

Inspecione os limites da NUI

O navegador chama o callback do recurso pelo nome real do recurso que o contém. O Lua sempre responde por meio de cb, e o navegador trata as solicitações que falham. Siga as instruções de depuração de NUI do Cfx.re para inspecionar o console e as solicitações de callback no seu cliente.

Adicione funções reais de telefone de forma deliberada

Um recurso de telefone existente pode disponibilizar seu próprio SDK de aplicativos; use essa integração compatível em vez de executar um segundo telefone completo. Contatos persistentes precisam de verificações de propriedade do personagem no servidor, limites de tamanho validados, consultas parametrizadas e uma migração para o esquema instalado.

Chamadas reais precisam da integração compatível do recurso de voz escolhido. Nunca aceite um identificador arbitrário de personagem enviado pela interface como prova de acesso, nem afirme que um formulário de contatos é um sistema de telefone completo e seguro.

Documentação de referência

Cfx.re — callbacks de nui · Cfx.re — manifesto de recurso