Reputation: 189
I am trying to use flutter to communicate with SunMi mobile printer. I want to invoke the printer using AIDL as one of the ways to communicate with the printer but i don't know how and where to place the AIDL files in flutter or is it even possible to use flutter in my case. I need to know if it is possible to communicate with the printer using its AIDL. I am opting to use flutter or android studio with java for my application.
Source of question : https://github.com/flutter/flutter/issues/49413#issue-554566892
i could not find the proper answer so posted the question here.
Upvotes: 0
Views: 2175
Reputation: 53
If your the printer uses a BT or USB interface (Sometimes even if the device has a built-in printer, they still use a USB interface via a ribbon cable), you can ditch the SDK of the vendor and use a flutter package for POS printing like flutter_esc_pos_utils.
To check which interface is being used, first install the above package and run this:
final profiles = await CapabilityProfile.getAvailableProfiles();
I have used this approach to print on the built in printer of self-ordering kiosk. Cuts down on the development time & makes your app compatible with more hardware.
Upvotes: 0
Reputation: 443
Since this is an AIDL file we're talking about, it would be safe to assume that this is an Android only feature.
To do this, like any other Android-specific MethodChannel
implementation, you'll need to create a MethodCallHandler and/or an StreamHandler (depending if you want to do streams or just an command -> result approach), register it on the Main FlutterActivity, and call it from dart through MethodChannels.
DISCLAIMER
Creating the MethodCallHandler/StreamHandler
Inside your android/app/src/main/com/some/path
folder in your flutter app, create a new java file and implement ServiceConnection
, MethodChannel.MethodCallHandler
and/or EventChannel.StreamHandler
:
public class PrinterPlugin implements MethodChannel.MethodCallHandler, EventChannel.StreamHandler, ServiceConnection {
public static final CHANNEL = "com.some.path/printer";
public static final EVENT_CHANNEL = "com.some.path/printer-events";
private Context context;
private IPrinterService printerService = null; // where IPrinterService would be the AIDL's name
public EventChannel.EventSink eventSink = null;
public PrinterPlugin(Context context) {
this.context = context;
if (printerService == null) {
// these strings should be in your documentation or you can find these values from the package manager
Intent intent = new Intent("com.your.printer.service");
intent.setPackage("com.whatever.aidl");
context.bindService(intent, this, Context.BIND_AUTO_CREATE);
}
}
public void disconnect() {
context.unbindService(this);
}
// streamhandler implementation
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
this.eventSink = events;
}
@Override
public void onCancel(Object arguments) {
this.eventSink = null;
}
// /streamhandler implementation
// methodcallhandler implementation
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
try {
switch (call.method) {
case "initialize": printerService.printerInit(); break;
case "print-text": printerService.printText(call.argument("data")); break;
// implement other aidl methods
}
} catch (RemoteException e) {
result.error("", ex.getMessage(), null);
}
}
// /methodcallhandler implementation
// serviceConnection implementation
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
printerService = IPrinterService .Stub.asInterface(service);
if (eventSink != null) {
eventSink.success("Printer Connected");
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
printerService = null;
if (eventSink != null) {
eventSink.success("Printer Disconnected");
}
}
// /serviceConnection implementation
}
Register the PrinterPlugin to the MainActivity as a MethodChannel and EventChannel
Now that that's out of the way, you'll need to register this plugin on the MainActivity
's configureFlutterEngine
method:
public class MainActivity extends FlutterActivity {
private PrinterPlugin printerPlugin;
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
Context context = getContext();
printerPlugin = new PrinterPlugin(context);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), PrinterPlugin.CHANNEL)
.setMethodCallHandler(printerPlugin);
new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), PrinterPlugin.EVENT_CHANNEL)
.setStreamHandler(printerPlugin);
}
@Override
protected void onDestroy() {
super.onDestroy();
this.printerPlugin.unbindService();
}
}
Call the methods from dart
Now the last thing that you need to do is call these from dart.
const MethodChannel _channel = MethodChannel('com.some.path/printer'); // should match the CHANNEL constant on the java side
const EventChannel _evntChannel = EventChannel('com.some.path/printer-events'); // should match the EVENT_CHANNEL constant on the java side
class PrinterPlugin {
static Stream<dynamic> _printerStream = _eventChannel.receiveBroadcastStream();
Stream<String> status$;
PrinterPlugin() {
status$ = _printerStream;
}
static Future printText(String data) async {
await _channel.invokeMethod('initialize');
await _channel.invokeMethod('print-text', 'Foo Bar');
}
}
Well, that was a lot of code - but that's basically how I did it. Just a MethodCallHandler
with a ServiceConnection
implementation.
You can go crazy with this implementation as well, like real-time printing progress, or getting streamed printer status, etc.
Let me know if it works for your needs.
Upvotes: 3