Journal De l’utilisation des technologies web dans une application native.

Posté par (page perso) . Licence CC by-sa
Tags : aucun
10
21
août
2015

Sommaire

Introduction

Une des particularités du framework Epeios, c'est de faciliter le codage d'utilitaires en ligne de commande comme tmcq et dpkq. Concrètement, cela se traduit, par exemple, par le fait que de tels utilitaires prennent en charge les arguments de la ligne de commande sans que cela n'ait nécessité d'écrire la moindre ligne de code dédiée lors du codage de ces utilitaires, comme expliqué dans ce journal. Dans le même esprit, le framework Epeios s'enrichit de fonctionnalités pour la prise en charge d'applications avec interface graphique. L'idée est de déporter un maximum de fonctionnalités dédiées à la gestion d'interfaces graphiques dans le framework même, de manière à ne pas avoir à les recoder pour chaque nouvelle application.

En outre, il ne s'agit pas seulement de simplifier le développement d'interfaces graphiques, mais également d'offrir à l'utilisateur un moyen simple de personnaliser au maximum l'interface d'une application sans avoir à en modifier le code source. Mettre les sources d'une application à disposition de l'utilisateur pour qu'il puisse l'adapter à ses besoins, c'est bien, mais lui offrir la possibilité de la personnaliser sans avoir à modifier ces sources (surtout qu'en l’occurrence, il s'agit de sources C++), c'est mieux.

En fait, ce framework était déjà capable de prendre en charge la gestion d'interfaces graphiques. Je m’appuyais pour cela sur XULRunner, comme décrit dans ce journal (n.b. : le lien donné dans ce journal n'existe plus). Cependant, un bug rédhibitoire (pour moi) de XULRunner, et des doutes concernant la pérennité de XULRunner, m'ont poussé à l'abandonner, et à explorer d'autres technologies en vue de le remplacer.

HTML5

Comme, dans ce même journal, on m'avait bassiné avec Qt, je résolus d'essayer ce dernier. Mais je n'ai pas persévéré dans cette voie, leur approche ne me convenant pas. Je rappelle que je cherchais uniquement une technologie pour gérer les interface graphiques, ce qui était l'unique usage que j'avais de XULRunner, bien qu'il soit capable de beaucoup plus ; pour toute la partie traitement, j'ai le framework Epeios.

Coïncidence, à peu près au même moment fût publiée la version finalisée de HTML5, et j’entrepris donc d'explorer cette piste. Au final, pour l'usage que je comptais en faire, HTML5 s'est révélé être très proche de XUL (langage dont XULRunner est le moteur de rendu) ; je pouvais donc réutiliser pas mal d'outils que j'avais développés dans le cadre de mon utilisation de XULRunner.

Chromium Embedded Framework

Comme mon but était de trouver des technologies pour développer des applications natives (j'avais déjà ce qu'il me fallait pour développer des applications web), il me fallait trouver un moyen d'exécuter HTML5 dans ce contexte. Comme j'avais déjà Qt d’installé, j'ai essayé QtWebKit, mais certaines limitations de ce composant, ainsi que le fait de recourir à tout l'environnement de développement Qt pour n'utiliser que ce composant m’apparaissait totalement disproportionné, je me suis mis à la recherche d'un équivalent.

Qui dit HTML(5), dit JavaScript. La même chose vaut pour XULRunner, comme on me l'avait fait remarquer toujours dans ce fameux journal. J'y ai cependant détaillé les raisons pour lesquelles je préférais utiliser C++, au détriment de JavaScript, et c'est pour ces mêmes raisons que je j'utiliserais C++ avec HTML5. Restait, comme écrit, à trouver le moyen d’exécuter HTML5 dans un contexte natif. Ce moyen, je l'ai trouvé avec Chromium Embedded Framework (CEF).

xdhcefq

Un problème que j'avais lorsque j'utilisais XULRunner, c'est que ses fichiers d’en-tête polluaient les sources de mes applications. Pour éviter ce désagrément, je résolus de développer un utilitaire qui prenait en charge toutes les interactions avec CEF, le code proprement dit de traitement de l'interface graphique étant déporté dans une bibliothèque, bibliothèque dont le code source n'aura donc pas à inclure de fichier d'en-tête de CEF. Cet utilitaire, c'est xdhcefq.

A noter que les exemples d’utilisation qui sont donnés pour CEF s'appuient sur son API C++. Comme l'utilisation de cet API nécessitait la compilation de bibliothèques supplémentaires, j'ai préféré utiliser l'API C, qui ne nécessitait pas ces bibliothèques supplémentaires. Mais la mise en œuvre de CEF est nettement plus compliquée en passant par la version C de l'API. Cependant, comme je n'ai à me préoccuper de CEF que lors du développement de xdhcefq, et que, pour le développement des applications proprement dites, je n'aurais plus à me préoccuper de l'API (C ou C++) de CEF (ce qui est, je le rappelle, justement l'objet de xdhcefq), j'ai préféré recourir à l'API C, car elle moins contraignante.

xdhdq

L'ensemble des technologies concernant la gestion d'interfaces graphiques dans le framework Epeios est regroupé sous le vocable XDHTML. Ci-après, vous allez trouver les principes de base de cette technologie. Pour rendre cela plus concret, une petite application triviale, s'appelant xdhdq, a été développée. Cette application prend la forme d'une bibliothèque dynamique, qui est chargée par xdhcefq. C'est de cette application que les exemples ci-dessous sont tirés.

Si vous désirez approfondir, xdhdq est librement téléchargeable à partir de sa page dédiée. Elle vient avec xdhcefq, qui est indispensable pour la faire tourner. Elle est disponible pour GNU/Linux, OS X et Windows, avec architecture IA-32 et AMD64.

Génération des composants HTML de l'interface graphique

Le code HTML de l'interface n'est pas directement généré par l'application, mais est le résultat d'une transformation XSL sur des données XML fournies par l'application. Les fichiers XSL utilisé pour la transformation sont spécifiés dans le fichier de configuration de l’application. Des exemples de tels fichiers XSL sont visibles ici (ce sont ceux suffixés par Layout.xsl).

Gestion de l'accessibilité des éléments

Pour gérer l'accessibilité d'un élément (c'est-à-dire le fait qu'un élément ait un attribut comme hidden ou disabled de défini ou non) se fait à l'aide d'un élément et d'un attribut maison (respectivement xdh-cast et data-xdh-cast). L'attribut data-xdh-cast est affecté aux éléments concernés lors de l'opération décrite juste au-dessus, et la définition des éléments xdh-cast se fait, comme précédemment, à partir d'une transformation XSL sur des données XML générées par l’application. Les fichiers XSL utilisés pour cette transformation sont également spécifiés dans le fichier de configuration de l’application, et des exemples de tels fichiers sont également visibles ici (ce sont ceux suffixés par Casting.xsl).

Voici un exemple de déclaration (issu de PrologLayout.xsl) :

    <select data-xdh-cast="PredefinedProjectsCast">
        ...
    </select>

Et la définition correspondante (issue de PrologCasting.xsl):

    <xsl:template match="ProjectType">
        <xsl:variable name="Type" select="."/>
        <xsl:choose>
            <xsl:when test="$Type='New'">
                <xdh-cast id="PredefinedProjectsCast" kind="Hide"/>
            </xsl:when>
            <xsl:when test="$Type='Predefined'">
                <xdh-cast id="PredefinedProjectsCast" kind="Plain"/>
            </xsl:when>
            <xsl:when test="$Type='Remote'">
                <xdh-cast id="PredefinedProjectsCast" kind="Hide"/>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

Gestion d’événements

La gestion d’événement se fait grâce aux attributs data-xdh-onevent, pour définir un seul gestionnaire d’événement, ou data-xdh-onevents (avec un s à la fin), pour en définir plusieurs. Les événements déclenchent une action définie dans un callback écrit en C++ et pourvu d'un identifiant unique. La définition d'un gestionnaire d’événement consiste donc à indiquer un événement (mouseleave, click…) ainsi que l'identifiant de l'action à lui associer. Par exemple (tiré de MainLayout.xsl) :

<fieldset data-xdh-onevents="(mouseenter|HideFacetiousButton)|(mouseleave|ShowFacetiousButton)">

On peut omettre la spécification de l’événement, auquel cas ce sera l’événement par défaut qui sera utilisé (généralement click).

Il existe certains événements prédéfinis, qui peuvent prendre plusieurs paramètres. Par exemple (issu de PrologLayout.xsl) :

<button data-xdh-onevent="(OpenFile|DisplayProjectFilename|(#plgSelectProjectFile#|.xprj))">

Un clic (événement qui n'est pas spécifié, car c'est l’événement par défaut pour cet élément) sur ce bouton provoquera l'affichage d'une sélecteur de fichier (action prédéfinie OpenFile), avec, pour titre, le texte correspondant à l'identifiant plgSelectProjectFile (qui est défini dans la section Locale du fichier de configuration), et .xprjcomme filtre d'extension. Une fois le sélecteur fermé, l’action DisplayProjectFilename (qui est une action classique, c'est-à-dire qui correspond à un callback C++) est lancée.

Composants HTML et JQuery

De nombreux composants HTML d'interface graphique s'appuient sur JQuery, et, de ce fait, ont toujours quasiment le même code JavaScript d’instanciation. Pour éviter d'avoir à taper ce code, on peut recourir à l'attribut data-xdh-widget, par exemple de la manière suivante (tiré de FieldsLayout.xsl) :

<textarea data-xdh-widget="ckeditor|enterMode : CKEDITOR.ENTER_BR, linkShowTargetTab: false, language: '#fieldsLanguage#', startupFocus : true,|val\(\)|ckeditor\(\).editor.focus\(\)">

Cela crée un composant ckeditor, avec certains paramètres propres à ce composant (situés entre le premier et le second | ; voir le site du composant pour leurs significations). Comme la récupération du contenu de ce composant, ainsi que la manière de lui donner le focus, ne se fait pas de façon classique, le code JavaScript adéquat est précisé (respectivement val() et ckeditor().editor.focus() ; les \servent à échapper les caractères (et )).

Et maintenant ?

Il y a principalement deux projets en cours relatifs à la technologie XDHTML. Le premier consiste en une véritable application, à titre de POC évoluée, mais pleinement fonctionnelle et d'une réelle utilité. Le second consiste à développer l'équivalent de xdhcefq, mais pour les applications web. L'idée et d'avoir un seul et même code C++, et pour la version native, et pour la version web d'une application (il restera néanmoins possible, si désiré, d'adapter l'interface pour l'une ou l'autre type d'application).

  • # Qt, QML

    Posté par (page perso) . Évalué à 8.

    on m'avait bassiné avec Qt, je résolus d'essayer ce dernier. Mais je n'ai pas persévéré dans cette voie, leur approche ne me convenant pas.

    Qu'est-ce qui ne te convenait pas dans Qt et QML?
    C'est fait exactement pour faire des interface graphique.
    Alors que HTML est un gros hack. Si tu fait du natif, alors je vois pas l'interrêt de se restreindre au limitations du HTML qui est conçu pour faire des pages web.

    • [^] # Re: Qt, QML

      Posté par . Évalué à 4.

      J'ai aussi une préférence pour des bibliothèques natives, mais j'ai l'impression qu'elles récoltent un peu ce qu'elles ont semé. L'innovation ces derniers temps est très limité, ce qu'on voit arriver c'est du déclaratif. C'est super, mais c'est ce qu'il y a déjà avec une stack web. Là où les frameworks graphiques pourraient innover c'est en ajoutant des widgets récents (des pine-menu par exemple), des interfaces responsives plus facilement,…

      S'il est difficile de voir l'apport d'une bibliothèque graphique, sur une pile HTML/CSS/JS/Bootstrap, pourquoi les gens ferraient autre chose ?

      Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

    • [^] # Re: Qt, QML

      Posté par . Évalué à 8.

      Alors que HTML est un gros hack. Si tu fait du natif, alors je vois pas l'interrêt de se restreindre au limitations du HTML qui est conçu pour faire des pages web.

      Le bon gros mantra qu'on annone bêtement depuis 10 ans : « HTML c'est pas fait pour faire des applications », et que je commence franchement à avoir marre d'entendre. C'était sûrement vrai y'a 10 ans, mais plus maintenant. Faut savoir mettre à jour ses parti pris. Section 1.1 de la spécification HTML5 (Introduction, Background):

      The main area that has not been adequately addressed by HTML is a vague subject referred to as Web Applications. This specification attempts to rectify this, while at the same time updating the HTML specifications to address issues raised in the past few years.

      C'est la deuxième phrase du document. HTML5 a été explicitement conçu pour faciliter l'écriture d'application web. Une section complète (Section 6, Web application APIs) est dédiée aux applications Web.

      Alors oui, je sais c'est "un gros hack". Ah bon. C'est ça l'esprit "hack", bidouille, détournement de l'usage initial cher aux libristes/hackers ? À la base tout était un gros hack, le language C n'était qu'un gros hack pour éviter d'avoir à écrire Unix en assembleur. Linux était une bidouille d'étudiant etc. La question n'est pas de savoir si HTML est fait pour faire telle chose, mais si HTML marche pour faire telle chose. Les applications web ont plein de bonnes propriétés par rapport aux applications natives: très facilement distribuables, collaboration entre plusieurs utilisateurs facilitée etc. Tout ça fait que beaucoup de gens développent des applications web, et donc des frameworks pratiques pour développer ces applications. On peut avoir envie de réutiliser des frameworks web ou même simplement les connaissances qu'on maîtrise (HTML, CSS, JS) pour faire des applications natives. Ensuite un moteur de rendu HTML + Javascript, c'est une base facile à utiliser pour développer son propre framework d'interface graphique.

      Après, ça n'empêche pas de critiquer les limitations de HTML pour faire des interfaces graphiques (ex: communication particulièrement lourde via des appels HTTP entre l'UI et le cœur de l'application, lenteur de certains widgets complexes, complexité de la pile logicielle etc.). Juste l'argument de "c'est pas fait pour ça" est irrecevable.

    • [^] # Re: Qt, QML

      Posté par (page perso) . Évalué à 2.

      C'est juste qu'avec HTML, je pouvais ajouter des éléments et attributs maisons (les fameux xdh-... et data-xdh-... du journal) qu'il était facile de traiter avec des outils DOM classiques, alors qu'avec le JSON-like de QML je ne pouvais pas (ou je n'ai pas trouvé comment) faire la même chose.
      Au final, c'est surtout, comme indiqué à la fin du journal, la perspective de pouvoir avoir un seul et même code (C++ qui plus est) pour la version web et la version native d'une application qui m'a fait préférer HTML à Qt et consorts.

      Freelance en ingénierie informatique.

    • [^] # Re: Qt, QML

      Posté par (page perso) . Évalué à 5.

      Si tu fait du natif, alors je vois pas l'interrêt de se restreindre au limitations du HTML qui est conçu pour faire des pages web.

      Le problème ce n'est pas HTML, mais Javascript :-)

      http://devnewton.bci.im

      • [^] # Re: Qt, QML

        Posté par . Évalué à 4.

        Donc QtQuick/QML n'est pas la solution :)

        Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

  • # NW

    Posté par (page perso) . Évalué à -1.

    Je ne comprends pas vraiment l'intérêt de rester sur du C++ dans ce cas précis, si je devais développer une application native en utilisant les technologies du web je me tournerais plutôt vers http://nwjs.io/ .

    • [^] # Re: NW

      Posté par (page perso) . Évalué à 4.

      Mon but n’est pas d'utiliser à tout prix des technologies web. Il se trouve que HTML5, typiquement une techno web, est un bon candidat pour remplacer XUL, que je voulais abandonner pour les raisons citées dans le journal. Par contre, j'utilisais déjà C++ avec XUL (alors que, tout comme avec HTML, l'usage est également d'utiliser JavaScript), et cela fonctionnait parfaitement, donc je n'avais aucune raison de passer à JavaScript.

      Freelance en ingénierie informatique.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.