Usando un depurador OEM

Si estas escribiendo exclusivamente apps en Flutter con código Dart y no usas bibliotecas especificas de la plataforma, o accediendo de otro modo a funcionalidades especificas de la plataforma, puedes depurar tu código usando el depurador de tu IDE Solo la primera sección de esta guía, Depurando código Dart, es relevante para ti.

Si estas escribiendo un plugin especifico de plataforma o usando bibliotecas especificas de plataforma escritas en Swift, ObjectiveC, Java, o Kotlin, puedes depurar esta parte de tu código usando Xcode (para iOS) o Android Gradle (para Android). Esta guia muestra como puedes conectar dos depuradores a tu app Dart, uno para Dart, y one para el código OEM.

Depurando código Dart

Usa tu IDE para depuración Dart estándar. Estas instrucciones describen Android Studio, pero puedes usar tu IDE preferido con los plugins para Flutter y Dart instalados y configurados.

Dart debugger

  • Abre tu proyecto en Android Studio. Si aún no tienes un proyecto, crea uno usando las instrucciones en Test drive.

  • Simultáneamente abre el panel Debug y ehecyta la app en la vista Console pulsando en el icono bug (Debug-run icon).

    La primera vez que lanzas tu app es la más lenta. Deberías ver aparecer el panel Debug en la parte inferior de la ventana que se ve algo parecido a lo siguiente:

    Debug pane

    Puedes configurar donde aparece el panel de debug, o incluso arrastralo a su propia ventana usando el engranaje a la derecha en la barra del panel Debug. Esto es cierto para cada inspector en Android Studio.

  • Añade un punto de interrupción en la línea counter++.

  • En la app, haz click en el botón + (FloatingActionButton, o FAB, para resumir) para incrementar el contador. La app se pausa.

  • Las siguientes capturas de pantalla muestran:

    • El punto de interrupción en el panel editor.
    • Estado de la app en el panel debug, cuando pausa en el punto de interrupción.
    • La variable this expandida para mostrar estos valores.

    Estado de la app cuando alcanza el puntu de interrupción fijado

Puedes saltar en, fuera o por encima de las declaraciones Dart, hacer hot reload o reanudar la app, y usar el depurador de la misma manera que usarías cualquier depurador. El botón 5: Debug alterna que se muestre el panel debug.

El inspector Flutter

Hay otras dos funcionalidades proporcionadas por el plugin Flutter que puedes encontrar util. El inspector Flutter es una herramienta para visualizar y explorar el árbol de widget de Flutter y ayudarte a:

  • Entender los layouts existentes
  • Diagnosticar problemas de layout

Alterna mostrar el inspector usando el botón vertical a la derecha de la ventana de Android Studio.

Flutter inspector

Flutter outline

Flutter Outline muestra el método build de forma visual. Nota que esto puede ser diferente que el árbol de widgets para el método build. Alterna mostrar el outline usando el botón vertical a la derecha de la ventan de Android Studio.

captura de pantalla mostrando el inspector Flutter

El resto de esta guía muestra como configurar tu entorno para depurar código OEM. Como esperarías, el proceso funciona diferente para iOS y Android.

Depurando con Android Gradle (Android)

Para depurar el código OEM de Android, necesitas una app que contenga código OEM de Android. En esta sección, aprenderás como conectar dos depuradores a tu app: 1) el depurador Dart y, 2) el depurador Gradle de Android.

  • Crea una app básica con Flutter.

  • Reemplaza lib/main.dart con el siguiente código del paquete url_launcher:

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'URL Launcher',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'URL Launcher'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Future<void> _launched;

  Future<void> _launchInBrowser(String url) async {
    if (await canLaunch(url)) {
      await launch(url, forceSafariVC: false, forceWebView: false);
    } else {
      throw 'Could not launch $url';
    }
  }

  Future<void> _launchInWebViewOrVC(String url) async {
    if (await canLaunch(url)) {
      await launch(url, forceSafariVC: true, forceWebView: true);
    } else {
      throw 'Could not launch $url';
    }
  }

  Widget _launchStatus(BuildContext context, AsyncSnapshot<void> snapshot) {
    if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    } else {
      return Text('');
    }
  }

  @override
  Widget build(BuildContext context) {
    String toLaunch = 'https://flutter.dev';
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: EdgeInsets.all(16.0),
              child: Text(toLaunch),
            ),
            RaisedButton(
              onPressed: () => setState(() {
                    _launched = _launchInBrowser(toLaunch);
                  }),
              child: Text('Launch in browser'),
            ),
            Padding(padding: EdgeInsets.all(16.0)),
            RaisedButton(
              onPressed: () => setState(() {
                    _launched = _launchInWebViewOrVC(toLaunch);
                  }),
              child: Text('Launch in app'),
            ),
            Padding(padding: EdgeInsets.all(16.0)),
            FutureBuilder<void>(future: _launched, builder: _launchStatus),
          ],
        ),
      ),
    );
  }
}
  • Añade la dependencia url_launcher al fichero pubspec, y ejecuta flutter pub get:
name: flutter_app
description: A new Flutter application.
version: 1.0.0+1

dependencies:
  flutter:
    sdk: flutter

  url_launcher: ^3.0.3
  cupertino_icons: ^0.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  • Haz clic en el icono de depurar (Debug-run icon) para simultaneamente abrir el panel Debug y lanzar la app. Espera que la app se inicie en el dispositivo, y a que el panel debug indique Connected. (Esto puede tomar un minuto la primera vez pero es más rápido en los siguientes lanzamientos.) La app contiene dos botones: 1) Launch in browser abre flutter.dev en el navegador predeterminado de tu teléfono y 2) Launch in app abre flutter.dev dentro de tu app.

    captura de pantalla conteniendo dos botones para abrir flutter.io

  • Haz clic en el botón Attach debugger to Android process ( se ve como un rectángulo con un pequeño escarabajo verde sobrepuesto )

  • En el diálogo process, deberías ver una entrada para cada dispositivo conectado. Selecciona show all processes para mostrar los proceso disponibles por cada dispositivo.

  • Elige el proceso que quieras vincular. En este caso, es el com.google.clickcount (o com.company.app_name) process for the Motorola Moto G.

    captura de pantalla conteniendo dos botones para abrir flutter.dev

  • En el panel debug, deberías ahora ver un tab para Android Debugger.

  • En el panel de proyecto, expande app_name > android > app > src > main > java > io.flutter plugins. Haz doble click en GeneratedProjectRegistrant para abrir el código Java en el panel de edición.

Ambos depuradores, el de Dart y el OEM, están interactuando con el mismo proceso. Usa uno de ellos, o ambos, para fijar puntos de interripción, examinar el stack, reanudar la ejecución… En otras palabras, DEPURAR!

caputra de pantalla de Android Studio en el panel de debug Dart. El panel de depuración de Dart con dos puntos de interrupción fijados en lib/main.dart.

captura de pantalla de Android Studio en el panel de debug Android. El panel de depuración Android con un punto de interrupción fijado en GeneratedPluginRegistrant.java. Alterna entre los depuradores pulsando el depurador apropiado en la banda del panel Debug.

Depurar con Xcode (iOS)

Para depurar código OEM en iOS, necesitas una app que contenga código OEM iOS. En esta sección, aprenderás como conectar dos depuradores a tu app: 1) el depurador de Dart y, 2) el depurador de Xcode.

Recursos

Los siguientes recursos tienen más información sobre depuración en Flutter, iOS, y Android:

Flutter

Android

Puedes encontrar los siguientes recursos de depuración en developer.android.com.

iOS

Puedes encontrar los siguientes recuros de depuración en developer.apple.com.