I am implementing the UniMag credit card slider API on Xamarin Android so my app can read credit cards. The API is only for native Android so I followed the instructions here to create a wrapper around the API's .jar file. That works great and is super simple.
I can initialize the api and get listener callbacks when connecting and disconnecting the slider device. Since not all Android devices are supported by the API the UniMagReader needs to read a provided config xml file.
The problem I am having is that I cannot get the API to read the file.
The API call to use for this is;
var reader = new UniMagReader(new UniMagMessage(), Android.App.Application.Context);
reader.SetSaveLogEnable(false);
reader.SetVerboseLoggingEnable(true);
reader.RegisterListen();
string fileNameWithPath = GetConfigurationFileFromRaw();
reader.SetXMLFileNameWithPath(fileNameWithPath);
reader.LoadingConfigurationXMLFile(false);
I have tried putting the file in the Resources.Raw, Resources.Assets and the Root directories and tried a few ways of providing the URL to the API.
This is the way the demo app suggests:
private string GetXMLFileFromRaw(string fileName)
{
//the target filename in the application path
string fileNameWithPath = null;
fileNameWithPath = fileName;
try
{
//using (var inStream = Android.App.Application.Context.Assets.Open("default_config.xml")) // assest file access
using (var inStream = Android.App.Application.Context.Resources.OpenRawResource(Resource.Raw.default_config)) // raw file access
{
var length = GetStreamLength(inStream);
byte[] buffer = new byte[length];
inStream.Read(buffer, 0, (int)length);
inStream.Close();
Android.App.Application.Context.DeleteFile(fileNameWithPath);
var fout = Android.App.Application.Context.OpenFileOutput(fileNameWithPath, Android.Content.FileCreationMode.Private);
fout.Write(buffer, 0, (int)length);
fout.Close();
// to refer to the application path
var fileDir = Android.App.Application.Context.FilesDir;
fileNameWithPath = fileDir.Parent + Path.DirectorySeparatorChar + fileDir.Name;
fileNameWithPath += Path.DirectorySeparatorChar + "default_config.xml";
}
}
catch (System.Exception e)
{
fileNameWithPath = null;
}
return fileNameWithPath;
}
// Return the length of a stream that does not have a usable Length property
public static long GetStreamLength(Stream stream)
{
long originalPosition = 0;
long totalBytesRead = 0;
if (stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}
try
{
byte[] readBuffer = new byte[4096];
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, 0, 4096)) > 0)
{
totalBytesRead += bytesRead;
}
}
finally
{
if (stream.CanSeek)
{
stream.Position = originalPosition;
}
}
return totalBytesRead;
}
And this is another way I tried:
var file = new Java.IO.File(Android.Net.Uri.Parse("file:///default_config.xml").ToString());
var uri = file.AbsolutePath;
The errors I am getting are coming from the API. When connecting the swiper to the device I see:
[UMSDK] SDK: headset attached
[UMSDK] SDK: reader attached, but no config loaded
From the OnReceiveMsgFailureInfo Callback I see "The XML file does not exist and the auto update disabled."
And in the Application Output I see:
[UMSDK] UmXmlParser: parsing XML failed due to exception
[UMSDK] org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 0: not well-formed (invalid token)
[UMSDK] at org.apache.harmony.xml.ExpatParser.parseFragment(ExpatParser.java:519)
[UMSDK] at org.apache.harmony.xml.ExpatParser.parseDocument(ExpatParser.java:478)
[UMSDK] at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:316)
[UMSDK] at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:279)
[UMSDK] at com.idtechproducts.acom.AcomXmlParser.parseFile(AcomXmlParser.java:91)
[UMSDK] at com.idtechproducts.unimagsdk.UniMagConfigHelper.loadingXMLFile(UniMagConfigHelper.java:116)
[UMSDK] at com.idtechproducts.unimagsdk.UniMagConfigHelper.loadingXMLFile(UniMagConfigHelper.java:46)
[UMSDK] at IDTech.MSR.uniMag.uniMagReader.loadingConfigurationXMLFile(uniMagReader.java:496)
The sample has the file placed in the Assets or Raw folder. To use a file that is in the Assets or Raw folders, you have to get a stream and then write that stream to a file that is accessible outside of the app itself (any file added to the app's project in the IDE ends up packaged within the APK itself so is not accessible by any thing outside of the APK itself). The Java sample you sent does do just that (copied from the sample in your post, but abbreviated to only show specific lines):
So first set up the file name and path variables:
Then get a stream.
If default_config.xml file in assets:
If default_config.xml in Raw resources:
Then do the following:
Then you can pass
fullPathto the API: