Flutter打印功能插件flutter_savanitdev_printer的使用
Flutter打印功能插件flutter_savanitdev_printer的使用
简介
flutter_savanitdev_printer
是一个用于在 Flutter 应用中实现打印功能的插件。该插件支持多种语言,如泰语和越南语,并且可以连接到不同类型的打印机(例如 Wi-Fi、蓝牙和 USB 打印机)。
安装
要安装此插件,首先需要将其添加到 pubspec.yaml
文件中:
dependencies:
flutter_savanitdev_printer: ^版本号
然后运行以下命令来获取依赖项:
flutter pub get
使用示例
以下是一个完整的示例,展示了如何使用 flutter_savanitdev_printer
插件进行打印操作。
主要代码
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_charset_savanitdev/charset.dart';
import 'package:get/get.dart';
import 'package:image/image.dart' as img;
import 'package:flutter_savanitdev_printer/flutter_savanitdev_printer.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:image_picker/image_picker.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
File? _image;
String? _base64Image;
String _selectedType = 'NET'; // net,2 : ble,3:usb
String _selectedLang = 'TH';
String inputText = '';
final _savanitdevPlugin = FlutterSavanitdevPrinter();
String addressPrinter = '192.168.1.197';
String codePageLang = '70'; // Thai : cp874 70,21 viet : viscii,tcvn 69,27
bool status = false;
List<dynamic> listPrinter = [];
TextEditingController _controller = TextEditingController(text: '192.168.1.197');
[@override](/user/override)
void initState() {
super.initState();
initPlatformState();
}
Uint8List useEncode(String text) {
return windows874.encode(text);
}
autoChangeLang(String text) {}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
try {
if (Platform.isIOS) {
await _savanitdevPlugin.initBLE();
} else {
await _savanitdevPlugin.onCreate();
}
} on PlatformException {}
}
void _onConnect() {
try {
if (_controller.text.isEmpty || addressPrinter.isEmpty) {
Get.snackbar(
"Alert",
"Please check printer!",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
if (_selectedType == "NET") {
_savanitdevPlugin.connectNet(addressPrinter).then((value) async {
autoChangeLang(_selectedLang);
setState(() {
status = true;
});
});
} else if (_selectedType == "BLE") {
_savanitdevPlugin.connectBLE(addressPrinter).then((value) {
Future.delayed(Duration(microseconds: 500), () {
autoChangeLang(_selectedLang);
setState(() {
status = true;
});
});
});
} else {
if (Platform.isAndroid) {
_savanitdevPlugin.connectUSB(addressPrinter).then((value) async {
autoChangeLang(_selectedLang);
setState(() {
status = true;
});
});
}
}
} catch (e) {
print(e);
}
}
_onDisconnect(String value) async {
try {
if (value == "NET" && status) {
await _savanitdevPlugin.disconnectNet(_controller.text.toString());
final mac = value == "NET" ? addressPrinter = _controller.text : "";
setState(() {
listPrinter = [];
addressPrinter = mac;
this._selectedType = value.toString();
status = false;
});
} else if (value == "BLE" && status) {
_savanitdevPlugin.disconnectBLE().then((res) {
final mac = value == "NET" ? addressPrinter = _controller.text : "";
setState(() {
listPrinter = [];
addressPrinter = mac;
this._selectedType = value.toString();
status = false;
});
});
} else {
if (Platform.isAndroid && status) {
_savanitdevPlugin.disconnectBLE().then((res) async {
final mac = value == "NET" ? addressPrinter = _controller.text : "";
setState(() {
listPrinter = [];
addressPrinter = mac;
this._selectedType = value.toString();
status = false;
});
});
} else {
setState(() {
listPrinter = [];
this._selectedType = value.toString();
});
}
}
} catch (e) {
print("error conenct ${e}");
Get.snackbar(
"Alert",
"Please check printer",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
}
}
void _onScanPrinter() {
if (_selectedType == "BLE") {
_savanitdevPlugin.findAvailableDevice().then((value) {
List<dynamic> arr = [];
value?.forEach((data) {
// Remove the curly braces and split the string by commas
List<String> parts = data
.toString()
.substring(1, data.toString().length - 1)
.split(', ');
Map<String, dynamic> resultMap = {};
parts.forEach((part) {
List<String> keyValue = part.split(': ');
resultMap[keyValue[0]] = keyValue[1];
});
arr.add(resultMap);
});
setState(() {
listPrinter = arr;
});
});
} else {
if (Platform.isAndroid) {
_savanitdevPlugin.getUSB().then((value) {
final path = value.toString().replaceAll("[", "").replaceAll("]", "");
List<dynamic> arr = [];
arr.add(path.toString());
setState(() {
listPrinter = arr;
addressPrinter = path.toString();
});
});
}
}
}
void _onButtonPrintRaw() async {
if (addressPrinter.isEmpty || status == false) {
Get.snackbar(
"Alert",
"Please connect printer first!",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
final profile = await CapabilityProfile.load();
final generator = Generator(PaperSize.mm80, profile);
List<int> bytes = [];
final ByteData data = await rootBundle.load('assets/images/logo.png');
final Uint8List imgBytes = data.buffer.asUint8List();
final img.Image image = img.decodeImage(imgBytes)!;
bytes += generator.imageRaster(img.copyResize(image, width: 130, height: 130));
bytes += generator.text(" ");
bytes += generator.text("SavanitDev Shop",
styles: PosStyles(
align: PosAlign.center, bold: true, height: PosTextSize.size1));
bytes += generator.text(" ");
bytes += generator.textEncoded(
useEncode(
_selectedLang == "TH" ? "หมายเลขโต๊ะ : 12345" : "số bàn : 12345"),
styles: PosStyles(align: PosAlign.center));
bytes += generator.text(" ");
bytes += generator.textEncoded(
useEncode(
_selectedLang == "TH" ? "วันที่ 25/05/2024" : "ngày 25/05/2024"),
styles: PosStyles(align: PosAlign.center));
bytes += generator.text(" ");
bytes += generator.row([
PosColumn(
textEncoded: useEncode(_selectedLang == "TH" ? "สินค้า" : "sản phẩm"),
width: 7,
styles: PosStyles(align: PosAlign.left)),
PosColumn(
textEncoded: useEncode(_selectedLang == "TH" ? "จำนวน" : "Số lượng"),
width: 3,
styles: PosStyles(align: PosAlign.left)),
PosColumn(
textEncoded: useEncode(_selectedLang == "TH" ? "ราคา" : "giá"),
width: 2,
styles: PosStyles(align: PosAlign.right)),
]);
final arr = [
{
"name": "ปอเปี๊ยะทอด",
"qty": "2",
"price": "1000.00",
},
{
"name": "อาหารไทย หมี่กรอบ",
"qty": "2",
"price": "45.00",
},
{
"name": "กุ้งลายโสร่ง,ประทัดลม,ทอดมันกุ้ง",
"qty": "2",
"price": "500.00",
},
{
"name": "หมู, เนื้อผึ่งแดดทอด",
"qty": "2",
"price": "10500.00",
},
];
for (var i = 0; i < arr.length; i++) {
final rep = arr[i];
bytes += generator.row([
PosColumn(
textEncoded: useEncode(_selectedLang
? rep["name"].toString()
: "món ăn việt nam"),
width: 7,
styles: PosStyles(align: PosAlign.left)),
PosColumn(
text: rep["qty"].toString(),
width: 2,
styles: PosStyles(align: PosAlign.left)),
PosColumn(
textEncoded: useEncode(_selectedLang
? "${rep["price"].toString()} บาท"
: "100.000 đồng"),
width: 3,
styles: PosStyles(align: PosAlign.right)),
]);
}
bytes += generator.row([
PosColumn(
textEncoded:
useEncode(_selectedLang == "TH" ? "ทั้งหมด" : "tổng cộng"),
width: 5,
styles: PosStyles(align: PosAlign.left)),
PosColumn(
text: "",
width: 1,
styles: PosStyles(align: PosAlign.center),
),
PosColumn(
textEncoded:
useEncode(_selectedLang == "TH" ? "500 บาท" : "100.000 đồng"),
width: 6,
styles: PosStyles(align: PosAlign.right)),
]);
bytes += generator.row([
PosColumn(
textEncoded: useEncode(_selectedLang ? "ลดราคา" : "giảm giá"),
width: 5,
styles: PosStyles(align: PosAlign.left)),
PosColumn(
text: "",
width: 1,
styles: PosStyles(align: PosAlign.center),
),
PosColumn(
textEncoded:
useEncode(_selectedLang == "TH" ? "500 บาท" : "100.000 đồng"),
width: 6,
styles: PosStyles(align: PosAlign.right)),
]);
bytes += generator.row([
PosColumn(
textEncoded: useEncode(_selectedLang ? "ค่าบริการ 10%" : "Phí dịch vụ 10%"),
width: 5,
styles: PosStyles(align: PosAlign.left)),
PosColumn(
text: "",
width: 1,
styles: PosStyles(align: PosAlign.center),
),
PosColumn(
textEncoded:
useEncode(_selectedLang == "TH" ? "50 บาท" : "10.000 đồng"),
width: 6,
styles: PosStyles(align: PosAlign.right)),
]);
bytes += generator.row([
PosColumn(
text: "VAT 7%",
width: 5,
styles: PosStyles(align: PosAlign.left),
),
PosColumn(
text: "",
width: 1,
styles: PosStyles(align: PosAlign.center),
),
PosColumn(
textEncoded:
useEncode(_selectedLang == "TH" ? "50 บาท" : "10.000 đồng"),
width: 6,
styles: PosStyles(align: PosAlign.right)),
]);
bytes += generator.hr(ch: "-");
bytes += generator.row([
PosColumn(
textEncoded:
useEncode(_selectedLang == "TH" ? "ทั้งหมด" : "tổng cộng"),
width: 5,
styles: PosStyles(align: PosAlign.left, bold: true)),
PosColumn(
text: "",
width: 1,
styles: PosStyles(align: PosAlign.center),
),
PosColumn(
textEncoded:
useEncode(_selectedLang == "TH" ? "50 บาท" : "10.000 đồng"),
width: 6,
styles: PosStyles(align: PosAlign.right, bold: true)),
]);
bytes += generator.hr(ch: "-");
bytes += generator.text(" ");
bytes += generator.text("Scan QR code for visit my Facebook",
styles: PosStyles(align: PosAlign.center));
bytes += generator.text(" ");
bytes += generator.qrcode("https://www.facebook.com/SavanitDev",
size: QRSize.Size8);
bytes += generator.text(" ");
bytes += generator.hr(ch: ".");
bytes += generator.text(" ");
bytes +=
generator.text("Thank you", styles: PosStyles(align: PosAlign.center));
bytes += generator.textEncoded(
useEncode(_selectedLang
? "สร้าง library นี้โดย"
: "tạo thư viện này bởi"));
bytes += generator.textEncoded(
useEncode("https://www.facebook.com/SavanitDev"),
styles: PosStyles(align: PosAlign.center));
bytes += generator.feed(2);
bytes += generator.cut();
String base64String = base64Encode(bytes);
if (_selectedType == "NET") {
await _savanitdevPlugin.printRawData(addressPrinter, base64String, false);
} else if (_selectedType == "BLE") {
await _savanitdevPlugin.rawDataBLE(base64String);
} else {
if (Platform.isAndroid) {
await _savanitdevPlugin.printRawData(
addressPrinter, base64String, false);
}
}
}
void _onButtonPrintText() async {
if (addressPrinter.isEmpty || status == false) {
Get.snackbar(
"Alert",
"Please connect printer first!",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
if (inputText.isEmpty) {
Get.snackbar(
"Alert",
"Please input your text",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
final profile = await CapabilityProfile.load();
final generator = Generator(PaperSize.mm80, profile);
List<int> bytes = [];
try {
bytes += generator.textEncoded(useEncode(inputText));
} catch (e) {
Get.snackbar(
"Alert use not correct language",
"this library just support Thai,vietnam and english, if you want you use other languages please contact me : https://www.facebook.com/SavanitDev",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
bytes +=
generator.textEncoded(useEncode("https://www.facebook.com/SavanitDev"));
bytes += generator.feed(2);
bytes += generator.cut();
String base64String = base64Encode(bytes);
if (_selectedType == "NET") {
await _savanitdevPlugin.printRawData(addressPrinter, base64String, false);
} else if (_selectedType == "BLE") {
await _savanitdevPlugin.rawDataBLE(base64String);
} else {
if (Platform.isAndroid) {
await _savanitdevPlugin.printRawData(
addressPrinter, base64String, false);
}
}
}
void _onButtonPremissionUSB() {
if (addressPrinter.isEmpty || status == false) {
Get.snackbar(
"Alert",
"Please connect printer first!",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
_savanitdevPlugin.tryGetUsbPermission().then((value) {
// print("tryGetUsbPermission -> ${value.toString()}");
});
}
void _onButtonBlePermission() async {
if (addressPrinter.isEmpty || status == false) {
Get.snackbar(
"Alert",
"Please connect printer first!",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
await _savanitdevPlugin.reqBlePermission();
}
void _onPrintImg() {
if (addressPrinter.isEmpty || status == false) {
Get.snackbar(
"Alert",
"Please connect printer first!",
colorText: Colors.white,
backgroundColor: Colors.lightBlue,
icon: const Icon(Icons.add_alert),
);
return;
}
_savanitdevPlugin.image64BaseBLE(_base64Image!, 576, 0).then((value) {
print("image64BaseBLE -> ${value.toString()}");
});
}
Future<void> _pickImage() async {
final picker = ImagePicker();
final pickedImage = await picker.pickImage(source: ImageSource.gallery);
setState(() {
if (pickedImage != null) {
_image = File(pickedImage.path);
_convertImageToBase64();
} else {
print('No image selected.');
}
});
}
Future<void> _convertImageToBase64() async {
if (_image != null) {
List<int> imageBytes = await _image!.readAsBytes();
setState(() {
_base64Image = base64Encode(imageBytes);
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Savanitdev Printer'),
),
body: Center(
child: Builder(builder: (context) {
return ListView(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () async {
final Uri url = Uri.parse('https://www.facebook.com/SavanitDev');
if (!await launchUrl(url)) {
throw Exception('Could not launch');
}
},
child: const Text('contact support'),
),
),
Center(
child: Text(
"Status : ${status && addressPrinter.isNotEmpty ? "Connected" : "No connect"}",
style: TextStyle(color: status ? Colors.green : Colors.red),
)),
Wrap(
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: DropdownButton<String>(
value: _selectedType.isEmpty ? "NET" : _selectedType,
items: <String>[
'NET',
'BLE',
'USB',
].map((String val) {
return DropdownMenuItem<String>(
value: val,
child: Text(val),
);
}).toList(),
onChanged: (String? value) {
_onDisconnect(value.toString());
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: DropdownButton<String>(
value: _selectedLang,
items: <String>[
'TH',
'VN',
].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? value) {
autoChangeLang(value.toString());
setState(() {
_selectedLang = value.toString();
});
},
),
),
_selectedType == "NET"
? Container(
width: 300,
height: 40,
alignment: Alignment.centerLeft,
child: TextField(
controller: _controller,
onChanged: (text) {
setState(() {
addressPrinter = text;
});
},
decoration: InputDecoration(
hintText: 'Enter your text here',
labelText: 'address ${_selectedType}',
border: const OutlineInputBorder(),
),
),
)
: Container(
width: 300,
child: Column(
children: [
const Text("List printer"),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(listPrinter.length, (index) {
final data = listPrinter[index];
return InkWell(
onTap: () {
setState(() {
addressPrinter = data["deviceAddress"].toString();
});
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
textAlign: TextAlign.left,
_selectedType == "BLE"
? "${addressPrinter == data["deviceAddress"].toString() ? "✅" : ""} ${data["name"].toString()} : ${data["deviceAddress"].toString()}"
: "${data.toString().isNotEmpty && addressPrinter == data.toString() ? "✅" : ""} ${data.toString()}",
),
));
}),
),
],
)),
_selectedType != "NET"
? Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _onScanPrinter,
child: const Text('scan'),
),
)
: Container(),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _onConnect,
child: const Text('connect'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () async {
await _onDisconnect(_selectedType);
},
child: const Text('disconnect'),
),
),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: 240, // TextField width
height: 120, // TextField height
child: TextField(
maxLines: null,
expands: true,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
filled: true, hintText: 'Enter text here'),
onChanged: (String? value) {
setState(() {
inputText = value.toString();
});
},
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _onButtonPrintText,
child: const Text('print text'),
),
),
Center(child: SizedBox(height: 20)),
_image == null
? Center(child: Text('No image selected.'))
: Image.file(_image!, width: 400, height: 400),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _pickImage,
child: const Text('choose image'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _onPrintImg,
child: const Text('image print'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _onButtonPrintRaw,
child: const Text('print template Rawdata'),
),
),
Platform.isAndroid
? Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _onButtonPremissionUSB,
child: const Text('request Usb Permission'),
),
)
: const Text(""),
Platform.isAndroid
? Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _onButtonBlePermission,
child: const Text('request Bluetooth Permission'),
),
)
: const Text(""),
],
);
}),
),
),
);
}
}
更多关于Flutter打印功能插件flutter_savanitdev_printer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter打印功能插件flutter_savanitdev_printer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用flutter_savanitdev_printer
插件来实现打印功能的示例代码。这个插件假设你已经添加到了你的pubspec.yaml
文件中,并且已经运行了flutter pub get
来安装它。
1. 添加依赖
首先,确保在你的pubspec.yaml
文件中添加了flutter_savanitdev_printer
依赖:
dependencies:
flutter:
sdk: flutter
flutter_savanitdev_printer: ^最新版本号 # 替换为实际版本号
2. 导入插件
在你的Dart文件中(比如main.dart
),导入插件:
import 'package:flutter/material.dart';
import 'package:flutter_savanitdev_printer/flutter_savanitdev_printer.dart';
3. 使用插件进行打印
下面是一个简单的示例,展示如何使用flutter_savanitdev_printer
插件来打印文本:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Printer Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String printResult = "";
void _printText() async {
try {
// 假设你有一个蓝牙打印机并且已经连接
String printerAddress = "你的打印机地址"; // 替换为实际的打印机地址
String textToPrint = "Hello, Flutter Printer!";
// 打印文本
bool success = await FlutterSavanitdevPrinter.printText(
printerAddress: printerAddress,
text: textToPrint,
);
if (success) {
setState(() {
printResult = "打印成功!";
});
} else {
setState(() {
printResult = "打印失败,请检查打印机连接。";
});
}
} catch (e) {
setState(() {
printResult = "发生错误: ${e.message}";
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Printer Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'点击按钮打印文本',
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _printText,
child: Text('打印'),
),
SizedBox(height: 20),
Text(
printResult,
style: TextStyle(color: Colors.red),
),
],
),
),
);
}
}
注意事项
-
打印机连接:确保你的打印机已经正确连接到设备,并且地址是正确的。对于蓝牙打印机,你可能需要先进行配对。
-
错误处理:上面的代码包含了基本的错误处理,你可以根据需要进一步扩展。
-
插件功能:
flutter_savanitdev_printer
插件可能有更多的功能,比如打印图片、条形码等,你可以查阅其官方文档来了解更多细节。 -
权限:确保你的应用有必要的权限,比如蓝牙权限,以访问和连接打印机。
这个示例展示了如何使用flutter_savanitdev_printer
插件在Flutter应用中实现基本的打印功能。如果你需要更复杂的打印需求,请查阅插件的官方文档或源代码以获取更多信息。