Xamarin - Using Portable Class Libraries a mandatory way to go? - xamarin

Recently I am requested to setup the design for a new app, which needs to be build using Xamarin. The team already created a DEMO app for Android, iOS and Windows Phone. So basically this demo version needs to be transformed/refactored into a proper maintainable product.
When looking into the code what currently is implemented in the DEMO app, I found out that some third party libraries are used which are not available as PCL. This means that I cannot build up my app using PCL's unless I can port this third party library into a PCL.
My findings are:
The functionality we use from this third party library works fine on all 3 platforms
I cannot find any blocking reason why I should not use normal Class Libraries
Questions:
Are there any blocking reasons why I cannot make use of normal Class Libraries?
Will the public apps stores accept these apps or is this not an issue at all?
If not.. Can you give recommendations where especially take care of going with normal Class Library's
If there are.. How can I port third party Libraries to PCL or is there any other way to work around?

First: public app stores don't care about the internals of your app, as long as it follows their guidelines. And that's something Xamarin takes care of, so everything that is dropping out of the compiler will be okay.
Second: You're totally fine with not using PCL if that fits your needs in a better way. In addition to PCL you could also make use of Shared Projects or just linking files from common library projects into each platform-specific project.
But from my personal experience PCL are a good way to make sure the code you're writing and the tools you're using are really working on every platform, so you don't have to be afraid of bad surprises afterwards. And with the PCL profile 78 support of stuff like LINQ etc. is pretty good.
What you can do in addition, is to use a facade inside your shared PCL code, that hides away the concrete implementation, that is then provided for each platform individually.
That could look like:
(PCL)
public interface ILogger
{
void Log(string message);
}
public static class SharedUtilities
{
public static ILogger Logger { get; private set; }
public static void SetUp(ILogger logger)
{
Logger = logger;
}
}
// Now Use it from everywhere in your code:
SharedUtilities.Logger.Log("Hello PCL!");
In your iOS app, for example:
public class IOSLogger : ILogger
{
public void Log(string message)
{
// Make use of a native logging library or whatever you want
}
}
// AppDelegate:
SharedUtilities.SetUp(new IOSLogger());

Related

How to import Activity of NfcFCardEmulation.EnableService from Xamarin common project, not Android project?

I'm developing an app using Xamarin's HCE feature.
The project structure is as follows.
hceSample
hceSample.Android
hceSample.iOS
I am implementing hce simulation code called hceService in hceSample, not hceSample.Android.
A function called Enable_Card exists in the hce service, and you want to use the NfcFCardEmulation.EnableService function in that function.
Activity and ComponentName are requested as parameters of the function.
The ComponentName area was handled easily, but I don't know how to get the Activity. Please advise.
This is the contents of enable_Card function of hceService.
private Activity activity = null;
private bool enable_Card(cardModel card)
{
try
{
sid = card.cardSN;
tag = "Felica";
emulation.EnableService(, componentName); //<- How to get Activity??
emulation.SetNfcid2ForService(componentName, sid);
return true;
}
catch
{
return false;
}
}
This is my first time asking a question on Stackoverflow.
I would appreciate it if you could point out any missing or incorrect parts.
I trying this
activity = Xamarin.Essentials.Platform.CurrentActivity; //<- this function is not found!
Added missing information!
The namespace of the Enable_Card function is located in hceSample.Service.
Are you using the NfcFCardEmulation.EnableService(Activity, ComponentName) Method, right?
The method is an android api from android sdk,you cannot use it directly in xamarin.form(yours is hceSample) project.
If you want to call the function in xamarin form project(hceSample) from native platform(hceSample.Android, or hceSample.iOS),you can use Xamarin.Forms DependencyService to achieve this.
The DependencyService class is a service locator that enables Xamarin.Forms applications to invoke native platform functionality from shared code.
For more information about DependencyService, you can check document Xamarin.Forms DependencyService. And there is a sample included in above document,which is helpful for you to understand DependencyService.
Note:
We recognize that hardware service is the right and ideal way to
implement in each OS project. However, I'm curious if there is a way
to code Android and iOS at the same time
Since the api you used is from android sdk, you can call it in native android or use DependencyService to call it on xamarin.form(yours is hceSample) project.
If you call it on xamarin.form(yours is hceSample) project, you also need to find the the corresponding function or interface in iOS.

How to send a form/notification to user from a DLL?

I have a DLL .
And want to send a form/notification to user( who would reference my dll) from this dll.
I just want to build a function inside one class in my dll such that ->, once a user runs his local program and references my dll -> and calls a function that is present in dll -> that particular function should show up a form/notification to user ( from some functionalities in dll )? Is there any other method for the same?
I tried converting the library to a Winform from class library type and that would change its properties into an executable and it would demand presence of the main function. But I am just building a library that can be referenced and when called by the user produces a form at their end?
I tried toast notifications but not .show() method doesnt work inside new ToastContentBuilder() while i call that in a fucntion from my library . Otherwise as an idenpendant console app , it worked fine
Is there a way I can have a project for toast notification in the same solution as that of my library and then call from a class in my main library -> the function present in this different project for toast notif and would produce the toast notification.
You can try the following steps to send a notification to the user from the dll.
First, please create a class library(Target Framework is .NET Core 3.1) called TestDll.
Second, you could install the nuget-package Microsoft.Toolkit.Uwp.Notifications in the class library.
Third, you can add a class and refer to the following code example.
namespace TestDll
{
public class Example
{
public void Setnotifications()
{
new ToastContentBuilder().AddArgument("action", "viewConversation")
.AddArgument("conversationId", 9813)
.AddText("Ev2 Compiler Library")
.AddText("Allow sending build Data to Microsoft")
.AddButton(new ToastButton()
.SetContent("Yes")
.AddArgument("action", "reply")
.SetBackgroundActivation())
.AddButton(new ToastButton()
.SetContent("No")
.AddArgument("action", "like")
.SetBackgroundActivation())
.SetToastScenario(ToastScenario.Reminder)
.Show();
}
}
}
Fourth, please rebuild the class lib and create a console app(Target Framework is .NET Core 3.1).
Fifth, we can add the project reference TestDll to the console app and write the following example in the main method.
static void Main(string[] args)
{
Example example = new Example();
example.Setnotifications();
}
Finally, we can see the notification in the right bottom of computer like the following:
Besides, the problem about 'toast notifications but not .show() method' maybe that you used .net standard framework, you can solve the problem by changing to the .net core framwork.

How can I get Android and iPhone IMEI number using Xamarin.forms

I am developing an Xamarin.forms application, I need to catch the imei number of mobile that is using the application. I am aware of how it is done in Android. But how can I do the same in Xamarin.forms. Please educate me.
There is no 'Forms-way' of doing this. If you know how on Android you can make use of the DependencyService. Which means in your shared project create an interface like:
public interface IImeiService
{
string GetImei();
}
Now in your Android project implement this interface, so it would be something like:
public class ImeiService : IImeiService
{
public string GetImei()
{
// ... Implement your Android code here
}
}
Register your Android code with an attribute on the class above the namespace
[assembly: Xamarin.Forms.Dependency (typeof (ImeiService))]
namespace ImeiApp.Droid {
You can now access it, back in your shared code, with:
var imei = DependencyService.Get<IImeiService>().GetImei();
If you would have an iOS implementation you could repeat the same steps, although you can, of course, use the same interface and call in shared code, so you will only need a iOS specific implementation.
However, since iOS 7 Apple disallows access to this kind of information programmatically, so you cannot get the IMEI number. And if you can, you will use code that will not be allowed through the App Store review process.

Java Binding: The type `...' does not exist in the namespace `...'. Are you missing an assembly?

I am trying to create a Xamarin Java Binding to the Spotify Android SDK. The SDK is now separated into two parts, one for authentication and one for the player. The former java binding works, however, the seconds gives me an error.
The original question was asked on the Xamarin Forums.
Hi,
I am trying to create a binding project for the Spotify Android SDK.
The SDK is seperated into two .aar files. One for authentication and one for media playback (Player).
Firstly I tried having both .aar files in one Binding Project, but the Player.aar was ignored. However, moving it to its own seem to work.
Now, my issue is related to the Java Interface NativePlayerNotificationCallback which is generated to IPlayerNotificationCallback (hence the lack og Notification), but in the Player class it tried to implement: global::Com.Spotify.Android.Player.INativePlayerNotificationCallback.
I can find no other mention of INativePlayerNotificationCallback in the decompiled files. Only IPlayerNotificationCallback.
I understand that this is a bit difficult to imagine. Here are the java class files seen in JD-GUI:
The generated files are listed here:
Inside the file Com.Spotify.Sdk.Android.Player.IPlayerNotificationCallback.cs:
And the error message itself
Error CS0234: The type or namespace name INativePlayerNotificationCallback' does not exist in the namespaceCom.Spotify.Sdk.Android.Player'. Are you missing an assembly reference?
I would really appreciate any insight as to how I can get this to work. It looks to me like there are some inconsistencies in the naming of the interface, but I am not sure.
Thank you for helping out,
Fredrik
Should be fixed by adding metadata to Player binding project:
<metadata>
<attr path="/api/package[#name='com.spotify.sdk.android.player']/interface[#name='NativePlayerNotificationCallback']" name="visibility">public</attr>
</metadata>
and Player class extension (into the Additions directory):
using System.Collections;
using Java.Lang;
using Java.Util.Concurrent;
namespace Com.Spotify.Sdk.Android.Player
{
public partial class Player
{
public IList InvokeAll(ICollection tasks)
{
return null;
}
public IList InvokeAll(ICollection tasks, long timeout, TimeUnit unit)
{
return null;
}
public Object InvokeAny(ICollection tasks)
{
return null;
}
public Object InvokeAny(ICollection tasks, long timeout, TimeUnit unit)
{
return null;
}
}
}
You will probably need to implement these methods correctly by calling generic methods.
Also I had to add metadata to Auth library binding project (I found it in your old topics) and referenced Auth project from Player project as it uses some of the classes (maybe that's no necessary).

Unmanaged Exports (DLLExport) crashes

I'm using RGiesecke DLLExport library to produce a C# DLL that can be dynamically loaded from legacy application built on VC6. It exported methods and they were called from VC6 code. No problems. However, as long as I tried to declare a variable as of any one of my .net classes, it crashed.
//I tried CallingConvention = CallingConvention.StdCall too
[DllExport(CallingConvention = CallingConvention.Winapi)]
static void GetDwgReferences(string fileName)
{
//OK: inialize System classes of .net
DateTime dateTime = DateTime.Now;
//crashing here: declare a variable of my static class (.net assemebly)
//SafeString safeString;
//crashing here: declare a variable of my class (.net assemebly)
//Email email;
//crashing here: initialize an object of my class (.net assemebly)
//DwgXrefs dwgXrefs = new DwgXrefs();
//crashing here by declcare a variable of third-party library (.net assemebly)
//ExSystemServices _serv;
}
What's wrong? Please help.
I had a similar problem here trying to use unmanaged exports with Metatrader to load associated managed dlls.
After some digging I think I have found the problem. The app domain is probably not where you would expect it to be, the CLR is trying to resolve your assembly but failing with a nondescript error. In my case the app domain was actually executing in the directory of the host application, so I assume this is always the case.
What I would suggest you do is build a bare dll with no dependencies, and place in something such as the following:
static void Initialize()
{
SimpleLog.WriteLog("App -" + AppDomain.CurrentDomain.BaseDirectory);
}
[DllExport("Test", CallingConvention = CallingConvention.StdCall)]
public static void Test()
{
Initialize();
}
I am not sure but I think you possibly cannot use a static constructor here?
In the log you should see the executing directory for that domain. If you put your assemblies here it (hopefully) should work. It has fixed the problem for me here. I guess the next question is can we change the domain at runtime as I might not want to put these assemblies here.
Have a google if you need the source code for a simple logger - obviously do not use a third party logging framework with dll dependencies!
I think mine is an adaptation of this one:
http://www.codeproject.com/Articles/80175/Really-Simple-Log-Writer
As the other answer stated, it is difficult to know what error C# is throwing without explicitly catching the error in a try / catch block within each method of a C# dll.
You likely need to export as CallingConvention.StdCall and additionally marshal the incoming string as an unmanaged LPWStr type:
[DllExport(CallingConvention = CallingConvention.StdCall)]
static void GetDwgReferences([MarshalAs(UnmanagedType.LPWStr)] string fileName)
{
}
Please see Code to Export C# DLL to Metatrader Build 600+ for a working example using Robert Giesecke's C# Project Template for Unmanaged Exports to export a C# dll to a legacy application (MT4).
Additionally, you might find Native and .NET Interopability interesting though it is mostly geared toward accessing native code from within .NET.

Resources