Flutter集成 CMB SDK 插件 cmbsdk_flutter 的使用
Flutter集成 CMB SDK 插件 cmbsdk_flutter 的使用
文档与集成信息
本页提供了有关如何在 Flutter 应用程序中集成 CMB SDK 插件 cmbsdk_flutter
的详细信息。
API 方法
所有 API 方法的使用和示例可以在 此处 找到。
更新日志
详细的更新日志可以在我们的 开发者网络站点 上找到。
示例代码
以下是完整的 Flutter 应用程序示例代码,演示如何使用 cmbsdk_flutter
插件进行扫描。
import 'dart:io';
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:cmbsdk_flutter/cmbsdk_flutter.dart';
import 'package:cmbsdk_flutter/cmbsdk_flutter_constants.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(
new MaterialApp(
home: new MyApp(),
),
);
}
class MyApp extends StatefulWidget {
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
// 支持多码扫描(一次扫描多个条形码);因此扫描结果返回为数组。
// 注意:此示例应用程序未演示多码功能。
List<dynamic> _resultsArray = [];
bool _isScanning = false;
String _cmbSDKVersion = 'N/A';
String _connectionStatusText = 'Disconnected';
Color _connectionStatusBackground = Colors.redAccent;
String _scanButtonText = '(NOT CONNECTED)';
bool _scanButtonEnabled = false;
late SharedPreferences prefs;
final String pairedPeripheralUUIDKey = 'pairedPeripheralUUID';
BuildContext? deviceDialogContext;
// 如果 USE_PRECONFIGURED_DEVICE 为 YES,则应用程序将使用 device/cameraMode 的值创建读取器。
// 否则,应用程序会提供一个选择列表供用户选择 MX-1xxx 或内置摄像头。
final bool _usePreconfiguredDevice = false;
int _deviceType = cmbDeviceType.MXReader;
int _cameraMode = cmbCameraMode.NoAimer;
[@override](/user/override)
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
initCmbSDK();
}
[@override](/user/override)
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
[@override](/user/override)
void didChangeAppLifecycleState(AppLifecycleState appLifecycleState) {
switch (appLifecycleState) {
case AppLifecycleState.resumed:
// 关闭设备选择对话框
if (deviceDialogContext != null) {
Navigator.pop(deviceDialogContext!);
}
cmb
.connect()
.catchError((error, stackTrace) => print('${error.message}'));
break;
case AppLifecycleState.paused:
cmb
.disconnect()
.catchError((error, stackTrace) => print('${error.message}'));
break;
}
}
Future<void> savePairedPeripheral() async {
final String? pairedperipheralUUID = await cmb
.getPairedBluetoothDevice()
.catchError((error, stackTrace) => print(error.message));
if (pairedperipheralUUID != null)
prefs.setString(pairedPeripheralUUIDKey, pairedperipheralUUID);
}
Future<void> initCmbSDK() async {
String cmbSDKVersion = 'N/A';
prefs = await SharedPreferences.getInstance();
// 当 MX-1xxx 设备可用时(USB电缆已插入或MX设备已打开),
// 或当 MX-1xxx 已经可用但不再可用(USB电缆被拔出、由于不活动或电池耗尽而关闭)时调用。
cmb.setAvailabilityChangedListener((availability) {
if (availability == cmbAvailability.Available.index) {
cmb
.connect()
.catchError((error, stackTrace) => print('${error.message}'));
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text('设备不可用'),
actions: [
TextButton(
child: Text('确定'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
});
// 当与读取器的连接状态改变时调用。
// 只有在“连接”状态下读取器才可用。
cmb.setConnectionStateChangedListener((state) {
if (state == cmbConnectionState.Connected.index) {
if (Platform.isIOS && _deviceType == cmbDeviceType.Bluetooth) {
savePairedPeripheral();
}
_configureReaderDevice();
_updateUIByConnectionState(cmbConnectionState.Connected);
} else {
_updateUIByConnectionState(cmbConnectionState.Disconnected);
}
if (!mounted) return;
setState(() {
_isScanning = false;
_resultsArray = [];
});
});
// 在扫描完成后调用(检测到条形码、通过屏幕按钮或硬件触发按钮取消扫描、扫描超时等)。
cmb.setReadResultReceivedListener((resultJSON) {
final Map<String, dynamic> resultMap = jsonDecode(resultJSON);
final List<dynamic> resultsArray = resultMap['results'];
if (!mounted) return;
setState(() {
_resultsArray = resultsArray;
});
});
// 返回 TRUE 表示扫描过程已开始,返回 FALSE 表示已停止。
cmb.setScanningStateChangedListener((scanningState) {
if (!mounted) return;
setState(() {
_isScanning = scanningState;
_scanButtonText = _isScanning ? '停止扫描' : '开始扫描';
});
});
// 获取 cmbSDK 版本号
cmbSDKVersion = await cmb.sdkVersion;
// 初始化并连接到 MX/手机摄像头
if (_usePreconfiguredDevice) {
_createReaderDevice();
} else {
_selectDeviceFromPicker();
}
if (!mounted) return;
setState(() {
_cmbSDKVersion = cmbSDKVersion;
});
}
// 根据当前连接状态更新应用程序的 UI(扫描按钮、连接状态标签)。
void _updateUIByConnectionState(cmbConnectionState state) {
String connectionStatusText = _connectionStatusText;
Color connectionStatusBackground = _connectionStatusBackground;
String scanButtonText = _scanButtonText;
bool scanButtonEnabled = _scanButtonEnabled;
if (state == cmbConnectionState.Connected) {
connectionStatusText = '已连接';
connectionStatusBackground = Colors.lightGreen;
scanButtonText = '开始扫描';
scanButtonEnabled = true;
} else {
connectionStatusText = '断开连接';
connectionStatusBackground = Colors.redAccent;
scanButtonText = '(未连接)';
scanButtonEnabled = false;
}
if (!mounted) return;
setState(() {
_connectionStatusText = connectionStatusText;
_connectionStatusBackground = connectionStatusBackground;
_scanButtonText = scanButtonText;
_scanButtonEnabled = scanButtonEnabled;
});
}
// 这是一个选择读取器连接类型的选项列表。
Future<void> _selectDeviceFromPicker() async {
int deviceType = _deviceType;
int cameraMode = _cameraMode;
List<Widget> deviceOptions = [
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, cmbDeviceType.Bluetooth);
},
child: const Text('配对蓝牙扫描仪'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, cmbDeviceType.MXReader);
},
child: const Text('MX 扫描仪 (MX-1xxx)'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, cmbDeviceType.Camera);
},
child: const Text('手机摄像头'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, null);
},
child: const Text('取消'),
),
];
if (Platform.isIOS) {
deviceOptions.insert(
0,
SimpleDialogOption(
onPressed: () {
prefs.remove(pairedPeripheralUUIDKey);
Navigator.pop(context, cmbDeviceType.Bluetooth);
},
child: const Text('新蓝牙扫描仪'),
));
}
bool dismissed = false;
switch (await showDialog<int>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
deviceDialogContext = context;
return SimpleDialog(
title: const Text('选择设备'),
children: deviceOptions,
);
})) {
case cmbDeviceType.Bluetooth:
deviceType = cmbDeviceType.Bluetooth;
break;
case cmbDeviceType.MXReader:
deviceType = cmbDeviceType.MXReader;
break;
case cmbDeviceType.Camera:
deviceType = cmbDeviceType.Camera;
cameraMode = cmbCameraMode.NoAimer;
// ...
break;
default:
// 对话框被取消
dismissed = true;
break;
}
deviceDialogContext = null;
if (!mounted) return;
setState(() {
_deviceType = deviceType;
_cameraMode = cameraMode;
});
if (dismissed == false) {
_createReaderDevice();
}
}
// 使用从 "selectDeviceFromPicker" 选择的选项创建读取器。
void _createReaderDevice() {
if (_deviceType == cmbDeviceType.Camera) {
cmb.setCameraMode(_cameraMode);
cmb.setPreviewOptions(cmbPrevewiOption.Defaults);
cmb.registerSDK("SDK_KEY");
} else if (_deviceType == cmbDeviceType.Bluetooth) {
if (Platform.isIOS) {
final String? pairedPeripheralUUID =
prefs.getString(pairedPeripheralUUIDKey);
if (pairedPeripheralUUID != null) {
cmb.setPairedBluetoothDevice(pairedPeripheralUUID);
} else {
cmb.setPairedBluetoothDevice(""); // 清除它
}
} else
cmb.setPairedBluetoothDevice("BT_Device_MAC_Address");
}
cmb.loadScanner(_deviceType).then((value) {
cmb.connect().then((value) {
_updateUIByConnectionState(cmbConnectionState.Connected);
}).catchError((error, stackTrace) {
_updateUIByConnectionState(cmbConnectionState.Disconnected);
});
}).catchError((error, stackTrace) => print('${error.message}'));
}
// 这是一个配置设备的示例。在此示例应用中,我们每次连接状态更改为连接时都配置设备(见 ConnectionStateChanged 事件),
// 这样可以保证其按我们想要的方式设置。这不仅确保了我们在首次连接时配置了设备,还覆盖了 MX 扫描仪休眠(重新连接)的情况——除非明确保存更改到非易失性内存,
// 否则它们可能会因 MX 休眠或重启而丢失。
//
// 这些只是示例设置;在您的应用程序中,您可能希望考虑哪些设置更改最适合您的应用。需要注意的是,
// 不同支持的设备有不同的默认设置:
//
// * MX-1xxx 移动终端默认启用以下符号体系:
// - Data Matrix
// - UPC/EAN
// - Code 39
// - Code 93
// - Code 128
// - Interleaved 2 of 5
// - Codabar
// * 相机扫描仪默认未启用任何符号体系
//
// 为了获得最佳扫描性能,建议仅启用应用程序实际需要扫描的条形码符号体系。如果使用 MX-1xxx,则可能意味着禁用某些默认值(或启用默认情况下关闭的符号体系)。
//
// 请注意,此示例应用程序适用于所有三种类型的设备,因此在我们的示例中,我们显示显式启用符号体系以及显式禁用符号体系(即使这些符号体系可能已经开启或关闭)。
//
// 我们还展示了如何发送可能特定于设备类型的配置命令——主要是为了演示目的。
void _configureReaderDevice() {
//----------------------------------------------
// 显式启用我们需要的符号体系
//----------------------------------------------
cmb
.setSymbologyEnabled(cmbSymbology.DataMatrix, true)
.then((value) => print('DataMatrix 启用'))
.catchError((error, stackTrace) =>
print('DataMatrix 未启用。${error.message}'));
cmb
.setSymbologyEnabled(cmbSymbology.C128, true)
.catchError((error, stackTrace) => print('${error.message}'));
cmb
.setSymbologyEnabled(cmbSymbology.UpcEan, true)
.catchError((error, stackTrace) => print('${error.message}'));
//-------------------------------------------------------
// 显式禁用我们已知不需要的符号体系
//-------------------------------------------------------
cmb
.setSymbologyEnabled(cmbSymbology.CodaBar, false)
.then((value) => print('CodaBar 禁用'))
.catchError((error, stackTrace) =>
print('CodaBar 未禁用。${error.message}'));
cmb
.setSymbologyEnabled(cmbSymbology.C93, false)
.catchError((error, stackTrace) => print('${error.message}'));
//---------------------------------------------------------------------------
// 下面是一些示例,展示如何发送 DMCC 命令并获取响应
//---------------------------------------------------------------------------
cmb
.sendCommand('GET DEVICE.TYPE')
.then((value) => print('$value'))
.catchError((error, stackTrace) => print('${error.message}'));
cmb
.sendCommand('GET DEVICE.FIRMWARE-VER')
.then((value) => print('$value'))
.catchError((error, stackTrace) => print('${error.message}'));
//---------------------------------------------------------------------------
// 我们将显式关闭图像结果(尽管这是默认设置)。原因是,对于 MX-1xxx 扫描仪,
// 如果应用程序不需要扫描图像,则启用图像结果可能会影响扫描性能。
//---------------------------------------------------------------------------
cmb
.enableImage(false)
.catchError((error, stackTrace) => print('${error.message}'));
cmb
.enableImageGraphics(false)
.catchError((error, stackTrace) => print('${error.message}'));
//---------------------------------------------------------------------------
// 设备特定配置示例
//---------------------------------------------------------------------------
if (_deviceType == cmbDeviceType.Camera) {
//---------------------------------------------------------------------------
// 手机/平板电脑
//---------------------------------------------------------------------------
// 将 SDK 的解码努力设置为 3 级
cmb
.sendCommand("SET DECODER.EFFORT 3")
.catchError((error, stackTrace) => print('${error.message}'));
} else if (_deviceType == cmbDeviceType.MXReader) {
//---------------------------------------------------------------------------
// MX-1xxx
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 将我们的配置保存到非易失性内存
// 如果 MX 休眠或重启,我们的设置将保留。
//---------------------------------------------------------------------------
cmb
.sendCommand("CONFIG.SAVE")
.catchError((error, stackTrace) => print('${error.message}'));
} else if (_deviceType == cmbDeviceType.Bluetooth) {
//---------------------------------------------------------------------------
// DM-8700
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 将我们的配置保存到非易失性内存
// 如果读取器休眠或重启,我们的设置将保留。
//---------------------------------------------------------------------------
cmb
.sendCommand("CONFIG.SAVE")
.catchError((error, stackTrace) => print('${error.message}'));
}
}
void _toggleScanner() {
if (_isScanning) {
cmb
.stopScanning()
.catchError((error, stackTrace) => print('${error.message}'));
} else {
cmb
.startScanning()
.catchError((error, stackTrace) => print('${error.message}'));
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xff333333),
appBar: AppBar(
title: const Text('CMBCameraDemo'),
actions: [
Padding(
padding: const EdgeInsets.all(20.0),
child: GestureDetector(
onTap: () {
_selectDeviceFromPicker();
},
child: const Text('设备'),
)),
],
),
body: Center(
child: Column(
children: [
Expanded(
child: ListView.separated(
padding: const EdgeInsets.all(10),
itemCount: _resultsArray.length,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${_resultsArray[index]['readString']}',
style: TextStyle(
color: Colors.white, fontSize: 18)),
Text('${_resultsArray[index]['symbologyString']}',
style: TextStyle(color: Colors.grey)),
]);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(thickness: 1))),
Padding(
padding: const EdgeInsets.all(10),
child: Container(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: _scanButtonEnabled
? () {
_toggleScanner();
}
: null,
child: Text(_scanButtonText),
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xfffadb04),
foregroundColor: Colors.black,
disabledBackgroundColor: Color(0xfffadb04)),
))),
Padding(
padding: const EdgeInsets.all(5),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(_cmbSDKVersion,
style: TextStyle(
color: Colors.white,
)),
Container(
color: _connectionStatusBackground,
child: Padding(
padding: EdgeInsets.all(2),
child: Text(_connectionStatusText,
style: TextStyle(
color: Colors.white,
))),
)
],
))
],
),
),
);
}
}
更多关于Flutter集成 CMB SDK 插件 cmbsdk_flutter 的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter集成 CMB SDK 插件 cmbsdk_flutter 的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter项目中集成并使用cmbsdk_flutter
插件(假设这是一个用于集成中国民生银行(CMB)SDK的Flutter插件),你可以按照以下步骤进行操作。以下是一个基本的代码案例,展示如何在Flutter应用中集成并使用该插件。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加cmbsdk_flutter
插件的依赖。
dependencies:
flutter:
sdk: flutter
cmbsdk_flutter: ^x.y.z # 请替换为实际的版本号
然后,运行flutter pub get
来获取依赖。
2. 导入插件
在你的Dart文件中导入该插件。
import 'package:cmbsdk_flutter/cmbsdk_flutter.dart';
3. 初始化SDK
根据CMB SDK的要求,你可能需要在应用启动时初始化SDK。以下是一个简单的示例,展示如何在Flutter应用的main.dart
文件中进行初始化。
import 'package:flutter/material.dart';
import 'package:cmbsdk_flutter/cmbsdk_flutter.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// 初始化CMB SDK
_initializeCMBSDK();
}
Future<void> _initializeCMBSDK() async {
try {
// 假设初始化方法需要一些参数,这里用示例参数
bool result = await CMBSDK.initialize(
appId: "your_app_id",
appKey: "your_app_key",
// 其他必要的初始化参数
);
if (result) {
print("CMB SDK initialized successfully.");
} else {
print("Failed to initialize CMB SDK.");
}
} catch (e) {
print("Error initializing CMB SDK: $e");
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('CMB SDK Flutter Example'),
),
body: Center(
child: Text('Check console for CMB SDK initialization status.'),
),
),
);
}
}
4. 使用SDK功能
一旦SDK初始化成功,你就可以调用SDK提供的其他功能了。例如,假设有一个登录方法,你可以这样调用:
Future<void> _login() async {
try {
// 假设登录方法需要用户名和密码
Map<String, String> credentials = {
"username": "user@example.com",
"password": "password123",
};
CMBUser user = await CMBSDK.login(credentials: credentials);
if (user != null) {
print("Login successful: ${user.toJson()}");
} else {
print("Login failed.");
}
} catch (e) {
print("Error during login: $e");
}
}
你可以在按钮点击事件中调用这个方法:
body: Center(
child: ElevatedButton(
onPressed: _login,
child: Text('Login'),
),
),
注意事项
- 错误处理:在实际应用中,你应该添加更详细的错误处理逻辑。
- 安全性:不要在代码中硬编码敏感信息,如
appId
和appKey
,应该使用更安全的方式存储和读取这些信息,如使用Flutter的keychain
或keystore
插件。 - 文档:查阅
cmbsdk_flutter
插件的官方文档,了解所有可用的方法和参数。
以上代码提供了一个基本的框架,展示如何在Flutter项目中集成并使用cmbsdk_flutter
插件。根据实际需求,你可能需要调整代码以适应特定的业务逻辑和UI设计。