Reverse Dependency Service - xamarin

I have a Xamarin Forms Project. I have used Dependency Service to call the Platform specific method to fire a local notification on Android and a Alert on iOS.
My problem is now, how to handle an action on both notification(android) and alert(iOS). Is it possible to call a method of the shared project from the android or iOS project?
Do I need another approach? Does someone know what I have to do?
Just for clarification, I know how the ordinary dependency services works i.e. Call a method on android or iOS from the shared project!

I believe I had a similar scenario on my app. If you want to push something from your platform methods to your PCL you would need to make use of call backs and event delegates.
In Interface PCL:
event OnMessageHandlerCallback OnMessageEvent;
event OnErrorHandlerCallBack OnErrorEvent;
In Platform specific Class inheriting interface:
private OnMessageHandlerCallback callback = null;
private OnErrorHandlerCallBack errorCallBack = null;
public event OnMessageHandlerCallback OnMessageEvent;
public event OnErrorHandlerCallBack OnErrorEvent;

Have you tried just calling the method from your native project...? No special patterns necessary. The native iOS and Android projects have a direct reference to your shared project, so it can call the method directly.

Related

Xamarin Forms - calling a shared code method from the platform project

I have read the two other questions on SO regarding this and I wanted to know if there is a good solution for that now / best practice.
Long story short, we use an SDK which is written natively and we've wrapped it so that it works on Xamarin.Android and Xamarin.iOS. It has asynchronous callback methods. I need to call a method in the shared code when a callback is received in the Android project for instance.
There's a lot of info for doing the opposite - using DependencyService. How about in my scenario? Does anyone have experience with an app like this and what's the best approach to keep code clean and do this using MVVM?
The options I know are:
Using a static App instance - this is what we currently do.
MessagingCenter
Anything else?
Actually I've never seen anyone recommend usage of MessagingCenter for anything else than communication between ViewModels so I am not sure it is recommended here. Also, I need to know the sender object type so I need a reference to the class in the platform specific project.
I would recommend you to use messagingCenter to pass data or call method between shared project and platform project. You can just send a new object instead of the class in the platform specific project.
Also, have a look at using eventhandler as I mentioned in this answer may help someone who want to call from the shared project into the platform specific one.
BTW, I mean you can even pass an object as TSender if it is not necessary to use:
MessagingCenter.Send<Object>(new object(), "Hi");
MessagingCenter.Subscribe<Object>(new object(), "Hi", (sender) =>
{
// Do something whenever the "Hi" message is received
});

Environment.System.Environment.SpecialFolder.MyDocuments Different in Xamarin.UITest than in app

I have a Xamarin Forms Project That targets iOS. I am trying to write Xamarin.UITests that depend on existence of certain files inside the /Documents folder on the device
In trying to read/write the files to the correct Folder here is what I found.
string documentBasePath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
Results From actual app :
"/Users/markwardell/Library/Developer/CoreSimulator/Devices/147FD387-FCAD-4E93-BFC7-4BC1572FF7D4/data/Containers/Data/Application/13E0B91B-8C70-4139-B570-7431DDF5B5CA/Documents"
Results From Xamarin.UITest :
"/Users/markwardell/”
Clearly I need a way of getting same result as 1..
How can I get the folder results same as app in the UITest?
The UITest project does not have access to the Xamarin.iOS SDK which is the SDK that is giving you the path from the actual app when deployed to a device or simulator. IOW, the System namespace in Xamarin.iOS's version of .NET/Mono implements some things differently depending on the platform, as is necessary in this case since the documents path is different on iOS than it is on Android, than it is on Windows, etc. So this is why the paths are different.
That said, you can get around this by using a backdoor method. See:
https://learn.microsoft.com/en-us/appcenter/test-cloud/uitest/working-with-backdoors
This allows you to call a method implemented in the iOS project itself, thereby using Xamarin.iOS SDK in that method.
You implement the backdoor method in your AppDelegate class in your iOS app project like so:
[Export("getMyDocumentsPath:")] // notice the colon at the end of the method name
public NSString GetMyDocumentsPath(NSString value)
{
// In through the backdoor - do some work.
return new NSString(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments));
}
Then call it from your UI Test project:
var path = app.Invoke("getMyDocumentsPath:", "").ToString();
Worth noting from the linked doc (in case it ever goes away):
On iOS, IApp.Invoke can call a C# method on the project's AppDelegate according to the following rules:
The method must be public.
The method must be adorned with the ExportAttribute and the name of the exposed C# method identified. The exposed name must append a : (colon) to the name. IApp.Invoke must use the iOS form of the method name.
The method must take a parameter of NSString.
The method must return NSString or void.

Call method on specific platform only

I know I can call a platform-specific method by using:
DependencyService.Get<ISomething>();
But I have a method I need to call only on one platform (Android). Instead of creating an interface and implementing it on one platform only, is there a way of calling a method in one platform?
I'm asking because creating an interface makes sense when there will be more than one implementation. But when there will be only one - I would expect there to be a simpler way of doing it.
Have you tried using Xamarin.Forms built in RuntimePlatform? For example, if you needed to do something specifically for Android only:
if (Device.RuntimePlatform == Device.Android)
{
//Call your method
}

How to call a Javascript function inside an webview on nativescript?

How to call a Javascript function (and register a callback function to be executed after the method execution from web view is done) inside an webview on nativescript?
First the bad new, nothing is "built" in to do this. This requires you to add some code to communicate back from the webview. In the nativescript-webworkers plugins that I wrote; the way I did it was I used the onJsConfirm function on Android. On iOS I used the userContentControllerDidReceiveScriptMessage callback to communicate back. If you want to develop your own code; just grab a copy of my webworkers plugin and you can see the way to do it.
Now to the good news, is that it appears there is already a plugin called "nativescript-webview-interface" which gives you this facility so you don't have to build all that binding code yourself. It looks like all you need to do is include it and you will have bi-directional communications with your webview on both iOS and Android.
Note; to see if a plugin exists in the NativeScript community; your best bet is to look on http://plugins.nativescript.rocks, that is how I found out about the above listed plugin.

Xamarin XLabs IOC and camera

I'm looking at https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/Samples/XLabs.Sample/ViewModel/CameraViewModel.cs to try and get the camera available to my app.
I have this setup the same, but when I run my app the iOS app that calls my PCL is giving the error:
IResolver has not been set. Please set it by calling Resolver.SetResolver(resolver) method.
I don't know what this means or what exact code I need. I don't use IOC at all and I don't much care about it but I just want this camera to be available to my PCL. How can I get this camera available to my PCL when I'm not using MVC here.
If you wish to use the ViewModel then modify the constructor to take in IMediaPicker:
https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/Samples/XLabs.Sample/ViewModel/CameraViewModel.cs#L62
public CameraViewModel(IMediaPicker mediaPicker)
{
this._mediaPicker = mediaPicker;
}
Remove the Setup function:
https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/Samples/XLabs.Sample/ViewModel/CameraViewModel.cs#L156-L167
How you get the IMediaPicker implementation to PCL is up to you. IoC is the preferred (and easy) way but you can use other patterns as well. One would be to define a static Func<IMediaPicker> property on the ViewModel and set it in the platform specific projects.
IoC container is the easiest and quickest way to get it done and it would as simple as adding these lines at the application startup (e.g. AppDelegate's FinishedLaunching method):
var container = new SimpleContainer();
container.Register<IMediaPicker, MediaPicker>();
Resolver.SetResolver(container.GetResolver());

Resources