Skip to content

Le cycle de rendu ​

Même famille d'idée que Flutter : un arbre de composants, un moteur de layout à contraintes, un moteur de peinture. La différence tient en une phrase : l'exécution se fait côté serveur PHP embarqué sur l'appareil, pas dans le process de l'app comme le fait le runtime Dart.

  1. NativeRenderPocActivity (Kotlin) fait une requête GET /native/layout-demo?screen=...&width=...&height=... vers le serveur PHP embarqué (php -S en dev, un process PHP intégré sur l'appareil).
  2. public/index.php route vers Engine\App\{Screen}::build($screenWidth, $screenHeight), qui retourne un arbre de Widget (Engine\Native\*, package phpnitro/ui).
  3. Une passe de layout descendante : chaque nœud reçoit des Constraints (min/max largeur/hauteur — le BoxConstraints de Flutter, porté tel quel) et retourne la Size qu'il occupe.
  4. Une passe de peinture parcourt le même arbre et empile des commandes de dessin plates ({"type":"rect",...}, {"type":"text",...}) dans un Canvas, en coordonnées absolues.
  5. Canvas::toJson() sérialise {commands, hitRegions, heroRegions, contentHeight, renderTimeMs, ...} en une seule réponse.
  6. NativeCanvasView.kt parse cette réponse et rejoue les commandes sur un vrai Canvas dans onDraw().

Chaque interaction refait ce cycle

Un tap envoie une nouvelle requête HTTP avec ?action=..., PHP recalcule tout l'écran (typiquement quelques millisecondes, mesurées et renvoyées via renderTimeMs), le client rejoue le nouveau jeu de commandes. Pas de diffing d'arbre virtuel côté client, pas d'état PHP qui survit entre deux requêtes — un tap sur un bouton est un process PHP indépendant du précédent. Tout ce qui doit persister vit dans $_SESSION, Engine\Preferences\Preferences, ou une vraie base de données (Doctrine DBAL, SQLite par défaut).

Un moteur de rendu partagé, en Rust ​

L'étape 6 ci-dessus (rejouer les commandes de dessin) était à l'origine réécrite indépendamment sur chaque plateforme — quatre moteurs séparés à faire évoluer en parallèle à chaque nouvelle fonctionnalité du protocole. Ils ont été remplacés par un seul moteur, écrit une fois en Rust (tiny-skia+cosmic-text), exposé via une interface C que chaque plateforme consomme (ctypes en Python, P/Invoke en C#, l'interop C de Swift, JNI en Kotlin).

Ce moteur couvre aujourd'hui l'intégralité du protocole : formes de base avec gradients/ombres portées, texte/icônes, images inline, animations (spinners, skeletons), curseurs et panneaux/listes déroulantes imbriqués — avec leur interactivité live, pas seulement leur état "au repos" —, et les transitions crossfade + hero (élément partagé qui "vole" d'un écran à l'autre) — porté formule par formule depuis l'implémentation Android d'origine, seule plateforme qui avait ça avant.

Il est le moteur de production sur Linux (par défaut) et Windows (seul chemin possible, cette plateforme n'a jamais eu de moteur natif). Sur Android et iOS, les liaisons existent et compilent, mais aucun test sur un vrai appareil n'a été possible jusqu'ici — le moteur natif historique (android.graphics.Canvas / Core Graphics, décrits ci-dessous) reste donc le chemin de production sur ces deux plateformes, par choix, pas par oubli. Voir Desktop pour le détail par plateforme.

État du projet ​

Le moteur de rendu natif Android est vérifié sur device réel : layout à contraintes complet, une cinquantaine de widgets (Scaffold, Flex, Button, LazyList...), animations implicites, geste de glisser 100% côté client (Dismissible), impression PDF native, une quarantaine de capacités device (caméra, biométrie, NFC, traduction ML Kit...).

Côté iOS : le moteur de rendu (Core Graphics), le hit-testing, le rendu d'icônes, la parité de commandes de dessin, une vraie boucle de fetch réseau et une pile d'écrans sont écrits et testés en continu (compilation + tests unitaires réels sur macos-14 en CI) — mais rien n'a encore tourné sur un simulateur ou un device réel (pas de Mac disponible pour l'instant), et le PHP embarqué sur iOS (SAPI embed) reste le plus gros chantier restant, pas encore commencé.

Ce qu'il reste pour rivaliser vraiment ​

Sans enjoliver : le modèle HTTP-par-interaction n'est pas du diffing d'arbre virtuel ni du hot-reload avec état préservé (juste rapide — quelques ms par écran), et ce n'est pas un simple oubli : PHP n'a pas de mécanisme natif pour re-définir le code d'une classe dont des instances vivent déjà, contrairement à la VM Dart. L'accessibilité (lecteur d'écran), elle, est confirmée fonctionnelle sur device réel (arbre de nœuds virtuel exposé via hitRegions, vérifié avec uiautomator sur un Infinix X6532). Il n'existe en revanche aucun test E2E automatisé sur émulateur/device Android au-delà de php -l + PHPUnit + curl + un vrai build Gradle. iOS reste le chantier le plus lourd — le PHP embarqué n'existe pas encore, faute de Mac disponible.

PhpNitro est un produit FINANFA TECH — Publié sous licence MIT.