Saltar al contenido principal

Construir herramientas personalizadas en DevTools de Flutter y Dart

¿Alguna vez has querido construir herramientas de desarrollo para Dart y Flutter pero no sabías por dónde empezar? ¿O tal vez no querías pasar por todo el trabajo de establecer una conexión con una aplicación Dart o Flutter en ejecución para acceder a datos de depuración? Luego, incluso si creaste una herramienta de desarrollo, ¿cómo la desplegarías o les darías a los usuarios un acceso fácil a ella? Puedes crear herramientas de desarrollo sin todos estos obstáculos.

Con el framework de extensiones de DevTools de Dart & Flutter, puedes construir fácilmente herramientas de desarrollo que están estrechamente integradas con la suite de herramientas existente de DevTools. Las extensiones se construyen usando Flutter web y aprovechan los frameworks y utilidades existentes de DevTools para simplificar la experiencia de creación de herramientas para desarrolladores.

Extensión de DevTools de ejemplo para package:foo

¿Cómo funcionan las extensiones de DevTools?

#

Las extensiones se envían como parte de un paquete pub. Puedes añadir una extensión de DevTools a un paquete pub existente, o puedes crear un nuevo paquete que proporcione solo una extensión de DevTools. En ambos escenarios, el usuario final debe listar una dependencia del paquete que proporciona la extensión de DevTools para poder ver la extensión en DevTools.

Por ejemplo, imagina que tenemos algún package:foo, y este paquete proporciona una extensión de DevTools. Cuando un usuario depende de package:foo en su app, obtiene automáticamente acceso a la extensión de DevTools proporcionada por este paquete. Cuando DevTools detecta que la extensión package:foo está disponible, basándose en la información de la app del usuario o de su IDE, se añadirá una nueva pestaña "Foo" a DevTools que contiene las herramientas de desarrollo proporcionadas por package:foo.

Diagrama que muestra cómo funciona una extensión de DevTools

Algunos ejemplos de paquetes que han añadido una extensión de DevTools a un paquete existente son package:shared_preferences, package:provider, package:patrol y package:drift.

¿Qué tipos de herramientas son compatibles?

#

Con el framework de extensiones de DevTools puedes construir muchos tipos de herramientas, incluyendo:

  • Herramientas complementarias para paquetes existentes.
  • Nuevas herramientas que se envían como su propio paquete.
  • Herramientas que interactúan con una aplicación en ejecución.
  • Herramientas que interactúan con archivos de proyecto abiertos en el IDE.
  • Herramientas que interactúan con el servidor de análisis.

El framework de Extensiones de DevTools viene con características listas para usar que hacen que la distribución de tu extensión a los usuarios sea fluida. Por ejemplo, los usuarios pueden:

  • Usa tu herramienta desde DevTools en el navegador.
  • Usa tu herramienta incrustada directamente en su IDE.
  • Descubre y abre tu herramienta desde los IDEs compatibles con Dart y Flutter.

A continuación, aprende cómo escribir una extensión de DevTools.


Escribir una extensión de DevTools

#

Antes de comenzar, necesitas:

  • Flutter SDK >= 3.17 & Dart SDK >= 3.2.
  • Un paquete pub que (en tu opinión) necesita una extensión personalizada de DevTools.

Configura la jerarquía de tu paquete

#

Proporcionarás ya sea una extensión independiente o una extensión complementaria.

Extensión independiente

#

Para una extensión independiente (que no se envía como parte de un paquete pub existente), tu extensión puede incluir código fuente en el mismo paquete con el que se envía la extensión. Esto simplifica el desarrollo, y dado que los usuarios de tu paquete añadirán tu paquete como una dev_dependency, el tamaño de tu paquete no afectará el tamaño de la app del usuario. La estructura de tu paquete se verá como la siguiente:

yaml
my_new_tool
  extension/
    devtools/
      build/
        ...  # pre-compiled output of the Flutter web app under lib/
      config.yaml
  lib/  # source code for your extension Flutter web app
    src/
      ...

Dado que la extensión se construye como una app web de Flutter, usa flutter create para generar el paquete:

flutter create --template app --platforms web my_new_tool

A continuación, usa el paquete my_new_tool para configurar tu extensión en el siguiente paso.

Extensiones complementarias

#

Para una extensión complementaria (que se envía como parte de un paquete pub existente), considera colocar el código fuente de tu extensión fuera de tu paquete pub. Esto mantiene el tamaño de tu paquete lo más pequeño posible, para evitar inflar el tamaño de las apps de los usuarios que dependen de tu paquete. Aquí está la estructura de paquete recomendada:

yaml
foo/  # formerly the repository root of your pub package
  packages/
    foo/  # your pub package
      extension/
        devtools/
          build/
            ...  # pre-compiled output of foo_devtools_extension/lib
          config.yaml
    foo_devtools_extension/
      lib/  # source code for your extension Flutter web app

Configura tu extensión

#

En el paquete Dart que proporciona la extensión de DevTools a los usuarios, añade un directorio de extensión de nivel superior:

yaml
foo/
  extension/
  lib/
  ...

Bajo el directorio extension, crea la siguiente estructura exactamente como se muestra:

yaml
extension/
  devtools/
    build/
    config.yaml

El archivo config.yaml contiene metadatos que DevTools necesita para cargar la extensión:

yaml
name: foo
version: 0.0.1
issueTracker: <link_to_your_issue_tracker.com>
materialIconCodePoint: '0xe0b1'
requiresConnection: true  # optional field - defaults to true

Copia el contenido del archivo config.yaml como se muestra y pégalo en el archivo config.yaml que acabas de crear en tu paquete. Es importante que uses el nombre de archivo y los nombres de campo exactos como se muestra, o de lo contrario tu extensión podría no cargarse en DevTools.

Para cada clave, completa el valor apropiado para tu paquete.

  • name: El nombre del paquete para esta extensión de DevTools. El valor de este campo se usa en la barra de título de la página de la extensión. [requerido]
  • version: La versión de tu extensión de DevTools. Este número de versión debería evolucionar con el tiempo a medida que envíes nuevas características para tu extensión. El valor de este campo se usa en la barra de título de la página de la extensión. [requerido]
  • issueTracker: La URL para tu rastreador de problemas (issue tracker). Cuando un usuario hace clic en el enlace Report an issue en la UI de DevTools, se le redirige a esta URL. [requerido]

Barra de título de la pantalla de extensión de DevTools

  • materialIconCodePoint: Corresponde al valor codepoint de un icono de material/icons.dart. Este icono se usa para la pestaña de la extensión en la barra de pestañas superior de DevTools. [requerido]

Icono de pestaña de extensión de DevTools

  • requiresConnection: Indica si la extensión requiere una app Dart o Flutter conectada para usarse. Este es un campo opcional que por defecto será true si no se especifica. [opcional]

Para obtener la documentación más actualizada sobre la especificación de config.yaml, visita extension_config_spec.md.

Construye tu extensión

#

Usa los siguientes pasos para construir una extensión.

Crea la app web de Flutter

#

Desde el directorio donde deseas que viva el código fuente de tu extensión, ejecuta el siguiente comando, reemplazando foo_devtools_extension con <nombre_de_tu_paquete>_devtools_extension:

flutter create --template app --platforms web foo_devtools_extension

Añade la dependencia package:devtools_extensions

#
flutter pub add devtools_extensions

Es probable que también desees añadir una dependencia en package:devtools_app_shared, que contiene servicios compartidos, utilidades y componentes de UI para usar mientras construyes tu extensión. Visita devtools_app_shared/example para ver usos de ejemplo.

flutter pub add devtools_app_shared

Añade el widget DevToolsExtension

#

En lib/main.dart, añade las siguientes importaciones:

dart
import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const FooDevToolsExtension());
}

class FooDevToolsExtension extends StatelessWidget {
  const FooDevToolsExtension({super.key});

  @override
  Widget build(BuildContext context) {
    return const DevToolsExtension(
      child: Placeholder(), // Build your extension here
    );
  }
}

El widget DevToolsExtension inicializa automáticamente todas las extensiones requeridas para interactuar con DevTools. Desde cualquier lugar en tu app web de extensión, puedes acceder a las siguientes variables globales:

  • extensionManager: un gestor para interactuar con DevTools o el framework de extensiones.
  • serviceManager: un gestor para interactuar con el servicio VM conectado, si está presente.
  • dtdManager: un gestor para interactuar con el Dart Tooling Daemon, si está presente.

Depura tu extensión

#

Al desarrollar y mantener tu extensión de DevTools, querrás ejecutar, depurar y probar tu app web de Flutter de la extensión. Tienes un par de opciones diferentes para esto, descritas a continuación.

#

Para propósitos de depuración, es probable que desees usar el "entorno simulado de DevTools". Este es un entorno simulado que te permite construir tu extensión sin tener que desarrollarla como un iFrame incrustado en DevTools. Ejecutar tu extensión de esta manera envolverá tu extensión con un entorno que simula la conexión de DevTools a la extensión de DevTools. También te da acceso a Hot Restart y a un ciclo de desarrollo más rápido.

Depurando una extensión con el entorno simulado de DevTools

  1. Your DevTools extension.
  2. El URI del servicio VM para una app de prueba con la que interactuará tu extensión de DevTools. Esta app debe depender del paquete padre de tu extensión (package:foo en este ejemplo).
  3. Botones para realizar acciones que un usuario puede activar desde DevTools.
  4. Logs que muestran los mensajes que se enviarán entre tu extensión y DevTools.

El entorno simulado se habilita mediante el parámetro de entorno use_simulated_environment. Para ejecutar tu app web de extensión con este flag habilitado, añade una configuración a tu archivo launch.json en VS Code:

json
{
    ...
    "configurations": [
        ...
        {
            "name": "foo_devtools_extension + simulated environment",
            "cwd": "packages/foo_devtools_extension",
            "request": "launch",
            "type": "dart",
            "args": [
                "--dart-define=use_simulated_environment=true"
            ],
        },
    ]
}

o lanza tu app desde la línea de comandos con el flag añadido:

flutter run -d chrome -dart-define=use_simulated_environment=true

Opción B: Usar un entorno real de DevTools

#

Una vez que desarrolles tu extensión hasta un punto en el que estés listo para probar tus cambios en un entorno real de DevTools, necesitas realizar una serie de pasos de configuración:

  1. Develop your extension to a point where you are ready to test your changes in a real DevTools environment. Build your flutter web app and copy the built assets from `your_extension_web_app/build/web` to your pub package's `extension/devtools/build directory`.

    Usa el comando build_and_copy de package:devtools_extensions para ayudar con este paso.

    console cd tu_extension_web_app; flutter pub get; dart run devtools_extensions build_and_copy --source=. --dest=path/to/tu_pub_package/extension/devtools

    Para asegurarte de que tu extensión esté configurada correctamente para cargarse en DevTools, ejecuta el comando validate de package:devtools_extensions. El argumento --package debe apuntar a la raíz del paquete Dart con el que se publicará esta extensión.

    console cd tu_extension_web_app; flutter pub get; dart run devtools_extensions validate --package=path/to/tu_pub_package

  2. Prepare a test environment with a dependency on your pub package that is providing the extension.

    En el proyecto Dart o Flutter donde estás añadiendo una dependencia a tu paquete, añade una dependencia de path que apunte al código fuente de tu paquete local (el paquete que contiene el directorio extension/devtools/ con los assets de tu extensión). Una vez que hayas hecho esto, ejecuta pub get en el paquete.

    * Si tu extensión requiere una aplicación en ejecución, entonces necesitarás ejecutar la app que depende de tu extensión. * Si tu extensión no requiere una aplicación en ejecución, entonces necesitarás abrir el proyecto de prueba Dart o Flutter que depende de tu paquete en un IDE compatible (VS Code o IntelliJ / Android Studio).

  3. Start DevTools

    Usa una de las siguientes formas para iniciar DevTools:

    * Si tu extensión requiere una aplicación en ejecución, puedes abrir DevTools ya sea desde la URI que se imprimió en la línea de comandos cuando ejecutaste la app de prueba, o desde el IDE donde ejecutaste tu app de prueba. * Si tu extensión no requiere una aplicación en ejecución, puedes abrir tu proyecto Dart o Flutter que depende de tu paquete en un IDE compatible (VS Code o IntelliJ / Android Studio). Abre DevTools desde el IDE para ver tu extensión en el navegador. * Si necesitas cambios locales o no lanzados de DevTools, necesitarás construir y ejecutar DevTools desde el código fuente. Consulta el archivo CONTRIBUTING.md de DevTools para obtener una guía sobre cómo hacer esto. Necesitarás construir DevTools con el servidor y el front-end para probar extensiones (instrucciones).

  4. Conecta tu app de prueba a DevTools si no está conectada aún, y deberías ver una pestaña en la barra de la app de DevTools para tu extensión. El estado habilitado o deshabilitado de tu extensión es gestionado por DevTools, el cual se expone desde un menú de **Extensions** en DevTools, disponible desde los botones de acción en la esquina superior derecha de la pantalla.

Una vez que hayas abierto DevTools, debería aparecer una pestaña en la barra de la app de DevTools para tu extensión. El estado habilitado o deshabilitado de tu extensión es gestionado por DevTools, el cual se expone desde un menú "Extensions", disponible desde los botones de acción en la esquina superior derecha de la pantalla.

Botón de menú de extensiones de DevTools

Menú de extensiones de DevTools

Publica tu paquete con una extensión de DevTools

#

Para que un paquete proporcione una extensión de DevTools a sus usuarios, debe publicarse con el contenido esperado en el directorio tu_pub_package/extension/devtools/ (como se describe en las instrucciones de configuración anteriores).

  1. Ensure the `extension/devtools/config.yaml` file exists and is configured per the specifications above. You can run the `validate` command from `package:devtools_extensions` to verify.
    cd your_extension_web_app;
    flutter pub get;
    dart run devtools_extensions validate --package=path/to/pkg_providing_your_extension_assets
    
  2. Use the `build_and_copy` command provided by `package:devtools_extensions` to build your extension and copy the output to the `extension/devtools` directory:

    console cd tu_extension_web_app; flutter pub get; dart run devtools_extensions build_and_copy --source=. --dest=path/to/tu_pub_package/extension/devtools

Luego, publica tu paquete en pub.dev:

flutter pub publish

Al ejecutar pub publish, verás una advertencia si no tienes el archivo config.yaml y un directorio build no vacío según lo requerido.

Para obtener orientación adicional sobre la publicación de tu paquete, visita la guía de publicación de package:devtools_extensions.


¡Eso es todo! Ahora, cuando un usuario dependa de la última versión de tu paquete, obtendrá automáticamente acceso a las herramientas que proporcionas en tu extensión de DevTools.

Quizás encuentres útiles los siguientes enlaces: