Tenemos un proyecto en el que necesitamos utilizar uno de estos terminales tipo POS ( Point of sale / punto de venta ) que a nuestro parecer era bastante completo, ya que cuenta con su propia impresora térmica y de alguna forma están relacionados con Xiaomi.

El problema
En nuestro equipo apenas un par conoce Android nativo, por lo que para acelerar el desarrollo decidimos utilizar Xamarin Forms que es el que todos conocemos, sin embargo nos encontramos con el problema de que no nos fue posible hacer funcionar correctamente el generador de código en base de los AIDL que si funcionan correctamente en nativo, mostrándonos un error referente a
Android.Graphics.BitmapStub
Este código es generado, por lo que no debería tocarse, así que no hubo forma de hacerlo funcionar así.
La solución
Para solucionar este problema, opté por generar un AAR que ya tenga todas las funcionalidades que necesitamos para después importarlas al proyecto Xamarin Android.
Explicaré paso a paso como generar este AAR y después como utilizarlo en sus proyectos.
1. Crear un proyecto en Android studio
Procederemos primero a crear un proyecto limpio usando Android Studio:

No necesitaremos un activity, por lo que seleccionamos “Add No Activity” y “Next”

El nombre del proyecto no importa, por lo que podemos poner lo que queramos, ya que crearemos un módulo nuevo que será el que usaremos en Xamarin

Una vez el proyecto esté cargado, creamos un nuevo módulo con File => New => New Module

Y aquí es importante seleccionar “Android Library”

Pongan un paquete y nombre de módulo que sea conveniente, ya que será el que usarán tanto para importar como para exportar la librería

En el proyecto les habrá creado un módulo nuevo llamado sunmiv2 (o el nombre que hayan elegido)

En este proyecto es donde implementarán sus archivos AIDL, en este caso yo usaré los que la documentación de la Sunmi V2 me indica, como si se tratara de una implementación en Android


Para que Android Studio genere las clases necesarias basado en los AIDL deberemos hacer Make Module sunmiv2 al módulo

Una vez hecho esto, ya podemos realizar la implementación de los servicios pertinentes basados en la definición de los AIDL que quieran utilizar
Dejaré un ejemplo con unas cuantas funciones implementadas, del servicio de impresión, donde cada uno deberá poner los métodos que vayan a utilizar:
package com.marcomaldonado.sunmiv2.services; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Bitmap; import android.os.IBinder; import android.os.RemoteException; import com.marcomaldonado.sunmiv2.contracts.SunmiCallback; import woyou.aidlservice.jiuiv5.ICallback; import woyou.aidlservice.jiuiv5.IWoyouService; public class SunmiPrinter { private static final SunmiPrinter printer = new SunmiPrinter(); private IWoyouService woyouService = null; private final String UNREACHABLE = "unreachable"; private ServiceConnection connService = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { woyouService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { woyouService = IWoyouService.Stub.asInterface(service); } }; private SunmiPrinter(){} public static SunmiPrinter getInstance() { return printer; } public void initPrinter(Context context){ Intent intent=new Intent(); intent.setPackage("woyou.aidlservice.jiuiv5"); intent.setAction("woyou.aidlservice.jiuiv5.IWoyouService"); context.startService(intent); context.bindService(intent, connService, Context.BIND_AUTO_CREATE); } // -------------------------------- public void printText(String text, SunmiCallback callback) { if (woyouService != null) { try { woyouService.printText(text, makeCallback(callback)); } catch (RemoteException e) { e.printStackTrace(); ThrowErrorCallback(callback); } } else { ThrowErrorCallback(callback); } } public void printBitmap(Bitmap bitmap, SunmiCallback callback) { if (woyouService != null) { try { woyouService.printBitmap(bitmap, makeCallback(callback)); } catch (RemoteException e) { e.printStackTrace(); ThrowErrorCallback(callback); } } else { ThrowErrorCallback(callback); } } private void ThrowErrorCallback(SunmiCallback callback) { if (callback != null) { try { callback.onRaiseException(500, UNREACHABLE); } catch (RemoteException e) { e.printStackTrace(); } } } private ICallback makeCallback(final SunmiCallback callback) { if (callback != null) { return new ICallback.Stub() { @Override public void onRunResult(boolean isSuccess) throws RemoteException { callback.onRunResult(isSuccess); } @Override public void onReturnString(String result) throws RemoteException { callback.onReturnString(result); } @Override public void onRaiseException(int code, String msg) throws RemoteException { callback.onRaiseException(code, msg); } }; } return null; } }
package com.marcomaldonado.sunmiv2.contracts; import android.os.RemoteException; public interface SunmiCallback { void onRunResult(boolean isSuccess) throws RemoteException; void onReturnString(String result) throws RemoteException; void onRaiseException(int code, String msg) throws RemoteException; }
La interfaz SunmiCallback y la implementación completa de este SunmiPrinter la pueden encontrar en este gist:
https://gist.github.com/Mxrck/297290b47c6a70392148b59f3ae3bcf2
Una vez que tengan hecha la implementación, tendremos que construir nuestro AAR, para hacerlo solo es necesario llamar de nuevo a Make Module Sunmi y buscamos el archivo generado;

2. Crear una librería que encapsule nuestro AAR en Visual Studio
Para este proceso utilicé Visual Studio 2019, lo primero será crear un proyecto del tipo Android Binding Library (Xamarin)

El nombre que le pondré al proyecto es el nombre que después será usado como referencia, por lo que le dejaré SunmiV2

En nuestro nuevo proyecto deberemos añadir nuestro archivo AAR, yo he optado por ponerlo dentro de la carpeta Jars

Una vez en nuestro proyecto, debemos cambiar el Build Action por LibraryProjectZip, tardará un poco en realizar este ajuste y una vez listo construimos el DLL


Al terminar nos habrá generado el DLL que ya podemos utililzar en otros proyectos

3. Implementación en un proyecto
Debido a que nosotros trabajaremos con Xamarin Forms, he creado un proyecto limpio en Forms para hacer la implementación, pero es perfectamente factible utillizar Xamarin Android, si tu proyecto no es en Xamarin Forms, puedes saltar al paso 4.
Primero tendremos que crear una interface en la solución .NET Standard usaré el nombre de IPrinter y en Xamarin Android la implementación Printer

Al XAML principal le añadí un botón para poder hacer la prueba de impresión:
<Button Clicked="Button_Clicked" Text="Test Printer" />
Con lo que ya podemos utilizar nuestra implementación, faltando solo utilizar la librería que creamos.
private void Button_Clicked(object sender, EventArgs e) { var printer = DependencyService.Get<IPrinter>(); printer.PrintImage(...); printer.PrintText("..."); }
En desarrollo…