Umesh Chakradhar
Umesh Chakradhar

Reputation: 189

How to implement .aidl file in flutter

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

Answers (2)

Tariiq Dusmohamud
Tariiq Dusmohamud

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

arvil
arvil

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

  • The code below is not tested and might have some syntax errors, let me know if you find issues and I'll address them.
  • I have combined everything in one file for brevity, you can move some parts of the code to separate files as you see fit.

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

Related Questions