Exploration de la technologie Flutter Hot Update | Équipe technique JD Cloud

1. Contexte de la demande :

Après la mise sur le marché de l'APP, il est inévitable que de graves bogues empêchent les utilisateurs de l'utiliser. Par conséquent, il est nécessaire d'utiliser la technologie de mise à jour à chaud pour corriger immédiatement les bogues sans publier une nouvelle version de l'APP. Les exigences de mise à jour à chaud pour les applications natives (par exemple Android et IOS) sont relativement matures, mais la pile technologique Flutter manque actuellement de solutions techniques similaires.Par conséquent, l'équipe de R&D Flutter a également besoin de technologies de mise à jour à chaud similaires.

2. Analyse de la direction de la technologie de mise à jour à chaud Flutter :

Après analyse, il peut y avoir trois solutions possibles : 1) similaire au framework RN ; 2) framework de composants dynamiques de page ; 3) solution de personnalisation de la machine virtuelle Dart ;

Nom du programme principe avantage défaut solution open-source
Schéma de type RN Utilisez JS pour écrire dart dans la syntaxe Flutter, puis utilisez JavaScript pour convertir XML DSL en composants de widget atomiques de Flutter, puis laissez Flutter rendre Étant donné que le système ios a un support intégré pour js, les mises à jour peuvent être implémentées sur ios 1) En raison de l'exécution en plusieurs langues, cela a un impact sur les performances ; le coût d'apprentissage est élevé 2) Le côté Android doit introduire des bibliothèques JS supplémentaires MXFlutter sur Mobile QQ, juste sur 58.com
Schéma de composants dynamiques de page Insérez/pré-intégrez le DynamicWidget dans le code lors de la compilation, puis livrez dynamiquement les données Json, faites correspondre la sémantique convenue aux données dans le JSON, et remplacez dynamiquement le contenu du Widget pour réaliser la mise à jour Peut prendre en charge les mises à jour aux deux extrémités d'Android/iOS 1) La mise à jour de l'interface utilisateur est relativement facile, mais la logique métier dynamique est gênante ; 2) Les coûts de développement de l'analyseur sémantique sont relativement élevés et sa maintenance n'est pas facile ; 3) Un ensemble complet de services et d'outils frontaux et principaux est requis Tangram de Tmall, DinamicX de Taobao, etc.
Solution de personnalisation de machine virtuelle Dart En analysant le principe de la machine virtuelle Dart, modifier le code Java/C++ de la couche Flutter Engine pour atteindre l'objectif de mise à jour à chaud ; Faible impact sur les performances, dynamique élevée, peut techniquement remplacer toutes les pages Flutter (y compris l'interface utilisateur, la logique, les fichiers de ressources) Puisqu'un moteur personnalisé est utilisé, différentes versions du code du moteur Flutter doivent être maintenues ; Non open source

Étant donné que d'autres méthodes ont des exemples open source, ce cas se concentrera sur la troisième "solution de personnalisation de machine virtuelle Dart" comme objectif, et effectuera des recherches et des explications sur la solution.

Trois, connaissances préliminaires

Avant de commencer à comprendre la solution technique, vous devez comprendre à l'avance certains concepts techniques correspondants :

3.1 Mode de compilation flottant

Le langage de développement de Flutter est Dart, et son mode de compilation est issu du mode de compilation de Dart, incluant principalement JIT (Just In Time) et AOT (Ahead Of Time).

nom du mode de compilation caractéristiques avantage défaut
Juste à temps Compilation juste-à-temps, un exemple typique de V8, il peut compiler et exécuter JS en temps réel, il suffit d'entrer la chaîne de code source, vous pouvez compiler et exécuter le code Il peut fournir et exécuter du code de manière dynamique, quelle que soit l'architecture du processeur, et peut fournir un contenu dynamique 1. De nombreux codes de chaînes font perdre du temps et de la mémoire au compilateur JIT 2. Les performances ne sont pas bonnes ;
AOAT Pré-compilé, un exemple typique de C/C++, compilé en code binaire par GCC, puis peut être chargé et exécuté une fois que l'installation a obtenu l'autorisation Pré-compilé, chargement et exécution rapides 1. L'architecture du processeur est distinguée lors de la compilation ; 2. Le package de code binaire généré est relativement volumineux ; 3. Le code binaire doit obtenir une autorisation avant de pouvoir être exécuté et ne peut pas être mis à jour dynamiquement sur le système ios

Les modes de compilation Flutter sont : Debug, Release, Profile ;

Mode de compilation flottant caractéristiques
Déboguer Correspond au mode JIT, prend en charge les appareils et les simulateurs ; permet les assertions, prend en charge le développement rapide et prend en charge HotReload ; n'optimise pas la taille du package et la vitesse d'exécution ;
Libérer Correspond au mode AOT, prend en charge les appareils réels, ne prend pas en charge les émulateurs ; désactive toutes les informations de débogage d'assertion ; optimise la taille du paquet, le démarrage et la vitesse d'exécution ;
Profil Semblable au mode Release, il conserve certaines fonctions de débogage pour faciliter l'analyse des performances.

3.2 Analyse du produit de compilation Flutter

Le projet iOS/Android sous Flutter est essentiellement un projet iOS/Android standard ; Plate-forme IOS : Flutter génère et intègre App.framework et Flutter.framework dans ios en ajoutant un shell (xcode_backend.sh) dans BuildPhase ; Plate- forme Android : Flutter ajoute flutter. jar et fichiers binaires compilés vers Android via gradle ;

3.2.1 Analyse de la structure de la couche moteur :

3.2.2 Analyse des produits compilés Android

3.2.3 Analyse des produits de compilation IOS

4. Analyse des solutions technologiques de mise à jour à chaud

4.1 Analyse du code des affaires

Selon l'analyse de "3.3.1" ~ "3.3.2", il peut être déterminé que les codes commerciaux IOS et Android APP sont composés de quatre segments : kDartVmSnapshotData, kDartVmSnapshotInstructions, kDartIsolateSnapshotData, kDartIsolateSnapshotInstructions ; en théorie, tant que le le segment de code chargé peut être remplacé dynamiquement et le code du segment de données pour atteindre l'objectif.

nom note effet note
kDartIsolateSnapshotData Dart isoler le segment de données Informations de classe, variables globales, pointeurs de fonction, etc. Autoriser la livraison dynamique
kDartIsolateSnapshotInstructions Section de la directive d'isolement des fléchettes Contient du code AOT exécuté par Dart isolate IOS ne permet pas la livraison dynamique
kDartVmSnapshotData vm isoler le segment de données L'état initial du tas Dart partagé entre les isolats Autoriser la livraison dynamique
kDartVmSnapshotInstructions vm isoler le segment d'instructions Contient des instructions AOT pour les programmes communs partagés entre tous les isolats Dart de la machine virtuelle IOS ne permet pas la livraison dynamique

Remarque : La signification de isolate, snapshot, vm isolate est expliquée comme suit :

nom signification
isoler Dart est un thread unique et isolate est similaire à un thread, qui peut être compris comme un thread dans Dart. La différence entre isolate et thread : la mémoire est partagée entre les threads, mais la mémoire n'est pas partagée entre isolate et isolate. Il n'y a pas de problème de concurrence de verrouillage. Les deux isolats sont des lignes d'exécution complètement indépendantes, et chaque isolat a sa propre boucle d'événements. Ils ne peuvent communiquer entre eux qu'en envoyant des messages, de sorte que leur surcharge de ressources est inférieure à celle des threads.
instantané Les informations de classe, les variables globales et les instructions de fonction sont directement stockées sur le disque de manière sérialisée, appelée Snapshot (instantané).
VM isoler Il peut y avoir de nombreux isolats dans le même processus, mais les zones de tas de deux isolats ne peuvent pas être partagées, de sorte que la conception officielle de l'isolat VM, c'est-à-dire kDartVmSnapshot, est utilisée pour l'interaction entre plusieurs isolats.

4.2 Chargement de l'analyse du code métier (runtime)

Selon l'idée d'analyse de 4.1, nous devons d'abord comprendre le processus complet de chargement du code lorsque Flutter s'exécute, et le processus d'analyse est le suivant :

1) Processus de chargement du code d'entreprise Android-APP :

2) Processus de chargement du code métier IOS-APP :

4.3 Compilation et génération du code métier (à la compilation)

Selon l'analyse ci-dessus, nous connaissons la structure de données du code métier Flutter et comment le charger au moment de l'exécution, nous n'avons donc qu'à apporter des modifications au moment de la compilation pour générer le segment de code et le fichier de segment de données dont nous avons besoin. Ceci est réalisé en chargeant vos propres artefacts de build lors de l'exécution.

1) Voici une analyse détaillée du processus de construction de votre propre code métier avec IOS :

** Il existe un processus de construction terminé qui peut être analysé. Le processus de base est "Dart Code (code métier)" -> (via le compilateur Dart gen_snapshot.cc) pour générer le fichier d'assemblage de snapshot_assemble.S -> (via le outil xcrun) pour générer le fichier obj snapshot_assemble.o -> App.Framework est généré (via la chaîne d'outils xcun clang).

2) Le processus de construction du produit Android est similaire à celui d'IOS. Étant donné qu'Android propose d'autres solutions plus simples, l'analyse détaillée du processus de construction est omise, à peu près comme suit :

4.4 Exploration de solutions pour réaliser une mise à jour à chaud

Selon les résultats de l'analyse technique ci-dessus, vous pouvez déjà générer indépendamment vos propres fichiers de segments de code et de segments de données. En modifiant le code sous-jacent de la machine virtuelle, celle-ci peut également être chargée et exécutée de manière dynamique. Cependant, étant donné que le système sous-jacent actuel du système IOS ne peut pas charger dynamiquement des données de segment de code lisibles et inscriptibles dans la mémoire, il existe encore des difficultés techniques qui doivent être surmontées. Cependant, il existe un chemin plus simple à résoudre du côté Android, donc ce qui suit utilise le côté Android comme exemple pour se concentrer sur l'analyse des idées, à peu près comme indiqué dans la figure suivante :

Comme le montre la figure ci-dessus, les principales étapes de la réparation à chaud du côté Android sont les suivantes :

1. Modifiez le code du moteur Flutter pour charger libapp.so et flutter_aasets dans le chemin spécifié, tel que le répertoire privé (data/data/files) ;

2. Lors de la compilation de l'APK, utilisez le plug-in Gradle Transform pour remplacer dynamiquement le moteur Flutter officiel en fonction de la version du moteur du SDK Flutter, puis écrivez le moteur modifié dans l'APK ;

3. Générez un package de correctifs : utilisez l'algorithme BSdiff pour comparer les anciens et les nouveaux fichiers APK, et générez un package de correctifs.

4. Accédez à l'interface principale lorsque l'APP démarre et extrayez le package de correctifs en fonction des paramètres (numéro de version de l'application, numéro de version du package de correctifs, md5, numéro de version du SDK flutter, numéro de version du moteur);

5. Package de correctifs composites : vérifiez md5, le numéro de version de l'application, le numéro de version du correctif, l'heure d'installation ;

6. Personnalisez le moteur Flutter pour charger les fichiers de ressources libapp.so et flutter_assets dans le chemin spécifié ;

 

Auteur : JD Technology Liu Zhenzhong, Zhou Zhi

Source de contenu : communauté de développeurs JD Cloud

{{o.name}}
{{m.name}}

Je suppose que tu aimes

Origine my.oschina.net/u/4090830/blog/9092965
conseillé
Classement