I'm trying to make work the PrintService class in Xamarin PCL Android Project and I make my PrintService to appear in printing options but in the moment of activating it or find printers program stops and Visual Studio shows the next error:
07-11 18:56:32.802 E/AndroidRuntime( 6088): java.lang.RuntimeException: Unable to instantiate service PrintService.Test.TransferPrintService: java.lang.ClassNotFoundException: Didn't find class "PrintService.Test.TransferPrintService" on path: DexPathList[[zip file "/data/app/PrintService.Test-dAvKeFP8zI2zBEHqn5yyqA==/base.apk"],nativeLibraryDirectories=[/data/app/PrintService.Test-dAvKeFP8zI2zBEHqn5yyqA==/lib/x86, /system/fake-libs, /data/app/PrintService.Test-dAvKeFP8zI2zBEHqn5yyqA==/base.apk!/lib/x86, /system/lib, /vendor/lib]]
I have read many posts here, on Google, etc, but haven't find a working solution.
I'm working on Visual Studio 2017 15.7.4, JDK 8, Xamarin 4.10.10.2.
Any idea of solving this error?
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="PrintService.Test" android:installLocation="auto" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="19" />
<application android:label="@string/app_name" android:allowBackup="false" android:icon="@mipmap/ic_launcher">
<service android:name=".TransferPrintService" android:permission="android.permission.BIND_PRINT_SERVICE">
<intent-filter>
<action android:name="android.printservice.PrintService" />
</intent-filter>
<meta-data android:name="android.printservice" android:resource="@xml/transfer_print_service" />
</service>
</application>
</manifest>
MainActivity.cs
namespace PrintServiceTest2
{
using Android.App;
using Android.Widget;
using Android.OS;
using Android.Support.V7.App;
using Android.Content;
[Activity(Label = "Test Print Service",
Theme = "@style/AppTheme", MainLauncher = true,
Name = "PrintService.Test.MainActivity")]
public class MainActivity : AppCompatActivity
{
public static Toast mainToast;
public static Intent myIntent;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
mainToast = Toast.MakeText(this, "Service", ToastLength.Long);
myIntent = new Intent("android.printservice.PrintService");
//var intent = new Intent(this, typeof(TransferPrintService));
//StartService(intent);
}
public static void ShowToast(string text)
{
mainToast.SetText(text);
mainToast.Show();
}
}
}
TransferPrintService.cs
namespace PrintServiceTest2
{
using Android.Print;
using Android.PrintServices;
using System.Collections.Generic;
public class TransferPrintService : PrintService
{
private object mFirstFakePrinter;
private object mSecondFakePrinter;
public TransferPrintService()
{
MainActivity.ShowToast("TransferPrintService");
}
public override void OnCreate()
{
mFirstFakePrinter = new PrinterInfo.Builder(GeneratePrinterId("Printer 1"),
"SHGH-21344", PrinterStatus.Idle).Build();
mSecondFakePrinter = new PrinterInfo.Builder(GeneratePrinterId("Printer 2"),
"OPPPP-09434", PrinterStatus.Idle).Build();
MainActivity.ShowToast("OnCreate");
base.OnCreate();
}
protected override void OnPrintJobQueued(Android.PrintServices.PrintJob printJob)
{
printJob.Start();
printJob.Complete();
}
protected override PrinterDiscoverySession OnCreatePrinterDiscoverySession()
{
MainActivity.ShowToast("OnCreatePrinterDiscoverySession");
return new TransferPrinterDiscoverySession(this);
}
protected override void OnRequestCancelPrintJob(Android.PrintServices.PrintJob printJob)
{
}
protected override void OnConnected()
{
MainActivity.ShowToast("OnConnected");
base.OnConnected();
}
protected override void OnDisconnected()
{
MainActivity.ShowToast("OnDisconnected");
base.OnDisconnected();
}
public override void OnDestroy()
{
MainActivity.ShowToast("OnDestroy");
base.OnDestroy();
}
}
public class TransferPrinterDiscoverySession : PrinterDiscoverySession
{
private readonly TransferPrintService printService;
private const string PRINTER = "Transfer Printer";
public TransferPrinterDiscoverySession(TransferPrintService printService)
{
this.printService = printService;
}
public override void OnStartPrinterDiscovery(IList<PrinterId> priorityList)
{
PrinterId id = printService.GeneratePrinterId(PRINTER);
PrinterInfo.Builder builder =
new PrinterInfo.Builder(id, PRINTER, PrinterStatus.Idle);
PrinterInfo info = builder.Build();
List<PrinterInfo> infos = new List<PrinterInfo>
{
info
};
AddPrinters(infos);
}
public override void OnStopPrinterDiscovery()
{
}
public override void OnValidatePrinters(IList<PrinterId> printerIds)
{
MainActivity.mainToast.Show();
}
public override void OnStartPrinterStateTracking(PrinterId printerId)
{
PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, PRINTER, PrinterStatus.Idle);
PrinterCapabilitiesInfo.Builder capBuilder =
new PrinterCapabilitiesInfo.Builder(printerId);
capBuilder.AddMediaSize(PrintAttributes.MediaSize.IsoA4, true);
capBuilder.AddResolution(new PrintAttributes.Resolution(
"Default", "Default", 360, 360), true);
capBuilder.SetColorModes(3, 2);
capBuilder.SetMinMargins(PrintAttributes.Margins.NoMargins);
PrinterCapabilitiesInfo caps = capBuilder.Build();
builder.SetCapabilities(caps);
PrinterInfo info = builder.Build();
List<PrinterInfo> infos = new List<PrinterInfo>
{
info
};
AddPrinters(infos);
}
public override void OnStopPrinterStateTracking(PrinterId printerId)
{
MainActivity.mainToast.Show();
}
public override void OnDestroy()
{
}
}
}
Either match your exported Xamarin.Android
JNI/Java Wrapper Class (AWC) to your manual manifest entries by using the Name parameter on the Service attribute:
[Service(Name = "PrintService.Test.TransferPrintService")]
public class TransferPrintService : PrintService
{
Or do not manually edit your manifest and let the Xamarin build do it:
[Service(Permission = "android.permission.BIND_PRINT_SERVICE")]
[IntentFilter(new String[] { "android.printservice.PrintService" })]
public class TransferPrintService : PrintService
{
~~~
}