Aller au contenu
RPScripts

Créer une petite application de téléphone FiveM avec NUI

Par Luke

Créer une application mobile FiveM personnalisée

Commencez par créer une petite application NUI de type téléphone pour apprendre l'intégralité du cycle de vie : ouverture, message, callback et fermeture. Cet exemple affiche une note de session qui persiste pendant l'exécution de la ressource. Il n'a ni appels, ni service de messagerie, ni base de données, ni dépendance à un framework ; les ajouter nécessite une autorisation côté serveur et une persistance distinctes.

Créez trois fichiers

Créer resources/[local]/tutorial_phone/ avec fxmanifest.lua, client.lua et index.html. L'exemple cible le GTA V Legacy gta5 runtime. Vérifiez les directives de migration améliorées de Cfx.re avant de l'adapter à un déploiement amélioré.

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>

Démarrer et vérifier

Ajouter ensure tutorial_phone à la configuration serveur active. Sur votre serveur de test, exécutez refresh et ensure tutorial_phone, connectez-vous, puis exécutez tutorial_phone dans F8. L’application doit s’ouvrir et placer le focus sur son champ de note.

Saisissez une note, fermez avec le bouton puis rouvrez. La note doit être conservée pendant cette session de la ressource. Testez Escape, des ouvertures/fermetures répétées et l’arrêt de la ressource alors qu’elle est ouverte ; les commandes du jeu doivent être libérées. Une reconnexion ou un redémarrage de la ressource crée une nouvelle session d’UI et efface la note.

Inspecter la frontière NUI

Le navigateur appelle le callback de la ressource par son nom de parent réel. Lua répond toujours via cb, et le navigateur gère une requête échouée. Suivez les instructions de débogage NUI de Cfx.re pour inspecter la console et les requêtes de callback sur votre client.

Ajoutez de véritables fonctionnalités de téléphone de manière délibérée

Une ressource de téléphone existante peut exposer son propre SDK d’applications ; utilisez cette intégration prise en charge plutôt que de faire tourner un second téléphone complet. Des contacts persistants nécessitent des vérifications de propriété du personnage côté serveur, des longueurs validées, des requêtes paramétrées et une migration pour le schéma installé.

Les véritables appels nécessitent l’intégration prise en charge de la ressource vocale choisie. N’acceptez jamais un identifiant de personnage arbitraire provenant de l’UI comme preuve d’accès, et n’affirmez pas qu’un formulaire de contacts constitue un système téléphonique complet et sécurisé.

Documentation de référence

Cfx.re — callbacks nui · Cfx.re — manifeste de ressource

Sélection premium pour ton serveur

  • téléphone haut
    • ESX
    • QBCore
    38,99 $US34,99 €29,99 £GB56,99 $AU198,99 R$32,99 CHF6 170 JPY
  • Téléphone Yordi
    • ESX
    19,99 $US17,99 €15,99 £GB28,99 $AU101,99 R$16,99 CHF3 160 JPY
  • Chezza V2

    Chezza Phone V2

    Chezza Studios

    • ESX
    • QBCore
    31,00 $US27,99 €23,99 £GB44,99 $AU157,99 R$25,99 CHF4 900 JPY
  • téléphone
    • ESX
    24,99 $US22,99 €18,99 £GB35,99 $AU127,99 R$20,99 CHF3 950 JPY
Tout Scripts téléphone