├── ios ├── Assets │ └── .gitkeep ├── .gitignore ├── Classes │ └── FlutterThermalPrinterPlugin.swift └── flutter_thermal_printer.podspec ├── example ├── linux │ ├── .gitignore │ ├── main.cc │ ├── flutter │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ ├── generated_plugins.cmake │ │ └── CMakeLists.txt │ ├── my_application.h │ ├── my_application.cc │ └── CMakeLists.txt ├── ios │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── .gitignore │ ├── RunnerTests │ │ └── RunnerTests.swift │ ├── Podfile.lock │ └── Podfile ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ ├── Icon-512.png │ │ ├── Icon-maskable-192.png │ │ └── Icon-maskable-512.png │ ├── manifest.json │ └── index.html ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── xml │ │ │ │ │ │ └── device_filter.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── flutter_thermal_printer_example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── flutter_thermal_printer_example │ │ │ │ │ │ └── MainActivity.java │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── build.gradle │ └── settings.gradle ├── macos │ ├── Runner │ │ ├── Configs │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ ├── Warnings.xcconfig │ │ │ └── AppInfo.xcconfig │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── app_icon_128.png │ │ │ │ ├── app_icon_16.png │ │ │ │ ├── app_icon_256.png │ │ │ │ ├── app_icon_32.png │ │ │ │ ├── app_icon_512.png │ │ │ │ ├── app_icon_64.png │ │ │ │ ├── app_icon_1024.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── MainFlutterWindow.swift │ │ ├── Release.entitlements │ │ ├── DebugProfile.entitlements │ │ └── Info.plist │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── RunnerTests │ │ └── RunnerTests.swift │ ├── Podfile.lock │ └── Podfile ├── windows │ ├── runner │ │ ├── resources │ │ │ └── app_icon.ico │ │ ├── resource.h │ │ ├── utils.h │ │ ├── runner.exe.manifest │ │ ├── flutter_window.h │ │ ├── main.cpp │ │ ├── CMakeLists.txt │ │ ├── utils.cpp │ │ ├── flutter_window.cpp │ │ ├── Runner.rc │ │ └── win32_window.h │ ├── .gitignore │ ├── flutter │ │ ├── generated_plugin_registrant.h │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugins.cmake │ │ └── CMakeLists.txt │ └── CMakeLists.txt ├── integration_test │ └── plugin_integration_test.dart ├── README.md ├── .gitignore ├── test │ └── widget_test.dart ├── analysis_options.yaml ├── .metadata └── pubspec.yaml ├── android ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .gitignore ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── flutter_thermal_printer │ │ │ └── FlutterThermalPrinterPlugin.java │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ └── flutter_thermal_printer │ │ └── FlutterThermalPrinterPluginTest.java ├── build.gradle └── gradlew.bat ├── .gitattributes ├── lib ├── Windows │ ├── windows_platform.dart │ ├── windows_stub.dart │ ├── print_data.dart │ └── printers_data.dart ├── utils │ ├── ble_config.dart │ └── printer.dart ├── network │ ├── network_print_result.dart │ └── network_printer.dart ├── flutter_thermal_printer_platform_interface.dart └── flutter_thermal_printer_method_channel.dart ├── windows ├── .gitignore ├── flutter_thermal_printer_plugin_c_api.cpp ├── include │ └── flutter_thermal_printer │ │ └── flutter_thermal_printer_plugin_c_api.h ├── flutter_thermal_printer_plugin.h ├── test │ └── flutter_thermal_printer_plugin_test.cpp ├── flutter_thermal_printer_plugin.cpp └── CMakeLists.txt ├── .gitignore ├── .vscode ├── tasks.json ├── c_cpp_properties.json ├── launch.json └── settings.json ├── test ├── flutter_thermal_printer_method_channel_test.dart ├── mocks │ └── mock_platform.dart ├── unit │ ├── network_print_result_test.dart │ ├── platform_interface_test.dart │ └── ble_config_test.dart └── flutter_thermal_printer_test.dart ├── macos └── flutter_thermal_printer.podspec ├── .metadata ├── LICENSE ├── pubspec.yaml ├── CHANGELOG.md └── README.md /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_thermal_printer' 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/web/favicon.png -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .cxx 10 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SunilDevX/flutter_thermal_printer/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/flutter_thermal_printer_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_thermal_printer_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void fl_register_plugins(FlPluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip 6 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/flutter_thermal_printer_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.flutter_thermal_printer_example; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | } 7 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /lib/Windows/windows_platform.dart: -------------------------------------------------------------------------------- 1 | // Windows-specific printer functionality 2 | // This file re-exports Windows printer classes and constants 3 | 4 | export 'package:ffi/ffi.dart' show using; 5 | export 'package:win32/win32.dart' show PRINTER_ENUM_LOCAL; 6 | 7 | export 'print_data.dart'; 8 | export 'printers_data.dart'; 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | app/.cxx 15 | -------------------------------------------------------------------------------- /example/macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import FlutterMacOS 2 | import Cocoa 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /example/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /example/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import flutter_thermal_printer 9 | import universal_ble 10 | 11 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 12 | FlutterThermalPrinterPlugin.register(with: registry.registrar(forPlugin: "FlutterThermalPrinterPlugin")) 13 | UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin")) 14 | } 15 | -------------------------------------------------------------------------------- /example/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /windows/flutter_thermal_printer_plugin_c_api.cpp: -------------------------------------------------------------------------------- 1 | #include "include/flutter_thermal_printer/flutter_thermal_printer_plugin_c_api.h" 2 | 3 | #include 4 | 5 | #include "flutter_thermal_printer_plugin.h" 6 | 7 | void FlutterThermalPrinterPluginCApiRegisterWithRegistrar( 8 | FlutterDesktopPluginRegistrarRef registrar) { 9 | flutter_thermal_printer::FlutterThermalPrinterPlugin::RegisterWithRegistrar( 10 | flutter::PluginRegistrarManager::GetInstance() 11 | ->GetRegistrar(registrar)); 12 | } 13 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | mavenCentral() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | tasks.register("clean", Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /lib/utils/ble_config.dart: -------------------------------------------------------------------------------- 1 | class BleConfig { 2 | const BleConfig({ 3 | this.connectionStabilizationDelay = const Duration(seconds: 10), 4 | }); 5 | 6 | final Duration connectionStabilizationDelay; 7 | 8 | BleConfig copyWith({ 9 | Duration? connectionStabilizationDelay, 10 | }) => 11 | BleConfig( 12 | connectionStabilizationDelay: 13 | connectionStabilizationDelay ?? this.connectionStabilizationDelay, 14 | ); 15 | 16 | @override 17 | String toString() => 18 | 'BleConfig(connectionStabilizationDelay: $connectionStabilizationDelay)'; 19 | } 20 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.device.bluetooth 8 | 9 | com.apple.security.device.usb 10 | 11 | com.apple.security.network.client 12 | 13 | com.apple.security.network.server 14 | 15 | com.apple.security.print 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example/integration_test/plugin_integration_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter integration test. 2 | // 3 | // Since integration tests run in a full Flutter application, they can interact 4 | // with the host side of a plugin implementation, unlike Dart unit tests. 5 | // 6 | // For more information about Flutter integration tests, please see 7 | // https://docs.flutter.dev/cookbook/testing/integration/introduction 8 | 9 | import 'package:flutter_test/flutter_test.dart'; 10 | import 'package:integration_test/integration_test.dart'; 11 | 12 | void main() { 13 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 14 | expect(true, true); 15 | } 16 | -------------------------------------------------------------------------------- /example/windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | 12 | void RegisterPlugins(flutter::PluginRegistry* registry) { 13 | FlutterThermalPrinterPluginCApiRegisterWithRegistrar( 14 | registry->GetRegistrarForPlugin("FlutterThermalPrinterPluginCApi")); 15 | UniversalBlePluginCApiRegisterWithRegistrar( 16 | registry->GetRegistrarForPlugin("UniversalBlePluginCApi")); 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | build/ 30 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.device.bluetooth 10 | 11 | com.apple.security.device.usb 12 | 13 | com.apple.security.network.client 14 | 15 | com.apple.security.network.server 16 | 17 | com.apple.security.print 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_thermal_printer_example 2 | 3 | Demonstrates how to use the flutter_thermal_printer plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /example/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /windows/include/flutter_thermal_printer/flutter_thermal_printer_plugin_c_api.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_PLUGIN_FLUTTER_THERMAL_PRINTER_PLUGIN_C_API_H_ 2 | #define FLUTTER_PLUGIN_FLUTTER_THERMAL_PRINTER_PLUGIN_C_API_H_ 3 | 4 | #include 5 | 6 | #ifdef FLUTTER_PLUGIN_IMPL 7 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) 8 | #else 9 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) 10 | #endif 11 | 12 | #if defined(__cplusplus) 13 | extern "C" { 14 | #endif 15 | 16 | FLUTTER_PLUGIN_EXPORT void FlutterThermalPrinterPluginCApiRegisterWithRegistrar( 17 | FlutterDesktopPluginRegistrarRef registrar); 18 | 19 | #if defined(__cplusplus) 20 | } // extern "C" 21 | #endif 22 | 23 | #endif // FLUTTER_PLUGIN_FLUTTER_THERMAL_PRINTER_PLUGIN_C_API_H_ 24 | -------------------------------------------------------------------------------- /ios/Classes/FlutterThermalPrinterPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | public class FlutterThermalPrinterPlugin: NSObject, FlutterPlugin { 5 | public static func register(with registrar: FlutterPluginRegistrar) { 6 | let channel = FlutterMethodChannel(name: "flutter_thermal_printer", binaryMessenger: registrar.messenger()) 7 | let instance = FlutterThermalPrinterPlugin() 8 | registrar.addMethodCallDelegate(instance, channel: channel) 9 | } 10 | 11 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 12 | switch call.method { 13 | case "getPlatformVersion": 14 | result("iOS " + UIDevice.current.systemVersion) 15 | default: 16 | result(FlutterMethodNotImplemented) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: cl.exe build active file", 6 | "command": "cl.exe", 7 | "args": [ 8 | "/Zi", 9 | "/EHsc", 10 | "/nologo", 11 | "/Fe${fileDirname}\\${fileBasenameNoExtension}.exe", 12 | "${file}" 13 | ], 14 | "options": { 15 | "cwd": "${fileDirname}" 16 | }, 17 | "problemMatcher": [ 18 | "$msCompile" 19 | ], 20 | "group": { 21 | "kind": "build", 22 | "isDefault": true 23 | }, 24 | "detail": "Task generated by Debugger." 25 | } 26 | ], 27 | "version": "2.0.0" 28 | } -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${workspaceFolder}/example/build/windows/x64/_deps/googletest-src/googletest/include/gtest", 8 | "${workspaceFolder}/example/build/windows/x64/_deps/googletest-src/googletest/include" 9 | ], 10 | "defines": [ 11 | "_DEBUG", 12 | "UNICODE", 13 | "_UNICODE" 14 | ], 15 | "windowsSdkVersion": "10.0.22621.0", 16 | "compilerPath": "cl.exe", 17 | "cStandard": "c17", 18 | "cppStandard": "c++17", 19 | "intelliSenseMode": "windows-msvc-x64" 20 | } 21 | ], 22 | "version": 4 23 | } -------------------------------------------------------------------------------- /example/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | @testable import flutter_thermal_printer 6 | 7 | // This demonstrates a simple unit test of the Swift portion of this plugin's implementation. 8 | // 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | 11 | class RunnerTests: XCTestCase { 12 | 13 | func testGetPlatformVersion() { 14 | let plugin = FlutterThermalPrinterPlugin() 15 | 16 | let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) 17 | 18 | let resultExpectation = expectation(description: "result block must be called.") 19 | plugin.handle(call) { result in 20 | XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion) 21 | resultExpectation.fulfill() 22 | } 23 | waitForExpectations(timeout: 1) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .pub-cache/ 33 | .pub/ 34 | /build/ 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | -------------------------------------------------------------------------------- /example/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | flutter_thermal_printer 7 | universal_ble 8 | ) 9 | 10 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | 22 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 23 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 24 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 25 | endforeach(ffi_plugin) 26 | -------------------------------------------------------------------------------- /lib/Windows/windows_stub.dart: -------------------------------------------------------------------------------- 1 | // Stub implementation for non-Windows platforms 2 | // This file provides empty implementations for Windows-specific functionality 3 | // ignore_for_file: avoid_annotating_with_dynamic 4 | 5 | // Win32 constants stub 6 | // ignore: constant_identifier_names 7 | const int PRINTER_ENUM_LOCAL = 0x00000002; 8 | 9 | class PrinterNames { 10 | PrinterNames(int _); 11 | 12 | Iterable all() sync* { 13 | // No Windows printers available on non-Windows platforms 14 | } 15 | } 16 | 17 | class RawPrinter { 18 | RawPrinter(String _, __); 19 | 20 | void printEscPosWin32(List data) { 21 | throw UnsupportedError( 22 | 'Windows printing is not supported on this platform', 23 | ); 24 | } 25 | } 26 | 27 | // Stub implementation for FFI's using function 28 | R using(R Function() computation) { 29 | throw UnsupportedError('FFI using function is not supported on web platform'); 30 | } 31 | -------------------------------------------------------------------------------- /test/flutter_thermal_printer_method_channel_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flutter_thermal_printer/flutter_thermal_printer_method_channel.dart'; 4 | 5 | void main() { 6 | TestWidgetsFlutterBinding.ensureInitialized(); 7 | 8 | final platform = MethodChannelFlutterThermalPrinter(); 9 | const channel = MethodChannel('flutter_thermal_printer'); 10 | 11 | setUp(() { 12 | TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger 13 | .setMockMethodCallHandler( 14 | channel, 15 | (methodCall) async => '42', 16 | ); 17 | }); 18 | 19 | tearDown(() { 20 | TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger 21 | .setMockMethodCallHandler(channel, null); 22 | }); 23 | 24 | test('getPlatformVersion', () async { 25 | expect(await platform.getPlatformVersion(), '42'); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false 21 | } 22 | } 23 | 24 | plugins { 25 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 26 | id "com.android.application" version "7.3.0" apply false 27 | } 28 | 29 | include ":app" 30 | -------------------------------------------------------------------------------- /macos/flutter_thermal_printer.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_thermal_printer.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_thermal_printer' 7 | s.version = '0.0.1' 8 | s.summary = 'A new Flutter project.' 9 | s.description = <<-DESC 10 | A new Flutter project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | 16 | s.source = { :path => '.' } 17 | s.source_files = 'Classes/**/*' 18 | s.dependency 'FlutterMacOS' 19 | # s.dependency 'ORSSerialPort' 20 | # s.dependency 'USBDeviceSwift' 21 | s.platform = :osx, '10.14' 22 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } 23 | s.swift_version = '5.0' 24 | end 25 | -------------------------------------------------------------------------------- /example/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ios/flutter_thermal_printer.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint flutter_thermal_printer.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'flutter_thermal_printer' 7 | s.version = '0.0.1' 8 | s.summary = 'A new Flutter project.' 9 | s.description = <<-DESC 10 | A new Flutter project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '11.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /example/macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - flutter_thermal_printer (0.0.1): 3 | - FlutterMacOS 4 | - FlutterMacOS (1.0.0) 5 | - universal_ble (0.0.1): 6 | - Flutter 7 | - FlutterMacOS 8 | 9 | DEPENDENCIES: 10 | - flutter_thermal_printer (from `Flutter/ephemeral/.symlinks/plugins/flutter_thermal_printer/macos`) 11 | - FlutterMacOS (from `Flutter/ephemeral`) 12 | - universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`) 13 | 14 | EXTERNAL SOURCES: 15 | flutter_thermal_printer: 16 | :path: Flutter/ephemeral/.symlinks/plugins/flutter_thermal_printer/macos 17 | FlutterMacOS: 18 | :path: Flutter/ephemeral 19 | universal_ble: 20 | :path: Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin 21 | 22 | SPEC CHECKSUMS: 23 | flutter_thermal_printer: 89ad742652b32933223d893678c14cbd59579ed0 24 | FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 25 | universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 26 | 27 | PODFILE CHECKSUM: 3c8ad955ec40fb62e263a45c008146ad22756f7a 28 | 29 | COCOAPODS: 1.16.2 30 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_thermal_printer_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => widget is Text && 22 | widget.data!.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /example/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /windows/flutter_thermal_printer_plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_PLUGIN_FLUTTER_THERMAL_PRINTER_PLUGIN_H_ 2 | #define FLUTTER_PLUGIN_FLUTTER_THERMAL_PRINTER_PLUGIN_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace flutter_thermal_printer { 10 | 11 | class FlutterThermalPrinterPlugin : public flutter::Plugin { 12 | public: 13 | static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); 14 | 15 | FlutterThermalPrinterPlugin(); 16 | 17 | virtual ~FlutterThermalPrinterPlugin(); 18 | 19 | // Disallow copy and assign. 20 | FlutterThermalPrinterPlugin(const FlutterThermalPrinterPlugin&) = delete; 21 | FlutterThermalPrinterPlugin& operator=(const FlutterThermalPrinterPlugin&) = delete; 22 | 23 | // Called when a method is called on this plugin's channel from Dart. 24 | void HandleMethodCall( 25 | const flutter::MethodCall &method_call, 26 | std::unique_ptr> result); 27 | }; 28 | 29 | } // namespace flutter_thermal_printer 30 | 31 | #endif // FLUTTER_PLUGIN_FLUTTER_THERMAL_PRINTER_PLUGIN_H_ 32 | -------------------------------------------------------------------------------- /android/src/test/java/com/example/flutter_thermal_printer/FlutterThermalPrinterPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.example.flutter_thermal_printer; 2 | 3 | import static org.mockito.Mockito.mock; 4 | import static org.mockito.Mockito.verify; 5 | 6 | import io.flutter.plugin.common.MethodCall; 7 | import io.flutter.plugin.common.MethodChannel; 8 | import org.junit.Test; 9 | 10 | /** 11 | * This demonstrates a simple unit test of the Java portion of this plugin's implementation. 12 | * 13 | * Once you have built the plugin's example app, you can run these tests from the command 14 | * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or 15 | * you can run them directly from IDEs that support JUnit such as Android Studio. 16 | */ 17 | 18 | public class FlutterThermalPrinterPluginTest { 19 | @Test 20 | public void onMethodCall_getPlatformVersion_returnsExpectedValue() { 21 | FlutterThermalPrinterPlugin plugin = new FlutterThermalPrinterPlugin(); 22 | 23 | final MethodCall call = new MethodCall("getPlatformVersion", null); 24 | MethodChannel.Result mockResult = mock(MethodChannel.Result.class); 25 | plugin.onMethodCall(call, mockResult); 26 | 27 | verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/network/network_print_result.dart: -------------------------------------------------------------------------------- 1 | class NetworkPrintResult { 2 | const NetworkPrintResult._internal(this.value); 3 | final int value; 4 | static const success = NetworkPrintResult._internal(1); 5 | static const timeout = NetworkPrintResult._internal(2); 6 | static const printerConnected = NetworkPrintResult._internal(3); 7 | static const ticketEmpty = NetworkPrintResult._internal(4); 8 | static const printInProgress = NetworkPrintResult._internal(5); 9 | static const scanInProgress = NetworkPrintResult._internal(6); 10 | 11 | String get msg { 12 | if (value == NetworkPrintResult.success.value) { 13 | return 'Success'; 14 | } else if (value == NetworkPrintResult.timeout.value) { 15 | return 'Error. Printer connection timeout'; 16 | } else if (value == NetworkPrintResult.printerConnected.value) { 17 | return 'Error. Printer not connected'; 18 | } else if (value == NetworkPrintResult.ticketEmpty.value) { 19 | return 'Error. Ticket is empty'; 20 | } else if (value == NetworkPrintResult.printInProgress.value) { 21 | return 'Error. Another print in progress'; 22 | } else if (value == NetworkPrintResult.scanInProgress.value) { 23 | return 'Error. Printer scanning in progress'; 24 | } else { 25 | return 'Unknown error'; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.example.flutter_thermal_printer' 2 | version '1.0' 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | mavenCentral() 8 | 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:7.3.0' 13 | 14 | } 15 | } 16 | 17 | rootProject.allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | 26 | android { 27 | if (project.android.hasProperty("namespace")) { 28 | namespace 'com.example.flutter_thermal_printer' 29 | } 30 | 31 | compileSdkVersion 36 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | 38 | defaultConfig { 39 | minSdkVersion 19 40 | } 41 | 42 | dependencies { 43 | testImplementation 'junit:junit:4.13.2' 44 | testImplementation 'org.mockito:mockito-core:5.0.0' 45 | } 46 | 47 | testOptions { 48 | unitTests.all { 49 | testLogging { 50 | events "passed", "skipped", "failed", "standardOut", "standardError" 51 | outputs.upToDateWhen {false} 52 | showStandardStreams = true 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /windows/test/flutter_thermal_printer_plugin_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "flutter_thermal_printer_plugin.h" 12 | 13 | namespace flutter_thermal_printer { 14 | namespace test { 15 | 16 | namespace { 17 | 18 | using flutter::EncodableMap; 19 | using flutter::EncodableValue; 20 | using flutter::MethodCall; 21 | using flutter::MethodResultFunctions; 22 | 23 | } // namespace 24 | 25 | TEST(FlutterThermalPrinterPlugin, GetPlatformVersion) { 26 | FlutterThermalPrinterPlugin plugin; 27 | // Save the reply value from the success callback. 28 | std::string result_string; 29 | plugin.HandleMethodCall( 30 | MethodCall("getPlatformVersion", std::make_unique()), 31 | std::make_unique>( 32 | [&result_string](const EncodableValue* result) { 33 | result_string = std::get(*result); 34 | }, 35 | nullptr, nullptr)); 36 | 37 | // Since the exact string varies by host, just ensure that it's a string 38 | // with the expected format. 39 | EXPECT_TRUE(result_string.rfind("Windows ", 0) == 0); 40 | } 41 | 42 | } // namespace test 43 | } // namespace flutter_thermal_printer 44 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "flutter_thermal_printer", 9 | "request": "launch", 10 | "type": "dart" 11 | }, 12 | { 13 | "name": "flutter_thermal_printer (profile mode)", 14 | "request": "launch", 15 | "type": "dart", 16 | "flutterMode": "profile" 17 | }, 18 | { 19 | "name": "flutter_thermal_printer (release mode)", 20 | "request": "launch", 21 | "type": "dart", 22 | "flutterMode": "release" 23 | }, 24 | { 25 | "name": "example", 26 | "cwd": "example", 27 | "request": "launch", 28 | "type": "dart" 29 | }, 30 | { 31 | "name": "example (profile mode)", 32 | "cwd": "example", 33 | "request": "launch", 34 | "type": "dart", 35 | "flutterMode": "profile" 36 | }, 37 | { 38 | "name": "example (release mode)", 39 | "cwd": "example", 40 | "request": "launch", 41 | "type": "dart", 42 | "flutterMode": "release" 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /example/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"flutter_thermal_printer_example", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | 7 | LSApplicationCategoryType 8 | 9 | NSCameraPortraitEffectEnabled 10 | 11 | CFBundleDevelopmentRegion 12 | $(DEVELOPMENT_LANGUAGE) 13 | CFBundleExecutable 14 | $(EXECUTABLE_NAME) 15 | CFBundleIconFile 16 | 17 | CFBundleIdentifier 18 | $(PRODUCT_BUNDLE_IDENTIFIER) 19 | CFBundleInfoDictionaryVersion 20 | 6.0 21 | CFBundleName 22 | $(PRODUCT_NAME) 23 | CFBundlePackageType 24 | APPL 25 | CFBundleShortVersionString 26 | $(FLUTTER_BUILD_NAME) 27 | CFBundleVersion 28 | $(FLUTTER_BUILD_NUMBER) 29 | LSMinimumSystemVersion 30 | $(MACOSX_DEPLOYMENT_TARGET) 31 | NSHumanReadableCopyright 32 | $(PRODUCT_COPYRIGHT) 33 | NSMainNibFile 34 | MainMenu 35 | NSPrincipalClass 36 | NSApplication 37 | NSBluetoothAlwaysUsageDescription 38 | For printer scanner 39 | 40 | 41 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_blue_plus (0.0.1): 4 | - Flutter 5 | - flutter_thermal_printer (0.0.1): 6 | - Flutter 7 | - integration_test (0.0.1): 8 | - Flutter 9 | - path_provider_foundation (0.0.1): 10 | - Flutter 11 | - FlutterMacOS 12 | 13 | DEPENDENCIES: 14 | - Flutter (from `Flutter`) 15 | - flutter_blue_plus (from `.symlinks/plugins/flutter_blue_plus/ios`) 16 | - flutter_thermal_printer (from `.symlinks/plugins/flutter_thermal_printer/ios`) 17 | - integration_test (from `.symlinks/plugins/integration_test/ios`) 18 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) 19 | 20 | EXTERNAL SOURCES: 21 | Flutter: 22 | :path: Flutter 23 | flutter_blue_plus: 24 | :path: ".symlinks/plugins/flutter_blue_plus/ios" 25 | flutter_thermal_printer: 26 | :path: ".symlinks/plugins/flutter_thermal_printer/ios" 27 | integration_test: 28 | :path: ".symlinks/plugins/integration_test/ios" 29 | path_provider_foundation: 30 | :path: ".symlinks/plugins/path_provider_foundation/darwin" 31 | 32 | SPEC CHECKSUMS: 33 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 34 | flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96 35 | flutter_thermal_printer: b8d6327b4d50d4d810a7568188692d0db882c3e6 36 | integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 37 | path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 38 | 39 | PODFILE CHECKSUM: 7be435dfd2f26876bfa5e0357ac24dbb6d9646e7 40 | 41 | COCOAPODS: 1.16.2 42 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9" 8 | channel: "stable" 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 17 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 18 | - platform: android 19 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 20 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 21 | - platform: ios 22 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 23 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 24 | - platform: macos 25 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 26 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 27 | - platform: windows 28 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 29 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 30 | 31 | # User provided section 32 | 33 | # List of Local paths (relative to this file) that should be 34 | # ignored by the migrate tool. 35 | # 36 | # Files that are not part of the templates will be ignored by default. 37 | unmanaged_files: 38 | - 'lib/main.dart' 39 | - 'ios/Runner.xcodeproj/project.pbxproj' 40 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_ios_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Note: This license has also been called the “New BSD License” or “Modified BSD License”. See also the 2-clause BSD License. 2 | 3 | Copyright 2023 @sunilflutter.in 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 11 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 14 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.15' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 33 | target 'RunnerTests' do 34 | inherit! :search_paths 35 | end 36 | end 37 | 38 | post_install do |installer| 39 | installer.pods_project.targets.each do |target| 40 | flutter_additional_macos_build_settings(target) 41 | target.build_configurations.each do |config| 42 | config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.14' 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/Windows/print_data.dart: -------------------------------------------------------------------------------- 1 | // Sends RAW data (string or hex sequences) directly to the printer 2 | 3 | // Example taken from: 4 | // https://learn.microsoft.com/windows/win32/printdocs/sending-data-directly-to-a-printer 5 | 6 | import 'dart:ffi'; 7 | import 'dart:typed_data'; 8 | 9 | import 'package:ffi/ffi.dart'; 10 | import 'package:win32/win32.dart'; 11 | 12 | class RawPrinter { 13 | RawPrinter(this.printerName, this.alloc); 14 | final String printerName; 15 | final Arena alloc; 16 | 17 | void printEscPosWin32(List data) { 18 | final hPrinter = calloc(); 19 | final docInfo = calloc(); 20 | 21 | final printerNamePtr = printerName.toNativeUtf16(); 22 | final docNamePtr = 'ESC/POS Print Job'.toNativeUtf16(); 23 | 24 | docInfo.ref.pDocName = docNamePtr; 25 | docInfo.ref.pOutputFile = nullptr; 26 | docInfo.ref.pDatatype = nullptr; 27 | 28 | if (OpenPrinter(printerNamePtr, hPrinter, nullptr) != 0) { 29 | final printerHandle = hPrinter.value; 30 | 31 | if (StartDocPrinter(printerHandle, 1, docInfo.cast()) != 0) { 32 | StartPagePrinter(printerHandle); 33 | 34 | final buffer = Uint8List.fromList(data); 35 | final bytesWritten = calloc(); 36 | 37 | WritePrinter( 38 | printerHandle, 39 | buffer.allocatePointer(), 40 | buffer.length, 41 | bytesWritten, 42 | ); 43 | 44 | EndPagePrinter(printerHandle); 45 | EndDocPrinter(printerHandle); 46 | } 47 | 48 | ClosePrinter(printerHandle); 49 | } 50 | 51 | calloc 52 | ..free(printerNamePtr) 53 | ..free(docNamePtr) 54 | ..free(hPrinter) 55 | ..free(docInfo); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/xml/device_filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 17 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 18 | - platform: android 19 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 20 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 21 | - platform: ios 22 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 23 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 24 | - platform: linux 25 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 26 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 27 | - platform: macos 28 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 29 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 30 | - platform: web 31 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 32 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 33 | - platform: windows 34 | create_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 35 | base_revision: 78666c8dc57e9f7548ca9f8dd0740fbf0c658dc9 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Flutter Thermal Printer 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | flutter_thermal_printer_example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /example/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /lib/Windows/printers_data.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Dart | Windows. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // Enumerates locally-connected printers. 6 | 7 | import 'dart:ffi'; 8 | 9 | import 'package:ffi/ffi.dart'; 10 | import 'package:win32/win32.dart'; 11 | 12 | class PrinterNames { 13 | PrinterNames(this._flags); 14 | final int _flags; 15 | 16 | Iterable all() sync* { 17 | try { 18 | _getBufferSize(); 19 | 20 | try { 21 | _readRawBuff(); 22 | yield* parse(); 23 | } finally { 24 | free(_rawBuffer); 25 | } 26 | } finally { 27 | free(_pBuffSize); 28 | free(_bPrinterLen); 29 | } 30 | } 31 | 32 | late Pointer _pBuffSize; 33 | late Pointer _bPrinterLen; 34 | 35 | void _getBufferSize() { 36 | _pBuffSize = calloc(); 37 | _bPrinterLen = calloc(); 38 | 39 | EnumPrinters(_flags, nullptr, 2, nullptr, 0, _pBuffSize, _bPrinterLen); 40 | 41 | if (_pBuffSize.value == 0) { 42 | throw Exception('Read printer buffer size fail'); 43 | } 44 | } 45 | 46 | late Pointer _rawBuffer; 47 | 48 | void _readRawBuff() { 49 | _rawBuffer = malloc.allocate(_pBuffSize.value); 50 | 51 | final isRawBuffFail = EnumPrinters( 52 | _flags, 53 | nullptr, 54 | 2, 55 | _rawBuffer, 56 | _pBuffSize.value, 57 | _pBuffSize, 58 | _bPrinterLen, 59 | ) == 60 | 0; 61 | 62 | if (isRawBuffFail) { 63 | throw Exception('Read printer raw buffer fail'); 64 | } 65 | } 66 | 67 | Iterable parse() sync* { 68 | for (var i = 0; i < _bPrinterLen.value; i++) { 69 | final printer = _rawBuffer.cast() + i; 70 | yield printer.ref.pPrinterName.toDartString(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "dev.flutter.flutter-gradle-plugin" 4 | } 5 | 6 | def localProperties = new Properties() 7 | def localPropertiesFile = rootProject.file('local.properties') 8 | if (localPropertiesFile.exists()) { 9 | localPropertiesFile.withReader('UTF-8') { reader -> 10 | localProperties.load(reader) 11 | } 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | android { 25 | namespace "com.example.flutter_thermal_printer_example" 26 | compileSdkVersion flutter.compileSdkVersion 27 | ndkVersion flutter.ndkVersion 28 | 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_1_8 31 | targetCompatibility JavaVersion.VERSION_1_8 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.example.flutter_thermal_printer_example" 37 | // You can update the following values to match your application needs. 38 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 39 | minSdkVersion flutter.minSdkVersion 40 | targetSdkVersion flutter.targetSdkVersion 41 | versionCode flutterVersionCode.toInteger() 42 | versionName flutterVersionName 43 | } 44 | 45 | 46 | buildTypes { 47 | release { 48 | // TODO: Add your own signing config for the release build. 49 | // Signing with the debug keys for now, so `flutter run --release` works. 50 | signingConfig signingConfigs.debug 51 | } 52 | } 53 | } 54 | 55 | flutter { 56 | source '../..' 57 | } 58 | -------------------------------------------------------------------------------- /lib/flutter_thermal_printer_platform_interface.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 4 | 5 | import 'flutter_thermal_printer_method_channel.dart'; 6 | import 'utils/printer.dart'; 7 | 8 | abstract class FlutterThermalPrinterPlatform extends PlatformInterface { 9 | FlutterThermalPrinterPlatform() : super(token: _token); 10 | static final Object _token = Object(); 11 | static FlutterThermalPrinterPlatform _instance = 12 | MethodChannelFlutterThermalPrinter(); 13 | static FlutterThermalPrinterPlatform get instance => _instance; 14 | 15 | static set instance(FlutterThermalPrinterPlatform instance) { 16 | PlatformInterface.verifyToken(instance, _token); 17 | _instance = instance; 18 | } 19 | 20 | Future getPlatformVersion() { 21 | throw UnimplementedError('platformVersion() has not been implemented.'); 22 | } 23 | 24 | Future startUsbScan() { 25 | throw UnimplementedError('startScan() has not been implemented.'); 26 | } 27 | 28 | Future connect(Printer device) { 29 | throw UnimplementedError('connect() has not been implemented.'); 30 | } 31 | 32 | Future printText(Printer device, Uint8List data, {String? path}) { 33 | throw UnimplementedError('printText() has not been implemented.'); 34 | } 35 | 36 | Future isConnected(Printer device) { 37 | throw UnimplementedError('isConnected() has not been implemented.'); 38 | } 39 | 40 | Future convertImageToGrayscale(Uint8List? value) { 41 | throw UnimplementedError( 42 | 'convertImageToGrayscale() has not been implemented.', 43 | ); 44 | } 45 | 46 | Future disconnect(Printer device) { 47 | throw UnimplementedError('disconnect() has not been implemented.'); 48 | } 49 | 50 | Future stopScan() { 51 | throw UnimplementedError('stopScan() has not been implemented.'); 52 | } 53 | 54 | Future getPrinters() { 55 | throw UnimplementedError('getPrinters() has not been implemented.'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /example/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length <= 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | example 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /lib/flutter_thermal_printer_method_channel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/services.dart'; 3 | 4 | import 'flutter_thermal_printer_platform_interface.dart'; 5 | import 'utils/printer.dart'; 6 | 7 | /// An implementation of [FlutterThermalPrinterPlatform] that uses method channels. 8 | class MethodChannelFlutterThermalPrinter extends FlutterThermalPrinterPlatform { 9 | /// The method channel used to interact with the native platform. 10 | @visibleForTesting 11 | final methodChannel = const MethodChannel('flutter_thermal_printer'); 12 | 13 | @override 14 | Future getPlatformVersion() async { 15 | final version = 16 | await methodChannel.invokeMethod('getPlatformVersion'); 17 | return version; 18 | } 19 | 20 | @override 21 | Future startUsbScan() async => 22 | methodChannel.invokeMethod('getUsbDevicesList'); 23 | 24 | @override 25 | Future connect(Printer device) async => 26 | await methodChannel.invokeMethod('connect', device.toJson()); 27 | 28 | @override 29 | Future printText( 30 | Printer device, 31 | Uint8List data, { 32 | String? path, 33 | }) async => 34 | await methodChannel.invokeMethod('printText', { 35 | 'vendorId': device.vendorId.toString(), 36 | 'productId': device.productId.toString(), 37 | 'name': device.name, 38 | 'data': List.from(data), 39 | 'path': path ?? '', 40 | }); 41 | 42 | @override 43 | Future isConnected(Printer device) async => 44 | await methodChannel.invokeMethod('isConnected', device.toJson()); 45 | 46 | @override 47 | Future convertImageToGrayscale(Uint8List? value) async => 48 | methodChannel.invokeMethod('convertimage', { 49 | 'path': List.from(value!), 50 | }); 51 | 52 | @override 53 | Future disconnect(Printer device) async => 54 | await methodChannel.invokeMethod('disconnect', { 55 | 'vendorId': device.vendorId.toString(), 56 | 'productId': device.productId.toString(), 57 | }); 58 | } 59 | -------------------------------------------------------------------------------- /windows/flutter_thermal_printer_plugin.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_thermal_printer_plugin.h" 2 | 3 | // This must be included before many other Windows headers. 4 | #include 5 | 6 | // For getPlatformVersion; remove unless needed for your plugin implementation. 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace flutter_thermal_printer { 17 | 18 | // static 19 | void FlutterThermalPrinterPlugin::RegisterWithRegistrar( 20 | flutter::PluginRegistrarWindows *registrar) { 21 | auto channel = 22 | std::make_unique>( 23 | registrar->messenger(), "flutter_thermal_printer", 24 | &flutter::StandardMethodCodec::GetInstance()); 25 | 26 | auto plugin = std::make_unique(); 27 | 28 | channel->SetMethodCallHandler( 29 | [plugin_pointer = plugin.get()](const auto &call, auto result) { 30 | plugin_pointer->HandleMethodCall(call, std::move(result)); 31 | }); 32 | 33 | registrar->AddPlugin(std::move(plugin)); 34 | } 35 | 36 | FlutterThermalPrinterPlugin::FlutterThermalPrinterPlugin() {} 37 | 38 | FlutterThermalPrinterPlugin::~FlutterThermalPrinterPlugin() {} 39 | 40 | void FlutterThermalPrinterPlugin::HandleMethodCall( 41 | const flutter::MethodCall &method_call, 42 | std::unique_ptr> result) { 43 | if (method_call.method_name().compare("getPlatformVersion") == 0) { 44 | std::ostringstream version_stream; 45 | version_stream << "Windows "; 46 | if (IsWindows10OrGreater()) { 47 | version_stream << "10+"; 48 | } else if (IsWindows8OrGreater()) { 49 | version_stream << "8"; 50 | } else if (IsWindows7OrGreater()) { 51 | version_stream << "7"; 52 | } 53 | result->Success(flutter::EncodableValue(version_stream.str())); 54 | } else { 55 | result->NotImplemented(); 56 | } 57 | } 58 | 59 | } // namespace flutter_thermal_printer 60 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureOnOpen": true, 3 | "files.associations": { 4 | "xstring": "cpp", 5 | "algorithm": "cpp", 6 | "any": "cpp", 7 | "array": "cpp", 8 | "atomic": "cpp", 9 | "bit": "cpp", 10 | "cctype": "cpp", 11 | "charconv": "cpp", 12 | "chrono": "cpp", 13 | "clocale": "cpp", 14 | "cmath": "cpp", 15 | "compare": "cpp", 16 | "concepts": "cpp", 17 | "cstddef": "cpp", 18 | "cstdint": "cpp", 19 | "cstdio": "cpp", 20 | "cstdlib": "cpp", 21 | "cstring": "cpp", 22 | "ctime": "cpp", 23 | "cwchar": "cpp", 24 | "deque": "cpp", 25 | "exception": "cpp", 26 | "format": "cpp", 27 | "forward_list": "cpp", 28 | "fstream": "cpp", 29 | "functional": "cpp", 30 | "initializer_list": "cpp", 31 | "iomanip": "cpp", 32 | "ios": "cpp", 33 | "iosfwd": "cpp", 34 | "iostream": "cpp", 35 | "istream": "cpp", 36 | "iterator": "cpp", 37 | "limits": "cpp", 38 | "list": "cpp", 39 | "locale": "cpp", 40 | "map": "cpp", 41 | "memory": "cpp", 42 | "new": "cpp", 43 | "optional": "cpp", 44 | "ostream": "cpp", 45 | "ratio": "cpp", 46 | "set": "cpp", 47 | "sstream": "cpp", 48 | "stdexcept": "cpp", 49 | "streambuf": "cpp", 50 | "string": "cpp", 51 | "system_error": "cpp", 52 | "tuple": "cpp", 53 | "type_traits": "cpp", 54 | "typeinfo": "cpp", 55 | "unordered_map": "cpp", 56 | "unordered_set": "cpp", 57 | "utility": "cpp", 58 | "variant": "cpp", 59 | "vector": "cpp", 60 | "xfacet": "cpp", 61 | "xhash": "cpp", 62 | "xiosbase": "cpp", 63 | "xlocale": "cpp", 64 | "xlocbuf": "cpp", 65 | "xlocinfo": "cpp", 66 | "xlocmes": "cpp", 67 | "xlocmon": "cpp", 68 | "xlocnum": "cpp", 69 | "xloctime": "cpp", 70 | "xmemory": "cpp", 71 | "xtr1common": "cpp", 72 | "xtree": "cpp", 73 | "xutility": "cpp" 74 | }, 75 | } -------------------------------------------------------------------------------- /example/windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/mocks/mock_platform.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:flutter_thermal_printer/flutter_thermal_printer_platform_interface.dart'; 4 | import 'package:flutter_thermal_printer/utils/printer.dart'; 5 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 6 | 7 | class MockFlutterThermalPrinterPlatform extends FlutterThermalPrinterPlatform 8 | with MockPlatformInterfaceMixin { 9 | String? platformVersionToReturn = 'Mock Platform 1.0'; 10 | List>? usbDevicesToReturn; 11 | bool connectResult = true; 12 | bool isConnectedResult = false; 13 | bool disconnectResult = true; 14 | bool printTextResult = true; 15 | dynamic convertImageResult; 16 | 17 | final List methodCalls = []; 18 | final List methodArguments = []; 19 | 20 | void reset() { 21 | methodCalls.clear(); 22 | methodArguments.clear(); 23 | platformVersionToReturn = 'Mock Platform 1.0'; 24 | usbDevicesToReturn = null; 25 | connectResult = true; 26 | isConnectedResult = false; 27 | disconnectResult = true; 28 | printTextResult = true; 29 | convertImageResult = null; 30 | } 31 | 32 | @override 33 | Future getPlatformVersion() async { 34 | methodCalls.add('getPlatformVersion'); 35 | return platformVersionToReturn; 36 | } 37 | 38 | @override 39 | Future startUsbScan() async { 40 | methodCalls.add('startUsbScan'); 41 | return usbDevicesToReturn ?? []; 42 | } 43 | 44 | @override 45 | Future connect(Printer device) async { 46 | methodCalls.add('connect'); 47 | methodArguments.add(device); 48 | return connectResult; 49 | } 50 | 51 | @override 52 | Future isConnected(Printer device) async { 53 | methodCalls.add('isConnected'); 54 | methodArguments.add(device); 55 | return isConnectedResult; 56 | } 57 | 58 | @override 59 | Future disconnect(Printer device) async { 60 | methodCalls.add('disconnect'); 61 | methodArguments.add(device); 62 | return disconnectResult; 63 | } 64 | 65 | @override 66 | Future printText(Printer device, Uint8List data, {String? path}) async { 67 | methodCalls.add('printText'); 68 | methodArguments.add({'device': device, 'data': data, 'path': path}); 69 | } 70 | 71 | @override 72 | Future convertImageToGrayscale(Uint8List? value) async { 73 | methodCalls.add('convertImageToGrayscale'); 74 | methodArguments.add(value); 75 | return convertImageResult ?? value; 76 | } 77 | 78 | @override 79 | Future stopScan() async { 80 | methodCalls.add('stopScan'); 81 | } 82 | 83 | @override 84 | Future getPrinters() async { 85 | methodCalls.add('getPrinters'); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/network/network_printer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'network_print_result.dart'; 3 | 4 | /// Optimized network thermal printer with improved connection management 5 | class FlutterThermalPrinterNetwork { 6 | FlutterThermalPrinterNetwork( 7 | String host, { 8 | int port = 9100, 9 | Duration timeout = const Duration(seconds: 5), 10 | }) : _host = host, 11 | _port = port, 12 | _timeout = timeout; 13 | final String _host; 14 | final int _port; 15 | final Duration _timeout; 16 | 17 | bool _isConnected = false; 18 | Socket? _socket; 19 | 20 | /// Connect to network printer with improved error handling 21 | Future connect({ 22 | Duration? timeout, 23 | }) async { 24 | if (_isConnected && _socket != null) { 25 | return NetworkPrintResult.success; 26 | } 27 | 28 | try { 29 | _socket = await Socket.connect( 30 | _host, 31 | _port, 32 | timeout: timeout ?? _timeout, 33 | ); 34 | _isConnected = true; 35 | return NetworkPrintResult.success; 36 | } on SocketException { 37 | _isConnected = false; 38 | return NetworkPrintResult.timeout; 39 | } catch (e) { 40 | _isConnected = false; 41 | return NetworkPrintResult.timeout; 42 | } 43 | } 44 | 45 | /// Print data with automatic connection management 46 | Future printTicket( 47 | List data, { 48 | bool isDisconnect = true, 49 | }) async { 50 | try { 51 | if (!_isConnected || _socket == null) { 52 | final connectResult = await connect(); 53 | if (connectResult != NetworkPrintResult.success) { 54 | return connectResult; 55 | } 56 | } 57 | 58 | _socket!.add(data); 59 | await _socket!.flush(); 60 | 61 | if (isDisconnect) { 62 | await disconnect(); 63 | } 64 | 65 | return NetworkPrintResult.success; 66 | } on SocketException { 67 | _isConnected = false; 68 | return NetworkPrintResult.timeout; 69 | } catch (e) { 70 | return NetworkPrintResult.timeout; 71 | } 72 | } 73 | 74 | /// Disconnect with proper resource cleanup 75 | Future disconnect({Duration? timeout}) async { 76 | try { 77 | if (_socket != null) { 78 | await _socket!.flush(); 79 | await _socket!.close(); 80 | _socket = null; 81 | } 82 | _isConnected = false; 83 | 84 | if (timeout != null) { 85 | await Future.delayed(timeout); 86 | } 87 | 88 | return NetworkPrintResult.success; 89 | } catch (e) { 90 | _isConnected = false; 91 | _socket = null; 92 | return NetworkPrintResult.success; // Still consider it successful cleanup 93 | } 94 | } 95 | 96 | /// Check if currently connected 97 | bool get isConnected => _isConnected && _socket != null; 98 | 99 | /// Get connection info 100 | String get connectionInfo => '$_host:$_port'; 101 | } 102 | -------------------------------------------------------------------------------- /test/unit/network_print_result_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:flutter_thermal_printer/network/network_print_result.dart'; 3 | 4 | void main() { 5 | group('NetworkPrintResult', () { 6 | group('static constants', () { 7 | test('success has value 1', () { 8 | expect(NetworkPrintResult.success.value, 1); 9 | }); 10 | 11 | test('timeout has value 2', () { 12 | expect(NetworkPrintResult.timeout.value, 2); 13 | }); 14 | 15 | test('printerConnected has value 3', () { 16 | expect(NetworkPrintResult.printerConnected.value, 3); 17 | }); 18 | 19 | test('ticketEmpty has value 4', () { 20 | expect(NetworkPrintResult.ticketEmpty.value, 4); 21 | }); 22 | 23 | test('printInProgress has value 5', () { 24 | expect(NetworkPrintResult.printInProgress.value, 5); 25 | }); 26 | 27 | test('scanInProgress has value 6', () { 28 | expect(NetworkPrintResult.scanInProgress.value, 6); 29 | }); 30 | }); 31 | 32 | group('msg getter', () { 33 | test('success returns Success', () { 34 | expect(NetworkPrintResult.success.msg, 'Success'); 35 | }); 36 | 37 | test('timeout returns connection timeout message', () { 38 | expect( 39 | NetworkPrintResult.timeout.msg, 40 | 'Error. Printer connection timeout', 41 | ); 42 | }); 43 | 44 | test('printerConnected returns not connected message', () { 45 | expect( 46 | NetworkPrintResult.printerConnected.msg, 47 | 'Error. Printer not connected', 48 | ); 49 | }); 50 | 51 | test('ticketEmpty returns empty ticket message', () { 52 | expect(NetworkPrintResult.ticketEmpty.msg, 'Error. Ticket is empty'); 53 | }); 54 | 55 | test('printInProgress returns print in progress message', () { 56 | expect( 57 | NetworkPrintResult.printInProgress.msg, 58 | 'Error. Another print in progress', 59 | ); 60 | }); 61 | 62 | test('scanInProgress returns scan in progress message', () { 63 | expect( 64 | NetworkPrintResult.scanInProgress.msg, 65 | 'Error. Printer scanning in progress', 66 | ); 67 | }); 68 | }); 69 | 70 | group('equality', () { 71 | test('same constant instances are equal', () { 72 | expect(NetworkPrintResult.success, NetworkPrintResult.success); 73 | expect(NetworkPrintResult.timeout, NetworkPrintResult.timeout); 74 | }); 75 | 76 | test('different constants are not equal', () { 77 | expect( 78 | NetworkPrintResult.success == NetworkPrintResult.timeout, 79 | false, 80 | ); 81 | }); 82 | }); 83 | 84 | group('value comparison', () { 85 | test('can compare by value', () { 86 | expect( 87 | NetworkPrintResult.success.value == 1, 88 | true, 89 | ); 90 | expect( 91 | NetworkPrintResult.timeout.value == 2, 92 | true, 93 | ); 94 | }); 95 | }); 96 | }); 97 | } 98 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_thermal_printer 2 | description: "Plugin for Flutter to print on thermal printers via ESC/POS commands." 3 | version: 2.0.0 4 | homepage: "https://sunilflutter.in/" 5 | repository: "https://github.com/SunilDevX/flutter_thermal_printer" 6 | 7 | environment: 8 | sdk: ">=3.2.3 <4.0.0" 9 | flutter: ">=3.3.0" 10 | 11 | dependencies: 12 | esc_pos_utils_plus: ^2.0.4 13 | ffi: ^2.1.4 14 | flutter: 15 | sdk: flutter 16 | image: ^4.7.1 17 | plugin_platform_interface: ^2.1.8 18 | screenshot: ^3.0.0 19 | universal_ble: ^1.0.0 20 | win32: ^5.15.0 21 | 22 | dev_dependencies: 23 | flutter_lints: ^6.0.0 24 | flutter_test: 25 | sdk: flutter 26 | 27 | # For information on the generic Dart part of this file, see the 28 | # following page: https://dart.dev/tools/pub/pubspec 29 | # The following section is specific to Flutter packages. 30 | flutter: 31 | # This section identifies this Flutter project as a plugin project. 32 | # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) 33 | # which should be registered in the plugin registry. This is required for 34 | # using method channels. 35 | # The Android 'package' specifies package in which the registered class is. 36 | # This is required for using method channels on Android. 37 | # The 'ffiPlugin' specifies that native code should be built and bundled. 38 | # This is required for using `dart:ffi`. 39 | # All these are used by the tooling to maintain consistency when 40 | # adding or updating assets for this project. 41 | plugin: 42 | platforms: 43 | android: 44 | package: com.example.flutter_thermal_printer 45 | pluginClass: FlutterThermalPrinterPlugin 46 | ios: 47 | pluginClass: FlutterThermalPrinterPlugin 48 | macos: 49 | pluginClass: FlutterThermalPrinterPlugin 50 | windows: 51 | pluginClass: FlutterThermalPrinterPluginCApi 52 | # To add assets to your plugin package, add an assets section, like this: 53 | # assets: 54 | # - assets/image.png 55 | # - images/a_dot_ham.jpeg 56 | # 57 | # For details regarding assets in packages, see 58 | # https://flutter.dev/assets-and-images/#from-packages 59 | # 60 | # An image asset can refer to one or more resolution-specific "variants", see 61 | # https://flutter.dev/assets-and-images/#resolution-aware 62 | # To add custom fonts to your plugin package, add a fonts section here, 63 | # in this "flutter" section. Each entry in this list should have a 64 | # "family" key with the font family name, and a "fonts" key with a 65 | # list giving the asset and other descriptors for the font. For 66 | # example: 67 | # fonts: 68 | # - family: Schyler 69 | # fonts: 70 | # - asset: fonts/Schyler-Regular.ttf 71 | # - asset: fonts/Schyler-Italic.ttf 72 | # style: italic 73 | # - family: Trajan Pro 74 | # fonts: 75 | # - asset: fonts/TrajanPro.ttf 76 | # - asset: fonts/TrajanPro_Bold.ttf 77 | # weight: 700 78 | # 79 | # For details regarding fonts in packages, see 80 | # https://flutter.dev/custom-fonts/#from-packages 81 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /example/linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | 12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 13 | # which isn't available in 3.10. 14 | function(list_prepend LIST_NAME PREFIX) 15 | set(NEW_LIST "") 16 | foreach(element ${${LIST_NAME}}) 17 | list(APPEND NEW_LIST "${PREFIX}${element}") 18 | endforeach(element) 19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 20 | endfunction() 21 | 22 | # === Flutter Library === 23 | # System-level dependencies. 24 | find_package(PkgConfig REQUIRED) 25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 28 | 29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 30 | 31 | # Published to parent scope for install step. 32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 36 | 37 | list(APPEND FLUTTER_LIBRARY_HEADERS 38 | "fl_basic_message_channel.h" 39 | "fl_binary_codec.h" 40 | "fl_binary_messenger.h" 41 | "fl_dart_project.h" 42 | "fl_engine.h" 43 | "fl_json_message_codec.h" 44 | "fl_json_method_codec.h" 45 | "fl_message_codec.h" 46 | "fl_method_call.h" 47 | "fl_method_channel.h" 48 | "fl_method_codec.h" 49 | "fl_method_response.h" 50 | "fl_plugin_registrar.h" 51 | "fl_plugin_registry.h" 52 | "fl_standard_message_codec.h" 53 | "fl_standard_method_codec.h" 54 | "fl_string_codec.h" 55 | "fl_value.h" 56 | "fl_view.h" 57 | "flutter_linux.h" 58 | ) 59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 60 | add_library(flutter INTERFACE) 61 | target_include_directories(flutter INTERFACE 62 | "${EPHEMERAL_DIR}" 63 | ) 64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 65 | target_link_libraries(flutter INTERFACE 66 | PkgConfig::GTK 67 | PkgConfig::GLIB 68 | PkgConfig::GIO 69 | ) 70 | add_dependencies(flutter flutter_assemble) 71 | 72 | # === Flutter tool backend === 73 | # _phony_ is a non-existent file to force this command to run every time, 74 | # since currently there's no way to get a full input/output list from the 75 | # flutter tool. 76 | add_custom_command( 77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 79 | COMMAND ${CMAKE_COMMAND} -E env 80 | ${FLUTTER_TOOL_ENVIRONMENT} 81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} 83 | VERBATIM 84 | ) 85 | add_custom_target(flutter_assemble DEPENDS 86 | "${FLUTTER_LIBRARY}" 87 | ${FLUTTER_LIBRARY_HEADERS} 88 | ) 89 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 30 | 34 | 35 | 36 | 37 | 38 | 40 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /test/flutter_thermal_printer_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:flutter_test/flutter_test.dart'; 4 | import 'package:flutter_thermal_printer/flutter_thermal_printer.dart'; 5 | import 'package:flutter_thermal_printer/flutter_thermal_printer_method_channel.dart'; 6 | import 'package:flutter_thermal_printer/flutter_thermal_printer_platform_interface.dart'; 7 | import 'package:flutter_thermal_printer/utils/printer.dart'; 8 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 9 | 10 | class MockFlutterThermalPrinterPlatform 11 | with MockPlatformInterfaceMixin 12 | implements FlutterThermalPrinterPlatform { 13 | @override 14 | Future getPlatformVersion() async => '42'; 15 | 16 | @override 17 | Future startUsbScan() async => []; 18 | 19 | @override 20 | Future connect(Printer device) async => true; 21 | 22 | @override 23 | Future printText( 24 | Printer device, 25 | Uint8List data, { 26 | String? path, 27 | }) async {} 28 | 29 | @override 30 | Future isConnected(Printer device) async => false; 31 | 32 | @override 33 | Future convertImageToGrayscale(Uint8List? value) async => value; 34 | 35 | @override 36 | Future disconnect(Printer device) async => true; 37 | 38 | @override 39 | Future stopScan() async {} 40 | 41 | @override 42 | Future getPrinters() async {} 43 | } 44 | 45 | void main() { 46 | final initialPlatform = FlutterThermalPrinterPlatform.instance; 47 | 48 | group('FlutterThermalPrinterPlatform', () { 49 | test('MethodChannelFlutterThermalPrinter is the default instance', () { 50 | expect( 51 | initialPlatform, 52 | isInstanceOf(), 53 | ); 54 | }); 55 | }); 56 | 57 | group('FlutterThermalPrinter', () { 58 | test('instance returns singleton', () { 59 | final instance1 = FlutterThermalPrinter.instance; 60 | final instance2 = FlutterThermalPrinter.instance; 61 | 62 | expect(identical(instance1, instance2), true); 63 | }); 64 | 65 | test('instance is FlutterThermalPrinter type', () { 66 | expect( 67 | FlutterThermalPrinter.instance, 68 | isA(), 69 | ); 70 | }); 71 | 72 | test('devicesStream is available', () { 73 | expect( 74 | FlutterThermalPrinter.instance.devicesStream, 75 | isA>>(), 76 | ); 77 | }); 78 | 79 | test('isBleTurnedOnStream is available', () { 80 | expect( 81 | FlutterThermalPrinter.instance.isBleTurnedOnStream, 82 | isA>(), 83 | ); 84 | }); 85 | }); 86 | 87 | group('Exports', () { 88 | test('ConnectionType is exported', () { 89 | expect(ConnectionType.BLE, isNotNull); 90 | expect(ConnectionType.USB, isNotNull); 91 | expect(ConnectionType.NETWORK, isNotNull); 92 | }); 93 | 94 | test('Printer is exported', () { 95 | final printer = Printer(name: 'Test'); 96 | expect(printer, isA()); 97 | }); 98 | 99 | test('FlutterThermalPrinterNetwork is exported', () { 100 | final network = FlutterThermalPrinterNetwork('192.168.1.1'); 101 | expect(network, isA()); 102 | }); 103 | }); 104 | } 105 | -------------------------------------------------------------------------------- /android/src/main/java/com/example/flutter_thermal_printer/FlutterThermalPrinterPlugin.java: -------------------------------------------------------------------------------- 1 | package com.example.flutter_thermal_printer; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.annotation.NonNull; 6 | 7 | import java.util.List; 8 | 9 | import io.flutter.embedding.engine.plugins.FlutterPlugin; 10 | import io.flutter.plugin.common.MethodCall; 11 | import io.flutter.plugin.common.MethodChannel; 12 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 13 | import io.flutter.plugin.common.MethodChannel.Result; 14 | import io.flutter.plugin.common.EventChannel; 15 | 16 | /** FlutterThermalPrinterPlugin */ 17 | public class FlutterThermalPrinterPlugin implements FlutterPlugin, MethodCallHandler { 18 | /// The MethodChannel that will the communication between Flutter and native Android 19 | /// 20 | /// This local reference serves to register the plugin with the Flutter Engine and unregister it 21 | /// when the Flutter Engine is detached from the Activity 22 | private MethodChannel channel; 23 | private EventChannel eventChannel; 24 | private Context context; 25 | private UsbPrinter usbPrinter; 26 | 27 | @Override 28 | public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { 29 | channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_thermal_printer"); 30 | eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_thermal_printer/events"); 31 | channel.setMethodCallHandler(this); 32 | context = flutterPluginBinding.getApplicationContext(); 33 | usbPrinter = new UsbPrinter(context); 34 | eventChannel.setStreamHandler(usbPrinter); 35 | } 36 | 37 | @Override 38 | public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { 39 | switch (call.method) { 40 | case "getPlatformVersion": 41 | result.success("Android " + android.os.Build.VERSION.RELEASE); 42 | break; 43 | case "getUsbDevicesList": 44 | result.success(usbPrinter.getUsbDevicesList()); 45 | break; 46 | case "connect": { 47 | String vendorId = call.argument("vendorId"); 48 | String productId = call.argument("productId"); 49 | usbPrinter.connect(vendorId, productId); 50 | result.success(false ); 51 | break; 52 | } 53 | case "disconnect": { 54 | String vendorId = call.argument("vendorId"); 55 | String productId = call.argument("productId"); 56 | result.success(usbPrinter.disconnect(vendorId, productId)); 57 | break; 58 | } 59 | case "printText": { 60 | String vendorId = call.argument("vendorId"); 61 | String productId = call.argument("productId"); 62 | List data = call.argument("data"); 63 | usbPrinter.printText(vendorId, productId, data); 64 | result.success(true); 65 | break; 66 | } 67 | case "isConnected": { 68 | String vendorId = call.argument("vendorId"); 69 | String productId = call.argument("productId"); 70 | result.success(usbPrinter.isConnected(vendorId, productId)); 71 | break; 72 | } 73 | default: 74 | result.notImplemented(); 75 | break; 76 | } 77 | } 78 | 79 | @Override 80 | public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { 81 | channel.setMethodCallHandler(null); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_thermal_printer_example 2 | description: "Demonstrates how to use the flutter_thermal_printer plugin." 3 | # The following line prevents the package from being accidentally published to 4 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 5 | publish_to: "none" # Remove this line if you wish to publish to pub.dev 6 | 7 | environment: 8 | sdk: ">=3.2.3 <4.0.0" 9 | 10 | # Dependencies specify other packages that your package needs in order to work. 11 | # To automatically upgrade your package dependencies to the latest versions 12 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 13 | # dependencies can be manually updated by changing the version numbers below to 14 | # the latest version available on pub.dev. To see which dependencies have newer 15 | # versions available, run `flutter pub outdated`. 16 | dependencies: 17 | flutter: 18 | sdk: flutter 19 | 20 | flutter_thermal_printer: 21 | # When depending on this package from a real application you should use: 22 | # flutter_thermal_printer: ^x.y.z 23 | # See https://dart.dev/tools/pub/dependencies#version-constraints 24 | # The example app is bundled with the plugin so we use a path dependency on 25 | # the parent directory to use the current plugin's version. 26 | path: ../ 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.2 31 | 32 | dev_dependencies: 33 | integration_test: 34 | sdk: flutter 35 | flutter_test: 36 | sdk: flutter 37 | 38 | # The "flutter_lints" package below contains a set of recommended lints to 39 | # encourage good coding practices. The lint set provided by the package is 40 | # activated in the `analysis_options.yaml` file located at the root of your 41 | # package. See that file for information about deactivating specific lint 42 | # rules and activating additional ones. 43 | flutter_lints: ^2.0.0 44 | 45 | # For information on the generic Dart part of this file, see the 46 | # following page: https://dart.dev/tools/pub/pubspec 47 | 48 | # The following section is specific to Flutter packages. 49 | flutter: 50 | # The following line ensures that the Material Icons font is 51 | # included with your application, so that you can use the icons in 52 | # the material Icons class. 53 | uses-material-design: true 54 | 55 | # To add assets to your application, add an assets section, like this: 56 | # assets: 57 | # - assets/ 58 | # - images/a_dot_ham.jpeg 59 | 60 | # An image asset can refer to one or more resolution-specific "variants", see 61 | # https://flutter.dev/assets-and-images/#resolution-aware 62 | 63 | # For details regarding adding assets from package dependencies, see 64 | # https://flutter.dev/assets-and-images/#from-packages 65 | 66 | # To add custom fonts to your application, add a fonts section here, 67 | # in this "flutter" section. Each entry in this list should have a 68 | # "family" key with the font family name, and a "fonts" key with a 69 | # list giving the asset and other descriptors for the font. For 70 | # example: 71 | # fonts: 72 | # - family: Schyler 73 | # fonts: 74 | # - asset: fonts/Schyler-Regular.ttf 75 | # - asset: fonts/Schyler-Italic.ttf 76 | # style: italic 77 | # - family: Trajan Pro 78 | # fonts: 79 | # - asset: fonts/TrajanPro.ttf 80 | # - asset: fonts/TrajanPro_Bold.ttf 81 | # weight: 700 82 | # 83 | # For details regarding fonts from package dependencies, 84 | # see https://flutter.dev/custom-fonts/#from-packages 85 | -------------------------------------------------------------------------------- /example/windows/runner/Runner.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | #include "resource.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "winres.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (United States) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_APP_ICON ICON "resources\\app_icon.ico" 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) 64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0,0 67 | #endif 68 | 69 | #if defined(FLUTTER_VERSION) 70 | #define VERSION_AS_STRING FLUTTER_VERSION 71 | #else 72 | #define VERSION_AS_STRING "1.0.0" 73 | #endif 74 | 75 | VS_VERSION_INFO VERSIONINFO 76 | FILEVERSION VERSION_AS_NUMBER 77 | PRODUCTVERSION VERSION_AS_NUMBER 78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 79 | #ifdef _DEBUG 80 | FILEFLAGS VS_FF_DEBUG 81 | #else 82 | FILEFLAGS 0x0L 83 | #endif 84 | FILEOS VOS__WINDOWS32 85 | FILETYPE VFT_APP 86 | FILESUBTYPE 0x0L 87 | BEGIN 88 | BLOCK "StringFileInfo" 89 | BEGIN 90 | BLOCK "040904e4" 91 | BEGIN 92 | VALUE "CompanyName", "com.example" "\0" 93 | VALUE "FileDescription", "flutter_thermal_printer_example" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "flutter_thermal_printer_example" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "flutter_thermal_printer_example.exe" "\0" 98 | VALUE "ProductName", "flutter_thermal_printer_example" "\0" 99 | VALUE "ProductVersion", VERSION_AS_STRING "\0" 100 | END 101 | END 102 | BLOCK "VarFileInfo" 103 | BEGIN 104 | VALUE "Translation", 0x409, 1252 105 | END 106 | END 107 | 108 | #endif // English (United States) resources 109 | ///////////////////////////////////////////////////////////////////////////// 110 | 111 | 112 | 113 | #ifndef APSTUDIO_INVOKED 114 | ///////////////////////////////////////////////////////////////////////////// 115 | // 116 | // Generated from the TEXTINCLUDE 3 resource. 117 | // 118 | 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | -------------------------------------------------------------------------------- /example/windows/runner/win32_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_WIN32_WINDOW_H_ 2 | #define RUNNER_WIN32_WINDOW_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be 11 | // inherited from by classes that wish to specialize with custom 12 | // rendering and input handling 13 | class Win32Window { 14 | public: 15 | struct Point { 16 | unsigned int x; 17 | unsigned int y; 18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {} 19 | }; 20 | 21 | struct Size { 22 | unsigned int width; 23 | unsigned int height; 24 | Size(unsigned int width, unsigned int height) 25 | : width(width), height(height) {} 26 | }; 27 | 28 | Win32Window(); 29 | virtual ~Win32Window(); 30 | 31 | // Creates a win32 window with |title| that is positioned and sized using 32 | // |origin| and |size|. New windows are created on the default monitor. Window 33 | // sizes are specified to the OS in physical pixels, hence to ensure a 34 | // consistent size this function will scale the inputted width and height as 35 | // as appropriate for the default monitor. The window is invisible until 36 | // |Show| is called. Returns true if the window was created successfully. 37 | bool Create(const std::wstring& title, const Point& origin, const Size& size); 38 | 39 | // Show the current window. Returns true if the window was successfully shown. 40 | bool Show(); 41 | 42 | // Release OS resources associated with window. 43 | void Destroy(); 44 | 45 | // Inserts |content| into the window tree. 46 | void SetChildContent(HWND content); 47 | 48 | // Returns the backing Window handle to enable clients to set icon and other 49 | // window properties. Returns nullptr if the window has been destroyed. 50 | HWND GetHandle(); 51 | 52 | // If true, closing this window will quit the application. 53 | void SetQuitOnClose(bool quit_on_close); 54 | 55 | // Return a RECT representing the bounds of the current client area. 56 | RECT GetClientArea(); 57 | 58 | protected: 59 | // Processes and route salient window messages for mouse handling, 60 | // size change and DPI. Delegates handling of these to member overloads that 61 | // inheriting classes can handle. 62 | virtual LRESULT MessageHandler(HWND window, 63 | UINT const message, 64 | WPARAM const wparam, 65 | LPARAM const lparam) noexcept; 66 | 67 | // Called when CreateAndShow is called, allowing subclass window-related 68 | // setup. Subclasses should return false if setup fails. 69 | virtual bool OnCreate(); 70 | 71 | // Called when Destroy is called. 72 | virtual void OnDestroy(); 73 | 74 | private: 75 | friend class WindowClassRegistrar; 76 | 77 | // OS callback called by message pump. Handles the WM_NCCREATE message which 78 | // is passed when the non-client area is being created and enables automatic 79 | // non-client DPI scaling so that the non-client area automatically 80 | // responds to changes in DPI. All other messages are handled by 81 | // MessageHandler. 82 | static LRESULT CALLBACK WndProc(HWND const window, 83 | UINT const message, 84 | WPARAM const wparam, 85 | LPARAM const lparam) noexcept; 86 | 87 | // Retrieves a class instance pointer for |window| 88 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 89 | 90 | // Update the window frame's theme to match the system theme. 91 | static void UpdateTheme(HWND const window); 92 | 93 | bool quit_on_close_ = false; 94 | 95 | // window handle for top level window. 96 | HWND window_handle_ = nullptr; 97 | 98 | // window handle for hosted content. 99 | HWND child_content_ = nullptr; 100 | }; 101 | 102 | #endif // RUNNER_WIN32_WINDOW_H_ 103 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 64 | 66 | 72 | 73 | 74 | 75 | 81 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /example/linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen* screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "example"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } else { 47 | gtk_window_set_title(window, "example"); 48 | } 49 | 50 | gtk_window_set_default_size(window, 1280, 720); 51 | gtk_widget_show(GTK_WIDGET(window)); 52 | 53 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 55 | 56 | FlView* view = fl_view_new(project); 57 | gtk_widget_show(GTK_WIDGET(view)); 58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 59 | 60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 61 | 62 | gtk_widget_grab_focus(GTK_WIDGET(view)); 63 | } 64 | 65 | // Implements GApplication::local_command_line. 66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { 67 | MyApplication* self = MY_APPLICATION(application); 68 | // Strip out the first argument as it is the binary name. 69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 70 | 71 | g_autoptr(GError) error = nullptr; 72 | if (!g_application_register(application, nullptr, &error)) { 73 | g_warning("Failed to register: %s", error->message); 74 | *exit_status = 1; 75 | return TRUE; 76 | } 77 | 78 | g_application_activate(application); 79 | *exit_status = 0; 80 | 81 | return TRUE; 82 | } 83 | 84 | // Implements GObject::dispose. 85 | static void my_application_dispose(GObject* object) { 86 | MyApplication* self = MY_APPLICATION(object); 87 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 88 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 89 | } 90 | 91 | static void my_application_class_init(MyApplicationClass* klass) { 92 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 93 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 94 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 95 | } 96 | 97 | static void my_application_init(MyApplication* self) {} 98 | 99 | MyApplication* my_application_new() { 100 | return MY_APPLICATION(g_object_new(my_application_get_type(), 101 | "application-id", APPLICATION_ID, 102 | "flags", G_APPLICATION_NON_UNIQUE, 103 | nullptr)); 104 | } 105 | -------------------------------------------------------------------------------- /example/windows/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.14) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 12 | 13 | # Set fallback configurations for older versions of the flutter tool. 14 | if (NOT DEFINED FLUTTER_TARGET_PLATFORM) 15 | set(FLUTTER_TARGET_PLATFORM "windows-x64") 16 | endif() 17 | 18 | # === Flutter Library === 19 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") 20 | 21 | # Published to parent scope for install step. 22 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 23 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 24 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 25 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) 26 | 27 | list(APPEND FLUTTER_LIBRARY_HEADERS 28 | "flutter_export.h" 29 | "flutter_windows.h" 30 | "flutter_messenger.h" 31 | "flutter_plugin_registrar.h" 32 | "flutter_texture_registrar.h" 33 | ) 34 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 35 | add_library(flutter INTERFACE) 36 | target_include_directories(flutter INTERFACE 37 | "${EPHEMERAL_DIR}" 38 | ) 39 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 40 | add_dependencies(flutter flutter_assemble) 41 | 42 | # === Wrapper === 43 | list(APPEND CPP_WRAPPER_SOURCES_CORE 44 | "core_implementations.cc" 45 | "standard_codec.cc" 46 | ) 47 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 48 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 49 | "plugin_registrar.cc" 50 | ) 51 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 52 | list(APPEND CPP_WRAPPER_SOURCES_APP 53 | "flutter_engine.cc" 54 | "flutter_view_controller.cc" 55 | ) 56 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 57 | 58 | # Wrapper sources needed for a plugin. 59 | add_library(flutter_wrapper_plugin STATIC 60 | ${CPP_WRAPPER_SOURCES_CORE} 61 | ${CPP_WRAPPER_SOURCES_PLUGIN} 62 | ) 63 | apply_standard_settings(flutter_wrapper_plugin) 64 | set_target_properties(flutter_wrapper_plugin PROPERTIES 65 | POSITION_INDEPENDENT_CODE ON) 66 | set_target_properties(flutter_wrapper_plugin PROPERTIES 67 | CXX_VISIBILITY_PRESET hidden) 68 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 69 | target_include_directories(flutter_wrapper_plugin PUBLIC 70 | "${WRAPPER_ROOT}/include" 71 | ) 72 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 73 | 74 | # Wrapper sources needed for the runner. 75 | add_library(flutter_wrapper_app STATIC 76 | ${CPP_WRAPPER_SOURCES_CORE} 77 | ${CPP_WRAPPER_SOURCES_APP} 78 | ) 79 | apply_standard_settings(flutter_wrapper_app) 80 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 81 | target_include_directories(flutter_wrapper_app PUBLIC 82 | "${WRAPPER_ROOT}/include" 83 | ) 84 | add_dependencies(flutter_wrapper_app flutter_assemble) 85 | 86 | # === Flutter tool backend === 87 | # _phony_ is a non-existent file to force this command to run every time, 88 | # since currently there's no way to get a full input/output list from the 89 | # flutter tool. 90 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") 91 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) 92 | add_custom_command( 93 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 94 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} 95 | ${CPP_WRAPPER_SOURCES_APP} 96 | ${PHONY_OUTPUT} 97 | COMMAND ${CMAKE_COMMAND} -E env 98 | ${FLUTTER_TOOL_ENVIRONMENT} 99 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" 100 | ${FLUTTER_TARGET_PLATFORM} $ 101 | VERBATIM 102 | ) 103 | add_custom_target(flutter_assemble DEPENDS 104 | "${FLUTTER_LIBRARY}" 105 | ${FLUTTER_LIBRARY_HEADERS} 106 | ${CPP_WRAPPER_SOURCES_CORE} 107 | ${CPP_WRAPPER_SOURCES_PLUGIN} 108 | ${CPP_WRAPPER_SOURCES_APP} 109 | ) 110 | -------------------------------------------------------------------------------- /windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have a version of Visual Studio 2 | # installed that includes CMake 3.14 or later. You should not increase this 3 | # version, as doing so will cause the plugin to fail to compile for some 4 | # customers of the plugin. 5 | cmake_minimum_required(VERSION 3.14) 6 | 7 | # Project-level configuration. 8 | set(PROJECT_NAME "flutter_thermal_printer") 9 | project(${PROJECT_NAME} LANGUAGES CXX) 10 | 11 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 12 | # versions of CMake. 13 | cmake_policy(VERSION 3.14...3.25) 14 | 15 | # This value is used when generating builds using this plugin, so it must 16 | # not be changed 17 | set(PLUGIN_NAME "flutter_thermal_printer_plugin") 18 | 19 | # Any new source files that you add to the plugin should be added here. 20 | list(APPEND PLUGIN_SOURCES 21 | "flutter_thermal_printer_plugin.cpp" 22 | "flutter_thermal_printer_plugin.h" 23 | ) 24 | 25 | # Define the plugin library target. Its name must not be changed (see comment 26 | # on PLUGIN_NAME above). 27 | add_library(${PLUGIN_NAME} SHARED 28 | "include/flutter_thermal_printer/flutter_thermal_printer_plugin_c_api.h" 29 | "flutter_thermal_printer_plugin_c_api.cpp" 30 | ${PLUGIN_SOURCES} 31 | ) 32 | 33 | # Apply a standard set of build settings that are configured in the 34 | # application-level CMakeLists.txt. This can be removed for plugins that want 35 | # full control over build settings. 36 | apply_standard_settings(${PLUGIN_NAME}) 37 | 38 | # Symbols are hidden by default to reduce the chance of accidental conflicts 39 | # between plugins. This should not be removed; any symbols that should be 40 | # exported should be explicitly exported with the FLUTTER_PLUGIN_EXPORT macro. 41 | set_target_properties(${PLUGIN_NAME} PROPERTIES 42 | CXX_VISIBILITY_PRESET hidden) 43 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 44 | 45 | # Source include directories and library dependencies. Add any plugin-specific 46 | # dependencies here. 47 | target_include_directories(${PLUGIN_NAME} INTERFACE 48 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 49 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) 50 | 51 | # List of absolute paths to libraries that should be bundled with the plugin. 52 | # This list could contain prebuilt libraries, or libraries created by an 53 | # external build triggered from this build file. 54 | set(flutter_thermal_printer_bundled_libraries 55 | "" 56 | PARENT_SCOPE 57 | ) 58 | 59 | # === Tests === 60 | # These unit tests can be run from a terminal after building the example, or 61 | # from Visual Studio after opening the generated solution file. 62 | 63 | # Only enable test builds when building the example (which sets this variable) 64 | # so that plugin clients aren't building the tests. 65 | if (${include_${PROJECT_NAME}_tests}) 66 | set(TEST_RUNNER "${PROJECT_NAME}_test") 67 | enable_testing() 68 | 69 | # Add the Google Test dependency. 70 | include(FetchContent) 71 | FetchContent_Declare( 72 | googletest 73 | URL https://github.com/google/googletest/archive/release-1.11.0.zip 74 | ) 75 | # Prevent overriding the parent project's compiler/linker settings 76 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 77 | # Disable install commands for gtest so it doesn't end up in the bundle. 78 | set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE) 79 | FetchContent_MakeAvailable(googletest) 80 | 81 | # The plugin's C API is not very useful for unit testing, so build the sources 82 | # directly into the test binary rather than using the DLL. 83 | add_executable(${TEST_RUNNER} 84 | test/flutter_thermal_printer_plugin_test.cpp 85 | ${PLUGIN_SOURCES} 86 | ) 87 | apply_standard_settings(${TEST_RUNNER}) 88 | target_include_directories(${TEST_RUNNER} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") 89 | target_link_libraries(${TEST_RUNNER} PRIVATE flutter_wrapper_plugin) 90 | target_link_libraries(${TEST_RUNNER} PRIVATE gtest_main gmock) 91 | # flutter_wrapper_plugin has link dependencies on the Flutter DLL. 92 | add_custom_command(TARGET ${TEST_RUNNER} POST_BUILD 93 | COMMAND ${CMAKE_COMMAND} -E copy_if_different 94 | "${FLUTTER_LIBRARY}" $ 95 | ) 96 | 97 | # Enable automatic test discovery. 98 | include(GoogleTest) 99 | gtest_discover_tests(${TEST_RUNNER}) 100 | endif() 101 | -------------------------------------------------------------------------------- /lib/utils/printer.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: constant_identifier_names 2 | 3 | import 'package:universal_ble/universal_ble.dart'; 4 | 5 | /// Optimized printer model with better data validation and serialization 6 | class Printer extends BleDevice { 7 | Printer({ 8 | this.address, 9 | this.name, 10 | this.connectionType, 11 | this.isConnected, 12 | this.vendorId, 13 | this.productId, 14 | }) : super(deviceId: address ?? '', name: name ?? ''); 15 | 16 | /// Create Printer from JSON with validation 17 | factory Printer.fromJson(Map json) { 18 | try { 19 | return Printer( 20 | address: json['address'] as String?, 21 | name: json['name'] as String?, 22 | connectionType: 23 | _getConnectionTypeFromString(json['connectionType'] as String?), 24 | isConnected: json['isConnected'] as bool?, 25 | vendorId: json['vendorId']?.toString(), 26 | productId: json['productId']?.toString(), 27 | ); 28 | } catch (e) { 29 | throw FormatException('Invalid Printer JSON format: $e'); 30 | } 31 | } 32 | 33 | @override 34 | // ignore: overridden_fields 35 | final String? name; 36 | final String? address; 37 | final ConnectionType? connectionType; 38 | final bool? isConnected; 39 | final String? vendorId; 40 | final String? productId; 41 | 42 | /// Convert to JSON with proper formatting 43 | Map toJson() { 44 | final data = {}; 45 | 46 | data['address'] = address; 47 | data['name'] = name; 48 | data['connectionType'] = connectionType?.name; 49 | data['isConnected'] = isConnected; 50 | data['vendorId'] = vendorId; 51 | data['productId'] = productId; 52 | 53 | return data; 54 | } 55 | 56 | /// Get human-readable connection type string 57 | String get connectionTypeString { 58 | switch (connectionType) { 59 | case ConnectionType.BLE: 60 | return 'BLE'; 61 | case ConnectionType.USB: 62 | return 'USB'; 63 | case ConnectionType.NETWORK: 64 | return 'NETWORK'; 65 | default: 66 | return 'UNKNOWN'; 67 | } 68 | } 69 | 70 | /// Create a copy with updated fields 71 | Printer copyWith({ 72 | String? address, 73 | String? name, 74 | ConnectionType? connectionType, 75 | bool? isConnected, 76 | String? vendorId, 77 | String? productId, 78 | }) => 79 | Printer( 80 | address: address ?? this.address, 81 | name: name ?? this.name, 82 | connectionType: connectionType ?? this.connectionType, 83 | isConnected: isConnected ?? this.isConnected, 84 | vendorId: vendorId ?? this.vendorId, 85 | productId: productId ?? this.productId, 86 | ); 87 | 88 | /// Generate unique identifier for the printer 89 | String get uniqueId { 90 | final buffer = StringBuffer(); 91 | if (vendorId != null) { 92 | buffer.write(vendorId); 93 | } 94 | buffer.write('_'); 95 | if (address != null) { 96 | buffer.write(address); 97 | } 98 | return buffer.toString(); 99 | } 100 | 101 | /// Check if printer has valid connection data 102 | bool get hasValidConnectionData { 103 | switch (connectionType) { 104 | case ConnectionType.USB: 105 | return vendorId != null && productId != null; 106 | case ConnectionType.BLE: 107 | return address != null; 108 | case ConnectionType.NETWORK: 109 | return address != null; 110 | default: 111 | return false; 112 | } 113 | } 114 | 115 | @override 116 | String toString() => 117 | 'Printer(name: $name, connectionType: ${connectionType?.name}, ' 118 | 'address: $address, isConnected: $isConnected)'; 119 | 120 | /// Convert string to ConnectionType enum 121 | static ConnectionType? _getConnectionTypeFromString(String? type) { 122 | if (type == null) { 123 | return null; 124 | } 125 | 126 | switch (type.toUpperCase()) { 127 | case 'BLE': 128 | return ConnectionType.BLE; 129 | case 'USB': 130 | return ConnectionType.USB; 131 | case 'NETWORK': 132 | return ConnectionType.NETWORK; 133 | default: 134 | return null; 135 | } 136 | } 137 | } 138 | 139 | /// Enhanced connection type enum 140 | enum ConnectionType { 141 | BLE, 142 | USB, 143 | NETWORK, 144 | } 145 | -------------------------------------------------------------------------------- /test/unit/platform_interface_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:flutter_test/flutter_test.dart'; 4 | import 'package:flutter_thermal_printer/flutter_thermal_printer_method_channel.dart'; 5 | import 'package:flutter_thermal_printer/flutter_thermal_printer_platform_interface.dart'; 6 | import 'package:flutter_thermal_printer/utils/printer.dart'; 7 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 8 | 9 | class MockFlutterThermalPrinterPlatform extends FlutterThermalPrinterPlatform 10 | with MockPlatformInterfaceMixin { 11 | @override 12 | Future getPlatformVersion() async => 'Mock Platform'; 13 | } 14 | 15 | class InvalidPlatform extends FlutterThermalPrinterPlatform {} 16 | 17 | void main() { 18 | TestWidgetsFlutterBinding.ensureInitialized(); 19 | 20 | group('FlutterThermalPrinterPlatform', () { 21 | late FlutterThermalPrinterPlatform originalInstance; 22 | 23 | setUp(() { 24 | originalInstance = FlutterThermalPrinterPlatform.instance; 25 | }); 26 | 27 | tearDown(() { 28 | FlutterThermalPrinterPlatform.instance = originalInstance; 29 | }); 30 | 31 | test('default instance is MethodChannelFlutterThermalPrinter', () { 32 | expect( 33 | FlutterThermalPrinterPlatform.instance, 34 | isA(), 35 | ); 36 | }); 37 | 38 | test('can set custom instance with valid token', () { 39 | final mockPlatform = MockFlutterThermalPrinterPlatform(); 40 | FlutterThermalPrinterPlatform.instance = mockPlatform; 41 | 42 | expect(FlutterThermalPrinterPlatform.instance, mockPlatform); 43 | }); 44 | 45 | test('InvalidPlatform can be created but lacks MockPlatformInterfaceMixin', 46 | () { 47 | final invalidPlatform = InvalidPlatform(); 48 | expect(invalidPlatform, isA()); 49 | }); 50 | 51 | group('unimplemented methods throw UnimplementedError', () { 52 | late FlutterThermalPrinterPlatform basePlatform; 53 | 54 | setUp(() { 55 | basePlatform = MockFlutterThermalPrinterPlatform(); 56 | }); 57 | 58 | test('startUsbScan throws UnimplementedError', () async { 59 | expect( 60 | () => basePlatform.startUsbScan(), 61 | throwsA(isA()), 62 | ); 63 | }); 64 | 65 | test('connect throws UnimplementedError', () async { 66 | final printer = Printer(); 67 | expect( 68 | () => basePlatform.connect(printer), 69 | throwsA(isA()), 70 | ); 71 | }); 72 | 73 | test('printText throws UnimplementedError', () async { 74 | final printer = Printer(); 75 | final data = Uint8List.fromList([1, 2, 3]); 76 | expect( 77 | () => basePlatform.printText(printer, data), 78 | throwsA(isA()), 79 | ); 80 | }); 81 | 82 | test('isConnected throws UnimplementedError', () async { 83 | final printer = Printer(); 84 | expect( 85 | () => basePlatform.isConnected(printer), 86 | throwsA(isA()), 87 | ); 88 | }); 89 | 90 | test('convertImageToGrayscale throws UnimplementedError', () async { 91 | final data = Uint8List.fromList([1, 2, 3]); 92 | expect( 93 | () => basePlatform.convertImageToGrayscale(data), 94 | throwsA(isA()), 95 | ); 96 | }); 97 | 98 | test('disconnect throws UnimplementedError', () async { 99 | final printer = Printer(); 100 | expect( 101 | () => basePlatform.disconnect(printer), 102 | throwsA(isA()), 103 | ); 104 | }); 105 | 106 | test('stopScan throws UnimplementedError', () async { 107 | expect( 108 | () => basePlatform.stopScan(), 109 | throwsA(isA()), 110 | ); 111 | }); 112 | 113 | test('getPrinters throws UnimplementedError', () async { 114 | expect( 115 | () => basePlatform.getPrinters(), 116 | throwsA(isA()), 117 | ); 118 | }); 119 | }); 120 | 121 | group('base class getPlatformVersion', () { 122 | test('throws UnimplementedError by default', () { 123 | final basePlatform = _BasePlatformForTest(); 124 | expect( 125 | basePlatform.getPlatformVersion, 126 | throwsA(isA()), 127 | ); 128 | }); 129 | }); 130 | }); 131 | } 132 | 133 | class _BasePlatformForTest extends FlutterThermalPrinterPlatform 134 | with MockPlatformInterfaceMixin {} 135 | -------------------------------------------------------------------------------- /example/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.14) 3 | project(flutter_thermal_printer_example LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "flutter_thermal_printer_example") 8 | 9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 10 | # versions of CMake. 11 | cmake_policy(VERSION 3.14...3.25) 12 | 13 | # Define build configuration option. 14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 15 | if(IS_MULTICONFIG) 16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 17 | CACHE STRING "" FORCE) 18 | else() 19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 20 | set(CMAKE_BUILD_TYPE "Debug" CACHE 21 | STRING "Flutter build mode" FORCE) 22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 23 | "Debug" "Profile" "Release") 24 | endif() 25 | endif() 26 | # Define settings for the Profile build mode. 27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 31 | 32 | # Use Unicode for all projects. 33 | add_definitions(-DUNICODE -D_UNICODE) 34 | 35 | # Compilation settings that should be applied to most targets. 36 | # 37 | # Be cautious about adding new options here, as plugins use this function by 38 | # default. In most cases, you should add new options to specific targets instead 39 | # of modifying this function. 40 | function(APPLY_STANDARD_SETTINGS TARGET) 41 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 43 | target_compile_options(${TARGET} PRIVATE /EHsc) 44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 46 | endfunction() 47 | 48 | # Flutter library and tool build rules. 49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 50 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 51 | 52 | # Application build; see runner/CMakeLists.txt. 53 | add_subdirectory("runner") 54 | 55 | # Enable the test target. 56 | set(include_flutter_thermal_printer_tests TRUE) 57 | 58 | # Generated plugin build rules, which manage building the plugins and adding 59 | # them to the application. 60 | include(flutter/generated_plugins.cmake) 61 | 62 | 63 | # === Installation === 64 | # Support files are copied into place next to the executable, so that it can 65 | # run in place. This is done instead of making a separate bundle (as on Linux) 66 | # so that building and running from within Visual Studio will work. 67 | set(BUILD_BUNDLE_DIR "$") 68 | # Make the "install" step default, as it's required to run. 69 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 70 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 71 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 72 | endif() 73 | 74 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 75 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 76 | 77 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 78 | COMPONENT Runtime) 79 | 80 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 81 | COMPONENT Runtime) 82 | 83 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 84 | COMPONENT Runtime) 85 | 86 | if(PLUGIN_BUNDLED_LIBRARIES) 87 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 88 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 89 | COMPONENT Runtime) 90 | endif() 91 | 92 | # Copy the native assets provided by the build.dart from all packages. 93 | set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") 94 | install(DIRECTORY "${NATIVE_ASSETS_DIR}" 95 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 96 | COMPONENT Runtime) 97 | 98 | # Fully re-copy the assets directory on each build to avoid having stale files 99 | # from a previous install. 100 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 101 | install(CODE " 102 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 103 | " COMPONENT Runtime) 104 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 105 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 106 | 107 | # Install the AOT library on non-Debug builds only. 108 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 109 | CONFIGURATIONS Profile;Release 110 | COMPONENT Runtime) 111 | -------------------------------------------------------------------------------- /test/unit/ble_config_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:flutter_thermal_printer/utils/ble_config.dart'; 3 | 4 | void main() { 5 | group('BleConfig', () { 6 | group('constructor', () { 7 | test('uses default connectionStabilizationDelay of 10 seconds', () { 8 | const config = BleConfig(); 9 | expect( 10 | config.connectionStabilizationDelay, 11 | const Duration(seconds: 10), 12 | ); 13 | }); 14 | 15 | test('accepts custom connectionStabilizationDelay', () { 16 | const config = BleConfig( 17 | connectionStabilizationDelay: Duration(seconds: 5), 18 | ); 19 | expect(config.connectionStabilizationDelay, const Duration(seconds: 5)); 20 | }); 21 | 22 | test('accepts zero duration', () { 23 | const config = BleConfig( 24 | connectionStabilizationDelay: Duration.zero, 25 | ); 26 | expect(config.connectionStabilizationDelay, Duration.zero); 27 | }); 28 | 29 | test('accepts milliseconds precision', () { 30 | const config = BleConfig( 31 | connectionStabilizationDelay: Duration(milliseconds: 500), 32 | ); 33 | expect( 34 | config.connectionStabilizationDelay, 35 | const Duration(milliseconds: 500), 36 | ); 37 | }); 38 | 39 | test('is const constructible', () { 40 | const config1 = BleConfig(); 41 | const config2 = BleConfig(); 42 | expect(identical(config1, config2), isTrue); 43 | }); 44 | }); 45 | 46 | group('copyWith', () { 47 | test('returns new instance with updated connectionStabilizationDelay', 48 | () { 49 | const original = BleConfig( 50 | // ignore: avoid_redundant_argument_values 51 | connectionStabilizationDelay: Duration(seconds: 10), 52 | ); 53 | final copied = original.copyWith( 54 | connectionStabilizationDelay: const Duration(seconds: 3), 55 | ); 56 | 57 | expect( 58 | copied.connectionStabilizationDelay, 59 | const Duration(seconds: 3), 60 | ); 61 | expect( 62 | original.connectionStabilizationDelay, 63 | const Duration(seconds: 10), 64 | ); 65 | }); 66 | 67 | test('preserves value when null passed', () { 68 | const original = BleConfig( 69 | connectionStabilizationDelay: Duration(seconds: 7), 70 | ); 71 | final copied = original.copyWith(); 72 | 73 | expect( 74 | copied.connectionStabilizationDelay, 75 | const Duration(seconds: 7), 76 | ); 77 | }); 78 | 79 | test('returns different instance', () { 80 | const original = BleConfig(); 81 | final copied = original.copyWith(); 82 | 83 | expect(identical(original, copied), isFalse); 84 | }); 85 | }); 86 | 87 | group('toString', () { 88 | test('includes connectionStabilizationDelay', () { 89 | const config = BleConfig( 90 | connectionStabilizationDelay: Duration(seconds: 5), 91 | ); 92 | final result = config.toString(); 93 | 94 | expect(result, contains('BleConfig')); 95 | expect(result, contains('connectionStabilizationDelay')); 96 | expect(result, contains('0:00:05')); 97 | }); 98 | 99 | test('formats default duration correctly', () { 100 | const config = BleConfig(); 101 | final result = config.toString(); 102 | 103 | expect(result, contains('0:00:10')); 104 | }); 105 | }); 106 | 107 | group('equality', () { 108 | test('const instances with same values are identical', () { 109 | const config1 = BleConfig( 110 | connectionStabilizationDelay: Duration(seconds: 5), 111 | ); 112 | const config2 = BleConfig( 113 | connectionStabilizationDelay: Duration(seconds: 5), 114 | ); 115 | 116 | expect(identical(config1, config2), isTrue); 117 | }); 118 | 119 | test('default const instances are identical', () { 120 | const config1 = BleConfig(); 121 | const config2 = BleConfig(); 122 | 123 | expect(identical(config1, config2), isTrue); 124 | }); 125 | }); 126 | 127 | group('edge cases', () { 128 | test('handles very long duration', () { 129 | const config = BleConfig( 130 | connectionStabilizationDelay: Duration(hours: 1), 131 | ); 132 | expect(config.connectionStabilizationDelay, const Duration(hours: 1)); 133 | }); 134 | 135 | test('handles microseconds', () { 136 | const config = BleConfig( 137 | connectionStabilizationDelay: Duration(microseconds: 100), 138 | ); 139 | expect( 140 | config.connectionStabilizationDelay, 141 | const Duration(microseconds: 100), 142 | ); 143 | }); 144 | }); 145 | }); 146 | } 147 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.0 2 | 3 | * **Major Refactoring & Code Quality Improvements** 4 | - Fixed all linting and static analysis issues across the project. 5 | - Improved null safety and type safety in `Printer` and `PrinterManager`. 6 | - Refactored `Printer` class to correctly handle name overrides and data sanitization. 7 | - Fixed Windows stub implementation for better cross-platform compatibility. 8 | 9 | * **Documentation** 10 | - Added comprehensive DartDoc comments for all public methods in `FlutterThermalPrinter` and `PrinterManager`. 11 | - Documented all parameters including `chunkSize`, `connectionStabilizationDelay`, and others. 12 | 13 | * **Testing** 14 | - Fixed and updated unit tests to ensure reliability Thanks to `@LosDanieloss`. 15 | - Verified behavior of `Printer` class serialization and initialization. 16 | 17 | ## 1.2.4 18 | * For windows and macos no chunking is required 19 | 20 | ## 1.2.3+1 21 | * Updated BLE MTU query or pass custom chunksize 22 | 23 | ## 1.2.3 24 | * Added Full Support for USB on Macos 25 | * Changed Flutter_blue_plus to universal_ble for better support of BLE and Classic Devices 26 | 27 | ## 1.2.2 - Optimized Version 28 | 29 | * **Enhanced Memory Management** 30 | - Proper stream lifecycle management with automatic cleanup 31 | - Improved resource disposal in disconnect operations 32 | - Optimized singleton pattern for thread safety 33 | - Better garbage collection patterns 34 | 35 | * **Image Processing Improvements** 36 | - Dynamic chunked image processing for better memory efficiency 37 | - Improved image validation with comprehensive error handling 38 | - Optimized image resizing algorithms 39 | - Better support for varying image dimensions 40 | 41 | * **Network Printer Enhancements** 42 | - Automatic connection validation and reconnection 43 | - Improved socket error handling with specific exception types 44 | - Better connection state management 45 | - Enhanced timeout handling 46 | 47 | * **Code Architecture Improvements** 48 | - Immutable Printer model with validation methods 49 | - Separated concerns into focused, testable methods 50 | - Enhanced error handling with meaningful messages 51 | - Comprehensive documentation and type safety 52 | 53 | * **Platform-Specific Optimizations** 54 | - Windows: Enhanced BLE initialization with proper error handling 55 | - Android/iOS: Optimized BLE scanning with better subscription management 56 | - All Platforms: Improved USB printer detection and management 57 | 58 | * **New Features** 59 | - `copyWith()` method for immutable Printer updates 60 | - `uniqueId` property for better printer identification 61 | - `hasValidConnectionData` validation method 62 | - Enhanced connection type validation 63 | - Comprehensive toString() and equality implementations 64 | 65 | * **Breaking Changes** 66 | - Printer class fields are now final (immutable) 67 | - Use `copyWith()` for printer updates instead of direct field assignment 68 | - Some internal method signatures have changed for better error handling 69 | 70 | * **Developer Experience** 71 | - Added OPTIMIZATION_GUIDE.md with detailed optimization explanations 72 | - Enhanced analysis_options.yaml with strict linting rules 73 | - Improved error messages for better debugging 74 | - Better type safety throughout the codebase 75 | 76 | ## 1.2.1 77 | * Fixed the issue of Flutter Blue plus for windows as it not supported for windows 78 | * Github repo for issues is now changed 79 | 80 | ## 1.2.0 81 | * Fixed BLE turn on exception for ios and macos by `@eduardohr-muniz` 82 | * Reduced time to print image on ble devices by `@eduardohr-muniz` 83 | 84 | ## 1.1.0 85 | * Added Improvments for windows Printing Thanks to `@eduardohr-muniz` 86 | * Updated Dependents Packages 87 | 88 | ## 1.0.1 89 | * Updated ReadMe 90 | 91 | ## 1.0.0 92 | * New Feature Network Printers added 93 | * Thanks to `@eduardohr-muniz` 94 | 95 | ## 0.0.20 96 | * Bugs fixed for usb printers 97 | 98 | ## 0.0.19+2 99 | * Bugs fixed for usb printers 100 | 101 | ## 0.0.19+1 102 | * Bugs Fixes 103 | 104 | ## 0.0.19 105 | * Refracted code and fixed bugs 106 | 107 | ## 0.0.18+1 108 | * Update some bugs 109 | 110 | ## 0.0.18 111 | * Added `turnOnBluetooth` function 112 | * Added `isBleTurnedOnStream` Stream of bluetooth is turned on or off 113 | * Added `isBleTurnedOn` function 114 | * Added `printWidget` function for printing any flutter widget 115 | * Updated USB Connection for Android 116 | * Updated BLE for All Platforms 117 | 118 | ## 0.0.17 119 | * Fixed get system devices in ble 120 | 121 | ## 0.0.16 122 | * Bumped packages dependent on like flutter_blue_plus,win32,flutter_utils_plus 123 | 124 | ## 0.0.15 125 | * Added new extension for Printer of connectionsState 126 | * Now you can get system connected devices on macos 127 | 128 | ## 0.0.14 129 | * Fixed flickering of bt devices 130 | * Added some improvements 131 | 132 | ## 0.0.13 133 | * Removed unused library flutterlib_serialport 134 | * Updated some dependencies 135 | 136 | ## 0.0.12 137 | * Some Bugs Fixed in MacOs 138 | 139 | ## 0.0.11 140 | * Some Bugs Fixed in MacOs 141 | 142 | ## 0.0.10 143 | * Some Bugs Fixed in MacOs 144 | 145 | ## 0.0.9 146 | * Added Getting USB Devices for MacOs 147 | 148 | ## 0.0.8 149 | * Updated Bluetooth Services Package 150 | 151 | ## 0.0.7 152 | * Removed test printing from the example 153 | 154 | ## 0.0.6 155 | * Added USB Printing for Windows Devices 156 | * Read Take Care Of part at below in Readme for More. 157 | 158 | ## 0.0.5 159 | * Added esc_pos_utils_plus for printing 160 | 161 | ## 0.0.4 162 | * Added getPrinter() to get the printers from both USB and Bluetooth 163 | 164 | ## 0.0.3 165 | * Added USB Printer Support for Android 166 | 167 | ## 0.0.2 168 | 169 | * Added Support for Windows Bluetooth 170 | * Added Start and Stop Scanning for BLE devices 171 | * Added Connect and Disconnect Printer 172 | * Added Printer Model Class 173 | * Added `longdata` to print data for long text 174 | 175 | ## 0.0.1 176 | 177 | * Initial release 178 | -------------------------------------------------------------------------------- /example/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.10) 3 | project(runner LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "example") 8 | # The unique GTK application identifier for this application. See: 9 | # https://wiki.gnome.org/HowDoI/ChooseApplicationID 10 | set(APPLICATION_ID "com.example.example") 11 | 12 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 13 | # versions of CMake. 14 | cmake_policy(SET CMP0063 NEW) 15 | 16 | # Load bundled libraries from the lib/ directory relative to the binary. 17 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 18 | 19 | # Root filesystem for cross-building. 20 | if(FLUTTER_TARGET_PLATFORM_SYSROOT) 21 | set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) 22 | set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) 23 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 24 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 25 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 26 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 27 | endif() 28 | 29 | # Define build configuration options. 30 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 31 | set(CMAKE_BUILD_TYPE "Debug" CACHE 32 | STRING "Flutter build mode" FORCE) 33 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 34 | "Debug" "Profile" "Release") 35 | endif() 36 | 37 | # Compilation settings that should be applied to most targets. 38 | # 39 | # Be cautious about adding new options here, as plugins use this function by 40 | # default. In most cases, you should add new options to specific targets instead 41 | # of modifying this function. 42 | function(APPLY_STANDARD_SETTINGS TARGET) 43 | target_compile_features(${TARGET} PUBLIC cxx_std_14) 44 | target_compile_options(${TARGET} PRIVATE -Wall -Werror) 45 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") 46 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") 47 | endfunction() 48 | 49 | # Flutter library and tool build rules. 50 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 51 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 52 | 53 | # System-level dependencies. 54 | find_package(PkgConfig REQUIRED) 55 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 56 | 57 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 58 | 59 | # Define the application target. To change its name, change BINARY_NAME above, 60 | # not the value here, or `flutter run` will no longer work. 61 | # 62 | # Any new source files that you add to the application should be added here. 63 | add_executable(${BINARY_NAME} 64 | "main.cc" 65 | "my_application.cc" 66 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 67 | ) 68 | 69 | # Apply the standard set of build settings. This can be removed for applications 70 | # that need different build settings. 71 | apply_standard_settings(${BINARY_NAME}) 72 | 73 | # Add dependency libraries. Add any application-specific dependencies here. 74 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 75 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 76 | 77 | # Run the Flutter tool portions of the build. This must not be removed. 78 | add_dependencies(${BINARY_NAME} flutter_assemble) 79 | 80 | # Only the install-generated bundle's copy of the executable will launch 81 | # correctly, since the resources must in the right relative locations. To avoid 82 | # people trying to run the unbundled copy, put it in a subdirectory instead of 83 | # the default top-level location. 84 | set_target_properties(${BINARY_NAME} 85 | PROPERTIES 86 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" 87 | ) 88 | 89 | 90 | # Generated plugin build rules, which manage building the plugins and adding 91 | # them to the application. 92 | include(flutter/generated_plugins.cmake) 93 | 94 | 95 | # === Installation === 96 | # By default, "installing" just makes a relocatable bundle in the build 97 | # directory. 98 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 99 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 100 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 101 | endif() 102 | 103 | # Start with a clean build bundle directory every time. 104 | install(CODE " 105 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 106 | " COMPONENT Runtime) 107 | 108 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 109 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 110 | 111 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 112 | COMPONENT Runtime) 113 | 114 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 115 | COMPONENT Runtime) 116 | 117 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 118 | COMPONENT Runtime) 119 | 120 | foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) 121 | install(FILES "${bundled_library}" 122 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 123 | COMPONENT Runtime) 124 | endforeach(bundled_library) 125 | 126 | # Copy the native assets provided by the build.dart from all packages. 127 | set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") 128 | install(DIRECTORY "${NATIVE_ASSETS_DIR}" 129 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 130 | COMPONENT Runtime) 131 | 132 | # Fully re-copy the assets directory on each build to avoid having stale files 133 | # from a previous install. 134 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 135 | install(CODE " 136 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 137 | " COMPONENT Runtime) 138 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 139 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 140 | 141 | # Install the AOT library on non-Debug builds only. 142 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 143 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 144 | COMPONENT Runtime) 145 | endif() 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_thermal_printer 2 | 3 | 4 | 5 | 6 | 7 | ## Buy Me A Coffee 8 | If you find this project helpful and want to support its development, you can buy me a coffee: 9 | 10 | Buy Me A Coffee 11 | 12 | ## Getting Started 13 | 14 | This plugin is used to print data on thermal printers with ease across multiple platforms. 15 | 16 | ## 🎉 New Feature: USB Printing Services 17 | 18 | > **✨ Exciting Update!** We now support **USB printing services** across multiple platforms! Connect your thermal printers directly via USB for faster, more reliable printing without the need for wireless connections. 19 | > 20 | > **Supported Platforms for USB:** 21 | > - 🤖 **Android** - Full USB support 22 | > - 🖥️ **Windows** - Complete USB integration 23 | > - 🍎 **macOS** - Native USB connectivity 24 | > 25 | > Experience enhanced printing performance with direct USB connections! 26 | 27 | ## Currently Supported 28 | 29 | | Service | Android | iOS | macOS | Windows | 30 | | ------------------------------ | :-----: | :-: | :---: | :-----: | 31 | | Bluetooth | ✅ | ✅ | ✅ | ✅ | 32 | | USB | ✅ | | ✅ | ✅ | 33 | | BLE | ✅ | ✅ | ✅ | ✅ | 34 | | WiFi | ✅ | ✅ | ✅ | ✅ | 35 | 36 | ```dart 37 | final _flutterThermalPrinterPlugin = FlutterThermalPrinter.instance; 38 | 39 | // Enum ConnectionType 40 | enum ConnectionType { 41 | BLE, 42 | USB, 43 | NETWORK, 44 | } 45 | 46 | // Additional Functions 47 | // Recommended Function for getting printers 48 | getPrinters( 49 | refreshDuration: Duration, 50 | connectionTypes: List, 51 | ) { 52 | // Supports WINDOWS, ANDROID , Macos for USB 53 | // MAC, IOS, ANDROID, WINDOWS for BLUETOOTH. 54 | } 55 | 56 | // Refer to Example for Complete code 57 | ``` 58 | 59 | --- 60 | 61 | ## Bluetooth Services 62 | 63 | | Feature | Android | iOS | macOS | Windows | 64 | | ------------------------------ | :-----: | :-: | :---: | :-----: | 65 | | Start scanning | ✅ | ✅ | ✅ | ✅ | 66 | | Stop scanning | ✅ | ✅ | ✅ | ✅ | 67 | | Connect printer | ✅ | ✅ | ✅ | ✅ | 68 | | Disconnect printer | ✅ | ✅ | ✅ | ✅ | 69 | | Print data | ✅ | ✅ | ✅ | ✅ | 70 | | Print widget | ✅ | ✅ | ✅ | ✅ | 71 | 72 | --- 73 | 74 | ## USB Services 75 | 76 | | Feature | Android | iOS | macOS | Windows | 77 | | ------------------------------ | :-----: | :-: | :---: | :-----: | 78 | | Start scanning | ✅ | | ✅ | ✅ | 79 | | Stop scanning | ✅ | | ✅ | ✅ | 80 | | Connect printer | ✅ | | ✅ | ✅ | 81 | | Print data | ✅ | | ✅ | ✅ | 82 | | Print widget | ✅ | | ✅ | ✅ | 83 | 84 | --- 85 | 86 | ## WiFi Services 87 | 88 | | Feature | Android | iOS | macOS | Windows | 89 | | ------------------------------ | :-----: | :-: | :---: | :-----: | 90 | | Connect printer | ✅ | ✅ | ✅ | ✅ | 91 | | Disconnect printer | ✅ | ✅ | ✅ | ✅ | 92 | | Print data | ✅ | ✅ | ✅ | ✅ | 93 | | Print widget | ✅ | ✅ | ✅ | ✅ | 94 | 95 | --- 96 | 97 | ## Printer Model Class 98 | 99 | ```dart 100 | String? address; 101 | String? name; 102 | ConnectionType? connectionType; 103 | bool? isConnected; 104 | String? vendorId; 105 | String? productId; 106 | ``` 107 | 108 | --- 109 | 110 | ## Additional Features 111 | 112 | ### Screenshot to Printer 113 | Easily capture and print widgets as images using the `printWidget` method. 114 | 115 | ### Image Cropping for Long Prints 116 | Handles long data by cropping images and printing them in chunks to ensure seamless printing on devices with limited buffer capacity. 117 | 118 | ### Connection Type Validation 119 | - Ensures `ConnectionType` compatibility and alerts when unsupported combinations are used. 120 | 121 | ### BLE State Monitoring 122 | Provides real-time monitoring for Bluetooth states, ensuring proactive error handling and reconnections. 123 | 124 | ### BLE Connection Configuration 125 | Customize BLE connection behavior to optimize for different printer models: 126 | 127 | ```dart 128 | // Global configuration (applies to all BLE connections) 129 | FlutterThermalPrinter.instance.bleConfig = 130 | BleConfig(connectionStabilizationDelay: Duration(seconds: 3)); 131 | 132 | // Per-connection override for specific devices 133 | await FlutterThermalPrinter.instance.connect( 134 | printer, 135 | connectionStabilizationDelay: Duration(seconds: 2), 136 | ); 137 | 138 | // Default behavior (10 seconds) - no configuration needed 139 | await FlutterThermalPrinter.instance.connect(printer); 140 | ``` 141 | 142 | | Configuration | Use Case | 143 | |---------------|----------| 144 | | Global config | Set once for consistent behavior across all connections | 145 | | Per-call override | Fine-tune for specific printer models that connect faster/slower | 146 | | Default (10s) | Backwards compatible, works with most printers | 147 | 148 | --- 149 | 150 | ## Notes and Recommendations 151 | 152 | - **Windows & MacOS Users:** Make sure you have the XPrinter driver installed on Windows for printer compatibility. 153 | Download the driver from [XPrinter Driver](https://www.xprintertech.com/drivers-2.html). 154 | 155 | - **Cross-Platform Usage:** Ensure Bluetooth permissions and configurations are set correctly for Android and iOS. 156 | 157 | --- 158 | 159 | ## Contributing Guidelines 160 | 161 | We welcome contributions to enhance the plugin's functionality! 162 | To contribute, please fork the repository, make changes, and submit a pull request. 163 | For bug reports or feature requests, feel free to open an issue. 164 | 165 | 166 | --- 167 | 168 | ## Contributors 169 | 170 | ![Contributors](https://contrib.rocks/image?repo=SunilDevX/flutter_thermal_printer) 171 | 172 | 173 | Feel free to contribute to this project and help make it better for everyone! 174 | 175 | --- --------------------------------------------------------------------------------