Exploración de la tecnología Flutter Hot Update | Equipo técnico de JD Cloud

1. Antecedentes de la demanda:

Después de que la aplicación se lanza al mercado, es inevitable que los errores graves impidan que los usuarios la usen. Por lo tanto, es necesario utilizar la tecnología de actualización en caliente para corregir los errores de inmediato sin lanzar una nueva versión de la aplicación. Los requisitos de actualización en caliente para aplicaciones nativas (p. ej., Android e IOS) son relativamente maduros, pero la pila de tecnología de Flutter actualmente carece de soluciones técnicas similares. Por lo tanto, el equipo de I+D de Flutter también necesita tecnologías de actualización en caliente similares.

2. Análisis de la dirección de la tecnología de actualización en caliente de Flutter:

Después del análisis, puede haber tres soluciones factibles: 1) Similar al marco RN, 2) Marco de componente dinámico de página, 3) Solución de personalización de máquina virtual Dart;

Nombre del programa principio ventaja defecto solución de código abierto
esquema similar a RN Use JS para escribir dart en la sintaxis de Flutter, luego use JavaScript para convertir XML DSL en componentes de widgets atómicos de Flutter, y luego deje que Flutter renderice Dado que el sistema ios tiene soporte integrado para js, las actualizaciones se pueden implementar en ios 1) Debido a la ejecución entre idiomas, tiene un impacto en el rendimiento; el costo de aprendizaje es alto 2) El lado de Android necesita introducir bibliotecas JS adicionales MXFlutter en Mobile QQ, Feria en 58.com
Esquema de componente dinámico de página Inserte/incruste previamente el DynamicWidget en el código durante la compilación, luego entregue dinámicamente los datos Json, haga coincidir la semántica acordada con los datos en JSON y reemplace dinámicamente el contenido del Widget para realizar la actualización. Puede admitir actualizaciones en ambos extremos de Android/iOS 1) La actualización de la interfaz de usuario es relativamente fácil, pero la lógica comercial dinámica es problemática; 2) Los costos de desarrollo del analizador semántico son relativamente altos y no es fácil de mantener; 3) Se necesita un conjunto completo de servicios y herramientas de front-end y back-end. requerido Tangram de Tmall, DinamicX de Taobao, etc.
Solución de personalización de máquinas virtuales Dart Al analizar el principio de la máquina virtual Dart, modifique el código Java/C++ de la capa Flutter Engine para lograr el objetivo de la actualización en caliente; Pequeño impacto en el rendimiento, alta dinámica, técnicamente puede reemplazar todas las páginas de Flutter (incluida la interfaz de usuario, la lógica, los archivos de recursos) Dado que se utiliza un motor personalizado, se deben mantener diferentes versiones del código del motor Flutter; No es de código abierto

Debido a que otros métodos tienen ejemplos de código abierto, este caso se centrará en la tercera "solución de personalización de la máquina virtual de Dart" como objetivo, e investigará y explicará la solución.

Tres, conocimiento preliminar

Antes de comenzar a comprender la solución técnica, debe comprender algunos conceptos técnicos correspondientes de antemano:

3.1 Modo de compilación Flutter

El lenguaje de desarrollo de Flutter es Dart, y su modo de compilación proviene del modo de compilación de Dart, que incluye principalmente JIT (Just In Time) y AOT (Ahead Of Time).

nombre del modo de compilación características ventaja defecto
JAT Compilación justo a tiempo, un ejemplo típico de V8, puede compilar y ejecutar JS en tiempo real, solo necesita ingresar la cadena del código fuente, puede compilar y ejecutar el código Puede entregar y ejecutar código dinámicamente, independientemente de la arquitectura de la CPU, y puede proporcionar contenido dinámico 1. Muchos códigos de cadena hacen que el compilador JIT gaste tiempo y memoria 2. El rendimiento no es bueno;
AOT Precompilado, un ejemplo típico de C/C++, compilado en código binario por GCC, y luego se puede cargar y ejecutar después de que la instalación obtenga el permiso. Carga y ejecución precompiladas y rápidas 1. La arquitectura de la CPU se distingue al compilar 2. El paquete de código binario generado es relativamente grande 3. El código binario necesita obtener permiso antes de que pueda ejecutarse y no puede actualizarse dinámicamente en el sistema ios

Los modos de compilación de Flutter son: Depuración, Lanzamiento, Perfil;

Modo de compilación flutter características
Depurar Corresponde al modo JIT, admite dispositivos y simuladores, permite aserciones, admite desarrollo rápido y admite HotReload, no optimiza el tamaño del paquete ni la velocidad de ejecución;
Liberar Corresponde al modo AOT, admite dispositivos reales, no admite emuladores, deshabilita toda la información de depuración de aserciones, optimiza el tamaño del paquete, la velocidad de inicio y ejecución;
Perfil Similar al modo Release, conserva algunas funciones de depuración para ayudar al análisis de rendimiento;

3.2 Análisis de productos de compilación Flutter

El proyecto iOS/Android bajo Flutter es esencialmente un proyecto iOS/Android estándar; Plataforma IOS: Flutter genera e integra App.framework y Flutter.framework en ios agregando shell (xcode_backend.sh) en BuildPhase; Plataforma Android: Flutter agrega flutter. jar y archivos binarios compilados para Android a través de gradle;

3.2.1 Análisis de la estructura de la capa del motor:

3.2.2 Análisis de productos compilados de Android

3.2.3 Análisis de productos de compilación de IOS

4. Análisis de soluciones tecnológicas de actualización en caliente

4.1 Análisis del código de negocio

De acuerdo con el análisis de "3.3.1" ~ "3.3.2", se puede determinar que los códigos comerciales de la aplicación IOS y Android están compuestos por cuatro segmentos: kDartVmSnapshotData, kDartVmSnapshotInstructions, kDartIsolateSnapshotData, kDartIsolateSnapshotInstructions; en teoría, siempre que el El segmento de código cargado se puede reemplazar dinámicamente y el código de segmento de datos para lograr el objetivo.

nombre nota efecto nota
kDartIsolateSnapshotData Dardo aislar segmento de datos Información de clase, variables globales, punteros de función, etc. Permitir entrega dinámica
kDartIsolateSnapshotInstrucciones Sección de directiva de aislamiento de dardos Contiene código AOT ejecutado por Dart aislado IOS no permite la entrega dinámica
kDartVmSnapshotData VM aislar segmento de datos El estado inicial del montón Dart compartido entre aislamientos Permitir entrega dinámica
kDartVmSnapshotInstrucciones segmento de instrucciones de aislamiento de vm Contiene instrucciones AOT para programas comunes compartidos entre todos los aislados de Dart en la VM IOS no permite la entrega dinámica

Nota: El significado de aislar, instantánea, aislar vm se explica a continuación:

nombre significado
aislar Dart es un único subproceso y aislar es similar a un subproceso, que puede entenderse como un subproceso en Dart. La diferencia entre aislar y subproceso: la memoria se comparte entre subprocesos, pero la memoria no se comparte entre aislar y aislar. No hay problema de competencia de bloqueo. Los dos Isolates son líneas de ejecución completamente independientes, y cada Isolate tiene su propio bucle de eventos. Solo pueden comunicarse entre sí mediante el envío de mensajes, por lo que su sobrecarga de recursos es menor que la de los hilos.
instantánea La información de clase, las variables globales y las instrucciones de función se almacenan directamente en el disco de manera serializada, lo que se denomina Instantánea (snapshot).
aislar Puede haber muchos aislamientos en el mismo proceso, pero las áreas de almacenamiento dinámico de dos aislamientos no se pueden compartir, por lo que el diseño oficial del aislamiento de VM, es decir, kDartVmSnapshot, se usa para la interacción entre múltiples aislamientos.

4.2 Análisis de carga del código comercial (tiempo de ejecución)

De acuerdo con la idea de análisis de 4.1, primero debemos comprender el proceso completo de carga de código cuando se ejecuta Flutter, y el proceso de análisis es el siguiente:

1) Proceso de carga del código comercial de la aplicación Android:

2) Proceso de carga del código comercial IOS-APP:

4.3 Compilación y generación de código comercial (al compilar)

De acuerdo con el análisis anterior, conocemos la estructura de datos del código comercial de Flutter y cómo cargarlo en tiempo de ejecución, por lo que solo necesitamos hacer cambios en tiempo de compilación para generar el segmento de código y el archivo de segmento de datos que necesitamos. Esto se logra cargando sus propios artefactos de compilación en tiempo de ejecución.

1) Aquí hay un análisis detallado del proceso de construcción de su propio código comercial con IOS:

** Hay un proceso de construcción completo que se puede analizar. El proceso básico es "Dart Code (código comercial)" -> (a través del compilador Dart gen_snapshot.cc) para generar el archivo de ensamblaje de snapshot_assemble.S -> (a través del herramienta xcrun) para generar el archivo obj snapshot_assemble.o -> App.Framework se genera (a través de la cadena de herramientas xcun clang).

2) El proceso de creación de productos de Android es similar al de IOS. Dado que Android tiene otras soluciones más simples, se omite el análisis detallado del proceso de construcción, más o menos como sigue:

4.4 Exploración de soluciones para realizar hot update

De acuerdo con los resultados del análisis técnico anterior, ya puede generar de forma independiente su propio segmento de código y archivos de segmento de datos. Al cambiar el código subyacente de la máquina virtual, también se puede cargar y ejecutar dinámicamente. Sin embargo, dado que el sistema subyacente actual del sistema IOS no puede cargar dinámicamente datos de segmentos de código legibles y escribibles en la memoria, aún existen dificultades técnicas que deben superarse. Sin embargo, hay un camino más simple para resolver en el lado de Android, por lo que a continuación se usa el lado de Android como ejemplo para enfocarse en el análisis de ideas, aproximadamente como se muestra en la siguiente figura:

Como se puede ver en la figura anterior, los pasos principales de la reparación en caliente en el lado de Android son los siguientes:

1. Modifique el código de Flutter Engine para cargar libapp.so y flutter_aasets en la ruta especificada, como el directorio privado (data/data/files);

2. Al compilar el APK, use el complemento Gradle Transform para reemplazar dinámicamente el motor oficial de Flutter de acuerdo con la versión del motor del SDK de Flutter y, finalmente, escriba el motor modificado en el APK;

3. Genere un paquete de parches: use el algoritmo BSdiff para comparar los archivos APK antiguos y nuevos, y genere un paquete de parches

4. Acceda a la interfaz de back-end cuando se inicia la aplicación y extraiga el paquete de parches de acuerdo con los parámetros (número de versión de la aplicación, número de versión del paquete de parches, md5, número de versión de flutter SDK, número de versión del motor);

5. Paquete de parche compuesto: verifique md5, número de versión de la aplicación, número de versión del parche, tiempo de instalación;

6. Personalice Flutter Engine para cargar los archivos de recursos libapp.so y flutter_assets en la ruta especificada;

 

Autor: Tecnología JD Liu Zhenzhong, Zhou Zhi

Fuente de contenido: comunidad de desarrolladores de JD Cloud

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4090830/blog/9092965
Recomendado
Clasificación