Flutter音乐评分插件finotescore的使用

Flutter音乐评分插件finotescore的使用

Finotes Core (finotescore)

Flutter插件,能够检测并报告Android和iOS移动应用中的错误。


开始使用

  1. 使用“开始使用”按钮在https://finotes.com注册Finotes账户,并登录仪表盘。
  2. 在仪表盘中使用“添加应用”功能将Android和iOS应用程序与Finotes绑定。
  3. 将Finotes插件集成到您的应用程序中。
  4. 测试您的集成。

集成前的准备

插件支持的Dart SDK版本为大于或等于2.16.2且小于3.0.0。
Flutter版本应大于或等于2.5.0。


集成插件

pubspec.yaml文件中添加finotescore依赖项:

dependencies:
  finotescore: ^version

初始化Finotes

在主函数中调用Fn.init()方法。确保在调用初始化API之前执行WidgetsFlutterBinding.ensureInitialized()

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

    WidgetsFlutterBinding.ensureInitialized();
    Fn.init();
}

设置ProGuard规则

如果在发布构建中使用了ProGuard,请在proguard-rules.pro文件中添加以下内容:

-keep class com.finotes.android.finotescore.* { *; }

-keepclassmembers class * {
    @com.finotes.android.finotescore.annotation.Observe *;
}

-keepattributes SourceFile,LineNumberTable

请确保备份生产构建的映射文件(每次构建),以便从Finotes仪表盘解混淆堆栈跟踪。
映射文件位置:project-folder/app/build/outputs/proguard/release/mapping.txt


测试集成

完成基本集成后,让我们确保仪表盘和插件同步。

第一步

Fn.init()下添加Fn.test()

import 'package:finotescore/finotescore.dart';

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

    WidgetsFlutterBinding.ensureInitialized();
    Fn.init();

    Fn.test(); // 调用此行以触发测试问题。
}
第二步

当应用程序打开时,检查Finotes仪表盘。我们触发的测试问题应该已报告。

记住要移除Fn.test()调用,否则每次运行应用程序时都会报告一个问题。


自动崩溃报告

通过基本集成,Finotes会自动捕获并报告未处理的异常到Finotes仪表盘。


报告已捕获的异常

任何已在Zone中捕获的异常需要被报告,因为它们可能会阻止应用程序崩溃,但同时可能导致应用程序不稳定。

runZonedGuarded<void>(() async {
    // 应用程序逻辑
}, (dynamic error, StackTrace stackTrace) {
    Fn.reportError(error, stackTrace); // 单行API用于报告捕获的错误。
});

报告自定义问题

使用Fn.reportIssue() API报告自定义问题:

Fn.reportIssue("主应用", "支付失败", "选择基础套餐时支付失败");

检测内存泄漏

为了捕获应用程序中的内存泄漏,从插件提供的FnState类扩展自定义类的State类。插件现在可以报告来自Dart代码和本机平台(Java、Kotlin、Swift和Obj-C)的内存泄漏。

class _MyAppState extends FnState<MyApp> { // 替换State类为FnState类。
    ...
}

跟踪UI阻塞问题

此功能在插件中自动激活。
通过基本集成,Finotes会自动跟踪并报告可能导致Android应用程序无响应(ANR)或iOS/iPadOS应用程序挂起的UI/主线程阻塞问题。

热重启导致主线程阻塞

在开发过程中,“热重启”模式会导致主线程临时阻塞。由于主线程被阻塞,FinotesCore插件会向仪表盘报告问题。


报告HTTP(s)问题

FinotesCore插件支持使用httphttp_interceptor插件跟踪HTTP(s)调用。

基于HTTP客户端

http.Client替换为FinotesCore插件提供的FnClient

import 'package:finotescore/fn_client.dart';

var client = http.Client(); // 使用常规HTTP客户端进行调用。
var client = FnClient(); // 替换为FinotesCore客户端。
基于拦截器

FnInterceptor添加到拦截器列表中,以启用FinotesCore插件跟踪HTTP(s)调用。

import 'package:finotescore/fn_interceptor.dart';

http.Client client = InterceptedClient.build(interceptors: [
  CustomInterceptor, FnInterceptor(), // 添加FinotesCore拦截器以跟踪API调用。
]);
掩码头字段

调用setMaskedHeaders函数以指定需要掩码的头字段键列表。设置后,所有具有上述键值的头字段都将从设备端掩码。此功能可用于掩码敏感头字段。

Observe().setMaskedHeaders(["X-Key"]);

活动轨迹

活动标记是在应用程序运行时发生的事件。为了捕获应用程序中使用的状态生命周期事件,请从插件提供的FnState类扩展State类。

class _MyAppState extends FnState<MyApp> { // 替换State类为FnState类。
    ...

    [@override](/user/override)
    Widget build(BuildContext context) {
        super.build(context); // 确保在此处调用super。
        return ...;
    }
}
设置自定义活动轨迹

开发人员可以在应用程序的任何位置使用Fn.setActivityMarker()设置自定义活动轨迹标记。这些标记将在报告问题时与生命周期事件一起显示。

Fn.setActivityMarker("主应用", "用户点击了支付按钮");

启用Finotes日志

您可以使用logMe() API激活内部Finotes日志记录。激活logMe() API将打印插件生成的所有日志,包括错误和警告日志。

Fn.logMe();

在准备生产发布时,请务必移除日志API。


完整示例代码

以下是一个完整的示例代码,展示如何使用finotescore插件:

import 'dart:async';
import 'dart:convert';
import 'dart:developer';

import 'package:finotescore/finotescore.dart';
import 'package:finotescore/fn_client.dart';
import 'package:finotescore/fn_interceptor.dart';
import 'package:finotescore/observe.dart';
import 'package:flutter/material.dart';
import 'package:http_interceptor/http_interceptor.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(const MyRootApp());

  WidgetsFlutterBinding.ensureInitialized(); // 确保在执行Fn.init()之前调用ensureInitialized。
  Fn.logMe();
  Fn.init(); // 需要调用此函数以激活插件。
  Observe().setMaskedHeaders(["connection"]); // 掩码敏感头字段。
  Observe().setWhiteListedDomain(["jsonplaceholder.typicode.com"]); // 白名单域名。
  Observe().setBaseUrlTimeouts({
    "jsonplaceholder.typicode.com": 1000 // 超时值应大于或等于1000。
  });
}

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

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

class MyScreenApp extends StatefulWidget {
  const MyScreenApp({Key? key}) : super(key: key);

  [@override](/user/override)
  State<MyScreenApp> createState() => _MyScreenState();
}

class _MyScreenState extends FnState<MyScreenApp> {
  int _counter = 0;

  void fetchTodoWithHttpClient() async {
    var client = FnClient(); // 替换为FinotesCore客户端。
    try {
      var response = await client.get(Uri.https('jsonplaceholder.typicode.com', 'todos/1'));
      var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
      print(decodedResponse);
    } finally {
      client.close();
    }
  }

  void fetchTodoWithInterceptor() async {
    http.Client client = InterceptedClient.build(interceptors: [
      FnInterceptor(), // 添加FinotesCore拦截器以跟踪API调用。
    ]);
    try {
      final response = await client.get("https://jsonplaceholder.typicode.com/toos/1/".toUri());
      if (response.statusCode == 200) {
        log("API response ${json.decode(response.body)}");
      } else {
        throw Exception("Error while fetching. \n ${response.body}");
      }
    } catch (e) {
      print(e);
    }
  }

  void _incrementCounter(BuildContext context) {
    fetchTodoWithInterceptor();

    setState(() {
      _counter++;
    });

    Fn.setActivityMarkerAt("Main", "User tapped on increment counter"); // 设置活动标记以获取问题上下文。

    runZonedGuarded(() async {
      throw Exception(); // 触发异常。
    }, (error, stackTrace) {
      Fn.reportError(error, stackTrace); // 单行API用于报告捕获的错误。
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Plugin example app'),
      ),
      body: Center(
        child: Text('Run $_counter'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _incrementCounter(context);
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

更多关于Flutter音乐评分插件finotescore的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter音乐评分插件finotescore的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


FinoteScore 是一个用于 Flutter 的音乐评分插件,它可以帮助开发者在应用中实现音乐评分功能。以下是如何使用 FinoteScore 插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 finotescore 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  finotescore: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来获取依赖。

2. 导入插件

在你的 Dart 文件中导入 finoteScore 插件:

import 'package:finotescore/finotescore.dart';

3. 初始化 FinoteScore

在使用 FinoteScore 之前,你需要初始化它。通常,你可以在 initState 方法中进行初始化:

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  FinoteScore finoteScore;

  [@override](/user/override)
  void initState() {
    super.initState();
    finoteScore = FinoteScore();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('FinoteScore Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () {
                  _startScoring();
                },
                child: Text('Start Scoring'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _startScoring() async {
    // 启动音乐评分
    await finoteScore.startScoring();
  }
}

4. 启动音乐评分

你可以通过调用 finoteScore.startScoring() 方法来启动音乐评分。这个方法会开始监听用户的音乐播放并进行评分。

5. 获取评分结果

你可以通过监听 finoteScore.onScoreUpdated 来获取实时的评分结果:

void _startScoring() async {
  await finoteScore.startScoring();

  finoteScore.onScoreUpdated.listen((score) {
    print('Current Score: $score');
  });
}

6. 停止音乐评分

当你想要停止音乐评分时,可以调用 finoteScore.stopScoring() 方法:

void _stopScoring() async {
  await finoteScore.stopScoring();
}

7. 处理权限

FinoteScore 可能需要访问麦克风权限来进行音乐评分。确保你在 AndroidManifest.xmlInfo.plist 中添加了相应的权限声明。

  • Android: 在 AndroidManifest.xml 中添加:

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • iOS: 在 Info.plist 中添加:

    <key>NSMicrophoneUsageDescription</key>
    <string>We need access to the microphone to score your music.</string>
    

8. 处理权限请求

在运行时,你可能需要请求用户授予麦克风权限。你可以使用 permission_handler 插件来处理权限请求:

import 'package:permission_handler/permission_handler.dart';

void _requestPermissions() async {
  var status = await Permission.microphone.request();
  if (status.isGranted) {
    // 权限已授予,可以开始评分
    _startScoring();
  } else {
    // 权限被拒绝,提示用户
    print('Microphone permission denied');
  }
}

9. 完整示例

以下是一个完整的示例,展示了如何使用 FinoteScore 插件:

import 'package:flutter/material.dart';
import 'package:finotescore/finotescore.dart';
import 'package:permission_handler/permission_handler.dart';

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

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  FinoteScore finoteScore;

  [@override](/user/override)
  void initState() {
    super.initState();
    finoteScore = FinoteScore();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('FinoteScore Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () {
                  _requestPermissions();
                },
                child: Text('Start Scoring'),
              ),
              ElevatedButton(
                onPressed: () {
                  _stopScoring();
                },
                child: Text('Stop Scoring'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _requestPermissions() async {
    var status = await Permission.microphone.request();
    if (status.isGranted) {
      _startScoring();
    } else {
      print('Microphone permission denied');
    }
  }

  void _startScoring() async {
    await finoteScore.startScoring();

    finoteScore.onScoreUpdated.listen((score) {
      print('Current Score: $score');
    });
  }

  void _stopScoring() async {
    await finoteScore.stopScoring();
  }
}
回到顶部