Flutter轮胎胎纹识别插件anyline_tire_tread_plugin的使用

Flutter轮胎胎纹识别插件anyline_tire_tread_plugin的使用

本Flutter插件提供了对Anyline轮胎胎纹SDK的接口,允许你在Flutter应用中集成轮胎胎纹扫描功能。

要求

Android

  • Android 8.0(Oreo)或更高版本(API级别26+)
  • 良好的摄像头功能(推荐:≥ 720p且具备良好的自动对焦)
  • 具备闪光灯功能
  • 稳定的互联网连接

iOS

  • iOS版本 >= 16.4
  • 稳定的互联网连接
  • 具备闪光灯功能

Anyline轮胎胎纹Flutter插件指南

在本指南中,我们将向你展示如何充分利用Anyline轮胎胎纹插件。如果你觉得本指南不完整或某些部分需要进一步解释,请随时联系我们。

获取Anyline许可证

为了能够使用该Flutter插件,你需要按照我们的文档中的步骤获取一个许可证密钥。

安装Anyline轮胎胎纹插件

pubspec.yaml文件中添加以下依赖:

dependencies:
  anyline_tire_tread_plugin: ^x.y.z

将Anyline轮胎胎纹SDK作为依赖项添加

要将Anyline轮胎胎纹SDK集成到你的Android项目中,请按以下步骤操作:

  1. 在Android Studio中打开你的项目。
  2. 找到项目的build.gradle文件。该文件通常位于项目的根目录下。
  3. 向你的repositories块中添加Anyline Maven仓库,以使项目能够访问指定Maven仓库中的Anyline轮胎胎纹SDK。更新你的repositories块以包含Anyline Maven仓库URL:
repositories {
    // ... 你的其他仓库 ...
    mavenCentral()
    // Anyline Maven仓库
    maven { url "https://europe-maven.pkg.dev/anyline-ttr-sdk/maven" }
}

通过pub.dev安装

从命令行安装包依赖项:

flutter pub get

或者,你可以使用IDE支持的flutter pub get命令。查阅其文档了解更多信息。

导入Anyline到你的Flutter项目

现在,在你的Dart代码中导入Anyline:

import 'package:anyline_tire_tread_plugin/anyline_tire_tread_plugin.dart';

通过此导入,你可以使用TireTreadPlugin类来调用SDK方法并执行扫描功能。接下来,创建该类的一个实例:

var tireTreadPlugin = TireTreadPlugin();

初始化SDK

在应用程序启动时,在调用任何其他插件方法之前,通过调用插件对象的initialize方法并提供你的许可证密钥来初始化Anyline轮胎胎纹SDK:

try {
  await tireTreadPlugin.initialize(licenseKey);
} catch (error) {    
  print("初始化Anyline轮胎胎纹SDK时出错: $error");
}

开始扫描

通过TireTreadPlugin实例调用scan方法,并传入配置选项:

scanWithAnyline() async {  
  tireTreadPlugin.scan(options: ScanOptions());
}

音频反馈

轮胎胎纹插件可以提供音频反馈来指导用户完成扫描过程。

要在你的应用中使用这些音频反馈,需要在以下文件夹内提供音频文件:

  • 对于iOS:path_to_plugin_root_folder/example/ios/Resources
  • 对于Android:path_to_plugin_root_folder/example/android/app/src/main/assets

在iOS/Android上播放的音频反馈(及其对应的文件名)包括:

  • 聚焦点找到时
    • tiretread_focuspoint_found.wav
  • 扫描开始时
    • tiretread_sound_start.wav
  • 扫描停止时
    • tiretread_sound_stop.wav
  • 手机距离轮胎太近时
    • tiretread_sound_beep_too_close.wav
  • 手机距离轮胎太远时
    • tiretread_sound_beep_too_far.wav

SDK仅支持这些文件名和.wav扩展名。

配置扫描行为

你可以通过传递一个ScanOptions对象来自定义扫描行为:

tireTreadPlugin.scan(options: ScanOptions());

一个未设置参数的ScanOptions对象包含一些默认值,可以帮助你快速开始使用。

如果你想自定义扫描速度(快或慢)和测量系统(公制或英制单位),可以这样做:

var scanOptions = ScanOptions(measurementSystem: MeasurementSystem.Imperial, scanSpeed: ScanSpeed.Fast);
tireTreadPlugin.scan(options: scanOptions);

或者,你可以提供一个包含SDK轮胎胎纹扫描视图配置JSON的字符串给ScanOptions对象,例如:

const configJSON = '{
  "scanSpeed": "Fast",
  "measurementSystem": "Metric",
  ...
}';

tireTreadPlugin.scan(options: ScanOptions(configFileContent: configJSON));

更多关于JSON配置的信息可以在这里找到:https://documentation.anyline.com/tiretreadsdk-component/latest/scanconfiguration.html

处理SDK的事件

通过TireTreadPlugin实例调用onScanningEvent来处理SDK的事件:

tireTreadPlugin.onScanningEvent.listen((event) { 
  switch (event) {
    case ScanAborted(): 
      debugPrint('测量UUID : ${event.measurementUUID}');
    case UploadAborted(): 
      debugPrint('测量UUID : ${event.measurementUUID}'); 
    case UploadCompleted(): 
      debugPrint('测量UUID : ${event.measurementUUID}'); 
      setState(() => _uuid = event.measurementUUID ?? ''); 
    case UploadFailed(): 
      debugPrint('测量UUID : ${event.error}');
  }
});

结果

获取测量结果

在上传扫描帧完成后(即UploadCompletedEvent),你的测量结果可能需要几秒钟才能可用。要获取结果,调用getResult函数:

String result = await tireTreadPlugin.getResult(measurementUUID: measurementUUID);

分析

热力图

在上传扫描帧完成后(即UploadCompletedEvent),你的热力图结果可能需要几秒钟才能可用。要获取热力图,调用getHeatMap函数:

String heatmap = await tireTreadPlugin.getHeatMap(measurementUUID: measurementUUID);

示例代码

以下是示例代码,展示了如何在Flutter应用中使用Anyline轮胎胎纹插件:

import 'dart:convert';

import 'package:anyline_tire_tread_plugin/anyline_tire_tread_plugin.dart';
import 'package:anyline_tire_tread_plugin_example/app_colors.dart';
import 'package:anyline_tire_tread_plugin_example/device_details_widget.dart';
import 'package:anyline_tire_tread_plugin_example/env_info.dart';
import 'package:anyline_tire_tread_plugin_example/initalize_dialog.dart';
import 'package:anyline_tire_tread_plugin_example/widgets.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

enum InitializationStatus { start, pending, done, fail }

void main() {
  EnvInfo.initialize();
  runApp(const AnylineTireTreadPluginExample());
}

class AnylineTireTreadPluginExample extends StatefulWidget {
  const AnylineTireTreadPluginExample({super.key});

  [@override](/user/override)
  State<AnylineTireTreadPluginExample> createState() => _AnylineTireTreadPluginExampleState();
}

class _AnylineTireTreadPluginExampleState extends State<AnylineTireTreadPluginExample> {
  bool showLoader = false;

  static GlobalKey<ScaffoldMessengerState> snackBarKey = GlobalKey<ScaffoldMessengerState>();

  String _uuid = '';
  String _result = '';
  String _heatmap = '';

  ValueNotifier<InitializationStatus> initializationStatus = ValueNotifier(InitializationStatus.pending);

  final TireTreadPlugin _tireTreadPlugin = TireTreadPlugin();
  final GlobalKey heatMapViewKey = GlobalKey();
  final GlobalKey resultViewKey = GlobalKey();
  final ScrollController scrollController = ScrollController();

  [@override](/user/override)
  void initState() {
    _tireTreadPlugin.onScanningEvent.listen((event) {
      switch (event) {
        case ScanAborted():
          debugPrint('UUID : ${event.measurementUUID}');
        case UploadAborted():
          debugPrint('UUID : ${event.measurementUUID}');
        case UploadCompleted():
          debugPrint('UUID : ${event.measurementUUID}');
          setState(() => _uuid = event.measurementUUID ?? '');
        case UploadFailed():
          debugPrint('UUID : ${event.error}');
      }
    });
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      scaffoldMessengerKey: snackBarKey,
      home: Scaffold(
        backgroundColor: const Color(0xFF000000),
        appBar: AppBar(
          backgroundColor: const Color(0xFF000000),
          title: const Text(
            'Anyline轮胎胎纹插件示例',
            style: TextStyle(color: AppColors.primary),
          ),
        ),
        body: SafeArea(
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 10),
            child: Center(
              child: Column(
                children: [
                  ValueListenableBuilder(
                      valueListenable: initializationStatus,
                      builder: (context, status, _) {
                        return Expanded(
                          child: SingleChildScrollView(
                            controller: scrollController,
                            child: Column(
                              children: [
                                AppButton(
                                    onPressed: (status != InitializationStatus.start)
                                        ? () async {
                                            EnvInfo.runTimeLicenseKey = EnvInfo.licenseKey ?? '';
                                            showDialog<void>(
                                              barrierDismissible: false,
                                              context: context,
                                              builder: (BuildContext context) {
                                                return Dialog(
                                                  backgroundColor: Colors.white,
                                                  child: InitializeDialog(
                                                      onCancel: () {
                                                    Navigator.pop(context);
                                                  }, onDone: (licenseKey) async {
                                                    EnvInfo.runTimeLicenseKey = licenseKey;
                                                    Navigator.of(context).pop();
                                                    setState(() {
                                                      _uuid = '';
                                                      _result = '';
                                                    });
                                                    await startInitialization();
                                                  }),
                                                );
                                              },
                                            );
                                          }
                                        : null,
                                    title: '初始化'),
                                sizedBox,
                                AppButton(
                                    onPressed: (status == InitializationStatus.done)
                                        ? () {
                                            try {
                                              setState(() {
                                                _uuid = '';
                                                _result = '';
                                                _heatmap = '';
                                              });
                                              _tireTreadPlugin.scan(options: ScanOptions());
                                            } on PlatformException catch (error) {
                                              if (kDebugMode) {
                                                print(error);
                                              }
                                            }
                                          }
                                        : null,
                                    title: '扫描'),
                                sizedBox,
                                AppButton(
                                    onPressed: (status == InitializationStatus.done && _uuid.isNotEmpty)
                                        ? () async {
                                            try {
                                              setState(() {
                                                showLoader = true;
                                              });
                                              Scrollable.ensureVisible(resultViewKey.currentContext!, duration: const Duration(milliseconds: 300));

                                              _result = (await _tireTreadPlugin.getResult(measurementUUID: _uuid))!;
                                            } on PlatformException catch (error) {
                                              if (context.mounted) {
                                                ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error.details as String)));
                                              }
                                            } finally {
                                              setState(() {
                                                showLoader = false;
                                              });
                                            }
                                          }
                                        : null,
                                    title: '获取结果'),
                                sizedBox,
                                AppButton(
                                    onPressed: (status == InitializationStatus.done && _uuid.isNotEmpty)
                                        ? () async {
                                            try {
                                              setState(() {
                                                showLoader = true;
                                              });
                                              Scrollable.ensureVisible(heatMapViewKey.currentContext!, duration: const Duration(milliseconds: 300));

                                              _heatmap = (await _tireTreadPlugin.getHeatMap(measurementUUID: _uuid))!;
                                            } on PlatformException catch (error) {
                                              if (context.mounted) {
                                                ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error.details as String)));
                                              }
                                            } finally {
                                              setState(() {
                                                showLoader = false;
                                              });
                                            }
                                          }
                                        : null,
                                    title: '获取热力图'),
                                sizedBox,
                                initializationStatusView(status),
                                sizedBox,
                                if (_uuid.isNotEmpty)
                                  Text(
                                    'UUID: $_uuid',
                                    style: const TextStyle(fontSize: 16, color: AppColors.primary),
                                  ),
                                sizedBox,
                                if (showLoader)
                                  const SizedBox(
                                      height: 40,
                                      width: 40,
                                      child: CircularProgressIndicator(color: AppColors.primary)),
                                sizedBox,
                                Image.network(
                                  _heatmap,
                                  key: heatMapViewKey,
                                  errorBuilder: (
                                    context,
                                    _,
                                    __,
                                  ) {
                                    return const SizedBox();
                                  },
                                ),
                                sizedBox,
                                Text(
                                  (_result.isNotEmpty)
                                      ? '结果: ${const JsonEncoder.withIndent('  ').convert(jsonDecode(_result))}'
                                      : '',
                                  key: resultViewKey,
                                  style: const TextStyle(fontSize: 16, color: AppColors.primary),
                                ),
                              ],
                            ),
                          ),
                        );
                      }),
                  pluginDetailsWidget(),
                  const DeviceDetailsWidget()
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Future<void> startInitialization() async {
    try {
      setState(() {
        _uuid = '';
        showLoader = true;
      });
      initializationStatus.value = InitializationStatus.start;
      await _tireTreadPlugin.initialize(EnvInfo.licenseKey ?? '');
      initializationStatus.value = InitializationStatus.done;
    } on PlatformException catch (error) {
      initializationStatus.value = InitializationStatus.fail;

      snackBarKey.currentState?.showSnackBar(SnackBar(content: Text(error.details as String)));
    } finally {
      setState(() {
        showLoader = false;
      });
    }
  }

  Column pluginDetailsWidget() {
    return Column(
      children: [
        FutureBuilder(
            future: _tireTreadPlugin.sdkVersion,
            builder: (context, snap) {
              if (snap.hasData) {
                return Text('SDK版本: ${snap.data}', style: const TextStyle(fontSize: 14, color: AppColors.primary));
              }
              return const SizedBox.shrink();
            }),
        FutureBuilder(
            future: _tireTreadPlugin.pluginVersion,
            builder: (context, snap) {
              if (snap.hasData) {
                return Text('插件版本: ${snap.data}', style: const TextStyle(fontSize: 14, color: AppColors.primary));
              }
              return const SizedBox.shrink();
            }),
      ],
    );
  }

  Widget initializationStatusView(InitializationStatus status) {
    String message = '';
    if (status == InitializationStatus.pending) {
      message = '待定';
    } else if (status == InitializationStatus.start) {
      message = '开始';
    } else if (status == InitializationStatus.fail) {
      message = '失败';
    } else {
      message = '成功';
    }
    return Text(
      '初始化结果: $message',
      style: const TextStyle(fontSize: 16, color: AppColors.primary),
    );
  }
}

更多关于Flutter轮胎胎纹识别插件anyline_tire_tread_plugin的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter轮胎胎纹识别插件anyline_tire_tread_plugin的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用anyline_tire_tread_plugin插件的一个基本示例。请注意,这个插件是假设存在的,用于轮胎胎纹识别的自定义插件。在实际使用中,你可能需要替换为真实的插件名称或者进行必要的调整。

首先,确保你的Flutter项目已经创建。如果还没有创建,可以使用以下命令创建一个新的Flutter项目:

flutter create tire_tread_recognition_app
cd tire_tread_recognition_app

接下来,假设anyline_tire_tread_plugin已经在pub.dev上发布(实际上你需要使用真实的插件名称或者从私有源安装),在pubspec.yaml文件中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  anyline_tire_tread_plugin: ^1.0.0  # 假设的版本号,实际使用时请替换为最新版本

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

安装完成后,你可以开始在你的Flutter应用中使用这个插件。以下是一个简单的示例代码,展示了如何使用anyline_tire_tread_plugin进行轮胎胎纹识别:

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

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

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String result = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Tire Tread Recognition'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Scan a tire tread image to recognize its pattern',
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                // 打开图像选择器或相机以获取图像
                var imageFile = await ImagePicker().pickImage(source: ImageSource.camera);
                if (imageFile != null) {
                  // 使用插件进行轮胎胎纹识别
                  var recognitionResult = await AnylineTireTreadPlugin.recognizeTireTread(imageFile.path);
                  setState(() {
                    result = recognitionResult?.toJson()?.toString() ?? 'Recognition failed';
                  });
                }
              },
              child: Text('Scan Tire Tread'),
            ),
            SizedBox(height: 20),
            Text(
              result,
              style: TextStyle(fontSize: 18),
              textAlign: TextAlign.center,
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们使用了ImagePicker插件来选择图像(可以从相机或图库中选择)。然后,我们使用假设的AnylineTireTreadPlugin.recognizeTireTread方法来处理图像并获取识别结果。请注意,AnylineTireTreadPlugin和它的recognizeTireTread方法是假设存在的,你需要根据实际的插件API进行调整。

此外,由于ImagePicker插件不是Flutter SDK的一部分,你还需要在pubspec.yaml文件中添加它的依赖:

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^0.8.4+4  # 假设的版本号,实际使用时请替换为最新版本
  anyline_tire_tread_plugin: ^1.0.0  # 假设的版本号,实际使用时请替换为最新版本

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

请注意,上述代码是一个简化的示例,用于说明如何使用一个假设的轮胎胎纹识别插件。在实际应用中,你可能需要处理更多的错误情况、优化用户体验,并根据实际的插件API文档进行调整。

回到顶部