How to call AAR library methods? - xamarin

I'm trying to create a simple wrapper to Application Insights Android SDK
I build the library in Android Studio which resulted in this debug AAR file which I then added to a library binding project in Xamarin Studio.
However, when I reference it I have the namespace:
using Com.Microsoft.Applicationinsights.Library;
But it doesn't contain class ApplicationInsights which it should if it would match the java library it's wrapping.
I don't want a fancy complete CLR wrapper, I just want to call the "setup" method on that class which takes the app's Context as an argument, then be able to call simple tracking methods.

Create a new Java Binding library, add the AAR file then you can do things like:
_appInsights = JNIEnv.FindClass ("com/microsoft/applicationinsights/library/ApplicationInsights");
_methodSetup = JNIEnv.GetStaticMethodID(_appInsights, "setup",
"(Landroid/content/Context;Landroid/app/Application;Ljava/lang/String;)V");
Call setup on it:
public static void Setup(Android.Content.Context context, Android.App.Application app, String key) {
var c = new JValue(context);
var a = new JValue(app);
var s = new JValue(new Java.Lang.String(key));
JNIEnv.CallStaticVoidMethod (_appInsights, _methodSetup, c, a, s);
}

Related

How to bind service from Java library in Xamarin Android Project

I have service class implementation in Example.aar
public class DemoService : Service{}
I have created a Native binding library project.
When i tried to bind this service in Xamarin.Android project. bindService() is returning false.
var Result =context.getApplicationContext.bindService(new Intent(context,typeof(DemoService)), new ServiceConnection(),Bind.AutoCreate); //Result is false.
How to bind a service created in 3rd party library project in Xamarin Android project.??
You can refer to this article Binding a Java Library.
In the Microsoft doc, first you can get the class from the .aar file.
var ClassName = new Com.MyCompany.MyProject.MyclassName();
Then use the bindService or other methods to use the Class.
var Result =context.getApplicationContext.bindService(new Intent(context,typeof(ClassName)), new ServiceConnection(),Bind.AutoCreate);

Xamarin Unit Testing Portable Bait and Switch error with Xamarin.Auth?

I have set up a TestProject in Visual Studio for Mac that references my Xamarin Forms project for testing the non-visual portions of my code.
However I am getting the following error when I try to test a piece of my code that leverages Xamarin.Auth to access the keychain.
System.NotImplementedException :
Portable Bait And Switch is nuget feature, so the package must be installed in all project.
NotImplementedException will indicate that Portable Code from PCL is used and not Platform Specific
implementation. Please check whether platform specific Assembly is properly installed.
Cannot save account in Portable profile - bait-and-switch error.
Please file a bug in https://bugzilla.xamarin.com
This code works fine running on the iOS simulator, and I assume it has something to do with the way xamarin auth leverages the ios Keychain which is not present in this test project. I tried to add my ios solution in references, but I am unable to do so in "edit references" of my test project. The project references dialog wont permit it:
Here is the code that is failing in my PCL.
AccountStore store;
store = AccountStore.Create();
Apparently it has trouble with AccountStore.Create()
Here is the testcode class that calls the PCL:
using System;
using NUnit.Framework;
using CrowdWisdom;
using CrowdWisdom.Authentication;
namespace CrowdWisdomTest
{
[TestFixture()]
public class AuthServiceTest
{
[Test()]
public void SaveRestoreSecret()
{
String secret = "ABCD";
AuthService auth = AuthService.GetInstance();
auth.putSecret("MySecret", secret);
Assert.AreEqual(secret, auth.GetSecret("MySecret"));
}
}
}
Bait And Switch pattern that most cross-platform plugins use - is not a very unit-test friendly pattern. As you can see in your example.
My very first recommendation would be to use a contract based approach, alongwith with a dependency-injection container for your authorization process; so that you can provide a mock implementation as unit-test context. But if that is not possible, then you can use following hack to provide your own mock-switch for these static classes.
Basically, the error you see is because your portable code is accessing the portable version of Xamarin.Auth which is just intended to be the bait. So you will have to create your own implementation to act as switch in unit-test context (as they have done in platform specific libraries in Xamarin.Auth).
In order to do that, you will need to:
Create another portable library (which will only be used by your unit-test project). Let's say we name it Xamarin.Auth.Mocks. Make sure to update the root namespace, and assembly name as 'Xamarin.Auth' in its properties page.
Add a mock account store class and implement AccountStore using switch pattern.
namespace Xamarin.Auth
{
/// <summary>
/// A persistent storage for <see cref="Account"/>s. This storage is encrypted.
/// Accounts are stored using a service ID and the username of the account
/// as a primary key.
/// </summary>
#if XAMARIN_AUTH_INTERNAL
internal abstract partial class AccountStore
#else
public abstract partial class AccountStore
#endif
{
public static AccountStore Create()
{
return new MockAccountStore();
}
}
public class MockAccountStore : AccountStore
{
}
}
Add reference to Xamarin.Auth.Mocks in your unit-test library
Now every time you run your unit-tests, your portable code, will find your mock switch implementation for all their Xamarin.Auth needs, and you achieve true isolation from Xamarin.Auth; which technically is something we aspire to anyways when we write unit-test(s).
Note: If your portable code uses other bait-switch classes, add mock implementation for them too in your Xamarin.Auth.Mocks library. You only need to add mock classes for the ones that you use in your code; not all of the classes in Xamarin.Auth
I had the same issue, in my case the Xamarin.Auth version was the same (1.7.0) in all projects.
I solved the issue by editing the .csproj in this way:
<Reference Include="Xamarin.Auth, Version=1.6.0.1, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Auth.1.7.0\lib\MonoAndroid10\Xamarin.Auth.dll</HintPath>
<Private>True</Private>
</Reference>
Adding the tag <Private>True</Private> solved the issue for me.
The reference must be present and with this tag in .csproj files.

Dependency Injection Android

I am not sure how to use Dependency Injection on Xamarin Android project solution. Currently my Android solution holds a reference to another class library solution. I have used Unity on my service layer and registered the container via WebApiConfig.cs.
My question is, how do i go about using Unity on Android side in order to run on start up, would be grateful if code was included. I dont want to new-up the container through main activity of Android. I want the container to register behind the process i.e. AppStart or Global asax where it does it for you for MVC apps. Is there a way to do it for Android? Also I noticed on Main Activity I am unable to create constructor. I guess this isnt possible but how do I go about holding object reference to my Class Library solution ? example that i attempted to do:
private IExample _ex;
MainActivity(IExample ex){
_ex = ex; //depedency Injection rather than newing it up
}
public void DoSomething(){
_ex.HelloWorld();
}
Is there a way to do it via Attribute ? Also for each of my layer do I need to install and create container in order to resolve current solution dependency ? or can I use container from android which would resolve all dependency in each layer as DDD architecture goes from outer to inner ?
In terms of setting up DI at startup you can create a custom Application implementation like so:
// Must include this attribute so that Android knows we want to use this as our Application implementation
[Application(Icon = "#drawable/Icon", Label = "#string/ApplicationName")]
public class MyApplication : Application
{
public override void OnCreate()
{
base.OnCreate();
// Do your DI initialization/registration here
}
}
I'm not sure exactly what you mean by not being able to create a constructor on the main activity. You can create constructors for any activity you feel like. You don't always see it though because people tend to put their initialization logic in OnCreate.

HttpClient + gzip at PCL causes method not found: 'System.Net.Http.HttpClientHandler.ser_AutomaticDecompression'

I'm adding gzip compression support to an Xamarin.Android app where HttpClient reside in Portable Class Library (Profile49).
Every time I'm trying to make a HttpClient call I'm getting the following error:
Method not found:
'System.Net.Http.HttpClientHandler.ser_AutomaticDecompression
the code is the following:
var handler = new HttpClientHandler();
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
using (var client = new HttpClient(handler))
...
If I'm not mistaken you'll need to add a reference to the httpclient package in the project you consume your PCL in. A reference within your PCL is not going to be enough, your other projects need to reference the httpclient BCL nuget package as well.

Register a runtime dependency in Castle Windsor

In a code I'm refactoring, I have the following situation:
void Plugin(IExternalService service)
{
var facade = new Facade(
new ExternalServiceWrapper(service),
new Dependency1(),
new Dependency2());
}
Where Dependency1 and Dependency2 are implementations of IDependency1 and IDependency2.
How can I convert this to a registration within Windsor installer? I can't seem to figure our how to pass the instance of IExternalService to the container.
EDIT I'm not in control of the Plugin's creation. I'd like to use it as a composition root to wire all the dependencies.
To register an existing instance, you can use the Instance method:
container.Register(Component.For<IExternalService>().Instance(service));

Resources