Flutter未知功能插件glance的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter未知功能插件glance的使用

插件介绍

glance 是一个用于检测Flutter中UI卡顿的APM库,适用于Android和iOS设备。它可以帮助开发者收集堆栈跟踪信息,以便定位导致性能问题的具体函数,从而有效地解决问题。

使用指南

开始UI卡顿检测

为了接收UI卡顿信息,需要实现自己的报告器(JankDetectedReporter)。一旦获得卡顿信息,可以将其保存到文件中,或上传到服务器,并使用 flutter symbolize 命令进行符号化处理。

// 实现自定义的 `JankDetectedReporter`
class MyJankDetectedReporter extends JankDetectedReporter {
  [@override](/user/override)
  void report(JankReport info) {
    final stackTrace = info.stackTrace.toString();
    // 保存堆栈跟踪到文件,或上传到服务器,并使用 `flutter symbolize` 命令进行符号化处理。
  }
}

void main() {
  // 确保 `GlanceWidgetBinding` 初始化
  GlanceWidgetBinding.ensureInitialized();
  // 启动UI卡顿检测
  Glance.instance.start(config: GlanceConfiguration(reporters: [MyJankDetectedReporter()]));

  runApp(const MyApp());
}
自动符号化

一些工具,如Firebase和Sentry,可以在你上传符号时自动符号化堆栈跟踪。这在没有自托管服务器的情况下非常有用。更多详情请参阅:

示例代码

import 'dart:convert';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:glance/glance.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:permission_handler/permission_handler.dart';

class MyJankDetectedReporter extends JankDetectedReporter {
  [@override](/user/override)
  void report(JankReport info) {
    compute((msg) async {
      final token = (msg as List)[0];
      final info = (msg)[1];
      BackgroundIsolateBinaryMessenger.ensureInitialized(token!);

      late Directory? docDir;
      if (defaultTargetPlatform == TargetPlatform.iOS) {
        docDir = await getApplicationDocumentsDirectory();
      } else {
        docDir = await getExternalStorageDirectory();
      }
      final stacktraceFilePath = path.join(
        docDir!.absolute.path,
        'jank_trace',
        'jank_trace_${DateTime.now().microsecondsSinceEpoch}.txt',
      );
      // 我们希望在非调试模式下打印日志
      // ignore: avoid_print
      print('[MyJankDetectedReporter] stacktraceFilePath: $stacktraceFilePath');
      final file = File(stacktraceFilePath);
      file.createSync(recursive: true);
      File(stacktraceFilePath).writeAsStringSync(
        info.stackTrace.toString(),
        flush: true,
      );
    }, [RootIsolateToken.instance, info]);
  }
}

void main() {
  GlanceWidgetBinding.ensureInitialized();
  FlutterError.onError = (details {
    FlutterError.presentError(details);
    // ignore: avoid_print
    print('FlutterError.onError:\n${details.toString()}');
  };
  PlatformDispatcher.instance.onError = (error, stack {
    // ignore: avoid_print
    print('PlatformDispatcher.instance.onError:\n$error\n$stack');
    return true;
  };

  _startGlance();
  runApp(const MyApp());
}

Future<void> _startGlance() async {
  Glance.instance.start(
    config: GlanceConfiguration(
      reporters: [MyJankDetectedReporter()],
    ),
  );

  await Permission.storage.request();
}

class MyApp extends StatelessWidget {
  // ignore: use_super_parameters
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      showPerformanceOverlay: true,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  // ignore: use_super_parameters
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _expensiveCall() {
    final watch = Stopwatch();
    watch.start();
    for (int i = 0; i < 1000; ++i) {
      jsonEncode({
        for (int i = 0; i < 10000; ++i) 'aaa': 0,
      });
    }
    watch.stop();
    // ignore: avoid_print
    print('[_expensiveCall] spent: ${watch.elapsedMilliseconds}');
  }

  void _incrementCounter() {
    _expensiveCall();
    setState(() {
      _counter++;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'You have pushed the button this many times:',
            ),
            Text('$_counter'),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

更多关于Flutter未知功能插件glance的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter未知功能插件glance的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,Glance是一个相对较新的插件,主要用于在支持Glance功能的设备上展示快速视图(glances)。这些设备通常是智能手表或其他可穿戴设备,允许用户在不打开应用的情况下快速查看信息。Glance插件使得Flutter开发者能够为这些设备创建自定义的快速视图。

由于Glance是一个特定于平台的插件,并且可能还处于早期开发阶段,它的使用可能会依赖于特定的设备和操作系统版本。以下是一个基本的代码示例,展示了如何在Flutter项目中使用Glance插件。请注意,实际使用时,你可能需要参考最新的官方文档和API,因为API可能会随时间发生变化。

首先,确保你的pubspec.yaml文件中已经添加了Glance插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  glance: ^x.y.z  # 替换为实际版本号

然后,运行flutter pub get来安装依赖。

接下来,创建一个Glance配置文件。这个文件通常定义了快速视图的内容和布局。以下是一个简单的示例:

import 'package:glance/glance.dart';

class MyGlanceData extends GlanceData {
  @override
  String get title => 'My Glance';

  @override
  List<GlanceWidget> buildWidgets(BuildContext context) {
    return [
      GlanceText(
        text: 'Hello, Glance!',
        style: GlanceTextStyle(
          fontSize: 24,
          fontWeight: FontWeight.bold,
        ),
      ),
      GlanceImage.asset(
        assetName: 'assets/my_image.png',
      ),
      // 可以添加更多小部件,如GlanceTime, GlanceDate等
    ];
  }
}

然后,在你的主应用或某个适当的地方注册这个Glance配置:

import 'package:flutter/material.dart';
import 'package:glance/glance.dart';
import 'my_glance_data.dart';  // 导入上面创建的类

void main() {
  // 注册Glance配置
  Glance.register(
    provider: GlanceDataProvider(
      buildData: (BuildContext context) => MyGlanceData(),
    ),
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Glance Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Glance Demo'),
        ),
        body: Center(
          child: Text('Check your wearable device for the glance view.'),
        ),
      ),
    );
  }
}

请注意,上面的代码示例是一个简化的版本,用于展示如何设置和使用Glance插件。在实际应用中,你可能需要处理更多细节,比如适配不同的屏幕尺寸、处理用户交互等。

此外,由于Glance插件可能还处于早期开发阶段,并且依赖于特定的设备和操作系统支持,因此在实际部署之前,请务必参考最新的官方文档和API指南。如果Glance插件有特定的配置要求或限制,官方文档通常会提供详细的说明。

回到顶部