How to set ParentActivityOrWindow on Android with Xamarin Prism - android

I am rewriting my vanilla Xamarin app to use Prism Library.
The current app uses Azure ADB2C for authorisation using this framework.
Android needs to have its parent window set, which is achieved by adding this code into the MainActivity.cs of the Android project:
var authenticationService = DependencyService.Get<IAuthenticationService>();
authenticationService.SetParent(this);
This doesn't work for the Prism app, authenticationService is null. For the record, the DependencyService used here is Xamarin.Forms.DependencyService.
I also tried the example from the Prism docs and put this code into the AndroidInitializer:
public void RegisterTypes(IContainerRegistry container)
{
// Register any platform specific implementations
container.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>("B2CAuthenticationService");
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(this);
}
In this code, Container (which is a DryIoC Container) had no definition for Resolve.
For completeness, this is my App.cs RegisterTypes:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>();
...
...
}

There are a few wrong assumptions you're making here. To start you'll notice that IContainerRegistry specifically has the name Registry in it to imply we don't want you resolving types here. This is why you don't see the Resolve method on it but rather the IContainerProvider instance.
By design, Prism no longer works directly with the Xamarin.Forms DependencyService as this is a complete anti-pattern. That said if you follow the guidance for registering Platform Specific types you can see how to use the IPlatformInitializer to register platform specific types. It is important to realize here that the IPlatformInitializer is called before RegisterTypes is called in PrismApplication.
What I would suggest is to introduce a IParentWindowProvider like:
public interface IParentWindowProvider
{
object Parent { get; }
}
You can then implement this on Android like:
public class MainActivity : IPlatformInitializer, IParentWindowProvider
{
object IParentWindowProvider.Parent => this;
void IPlatformInitializer.RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterInstance<IParentWindowProvider>(this);
}
}
Then in your Application you might do something like:
protected override void OnInitialized()
{
if(Container.IsRegistered<IParentWindowProvider>())
{
var provider = Container.Resolve<IParentWindowProvider>();
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(provider.Parent);
}
}
For more info be sure to check out the relevant docs and sample
https://prismlibrary.com/docs/xamarin-forms/dependency-injection/platform-specific-services.html
https://github.com/PrismLibrary/Prism-Samples-Forms/tree/master/03-PlatformSpecificServices

Related

How to use #Subscribe annotation on Xamarin.Forms Android platform using Greenrobot.EventBus package

I am trying to implement EventBus on Xamarin but Could not able to Subscribe the Events because when I am adding the annotation #Subscribe(), I am getting an error "#Subscribe does not exist in the current context". And when I am running the Application without #Subscribe annotation, it is showing me an Error saying "MainActivity and its super classes have no public-methods with the #Subscribe annotation". Please help me on how to subscribe the Event on Xamarin Android platform
#MainActivity class:
public class MainActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
//Registering Event Bus here
EventBus.Default.Register(this);
SetContentView(Resource.Layout.activity_main);
}
#Subscribe //Showing me an error while adding this annotation
public void OnEvent(NetworkInfo networkInfo)
{
Console.WriteLine(networkInfo);
}
protected void OnDestroy()
{
base.OnDestroy();
EventBus.Default.Unregister(this);
}
}
PublisherEvent class:
public class PublishEvent
{
public PublishEvent()
{
EventBus.getDefault().post(message);
}
}
I'm not sure whether Xamarin Forms supports EventBus, and uses #Subscribe() as the same with native Android.
However, there is a same way in Xamarin Forms. You could use Xamarin.Forms MessagingCenter to achieve that, it also can subscribe the message and receive message.
Send Messaage:
MessagingCenter.Send<object>(this, "Hi");
Subscribe Message:
MessagingCenter.Subscribe<object> (this, "Hi", (sender) =>
{
// Do something whenever the "Hi" message is received
});
I was able to get Subscribe to work via Xamarin
I noticed your code here
#Subscribe //Showing me an error while adding this annotation
public void OnEvent(NetworkInfo networkInfo)
{
Console.WriteLine(networkInfo);
}
was this implemented as follows? (note the use of attributes rather than the java annotation)
[Subscribe]
public void OnEvent(NetworkInfo networkInfo)
{
Console.WriteLine(networkInfo);
}
In order for this to work, Android needs to convert the Subscribe attribute to the #Subscribe Annotation in Java. The Xamarin Binding Library should be creating SubscribeAttribute for you if you've got that project setup correctly (though it may notably be missing the ThreadMode property, I may be investigating that for myself soon!)
Anyways, this attribute won't be correctly generated if the OnEvent method isn't also generated in the corresponding Java class. I found this did not happen automatically for me so I simply needed to add [Export] to the method.
[Export]
[Subscribe]
public void OnEvent(NetworkInfo networkInfo)
{
Console.WriteLine(networkInfo);
}
This is actually (somewhat unobviously) documented here

How to create compile time library that annotates the code (as compiler) in Android

I'm trying to create a library such as retro-lambda that reads the code at edit time or compile time and provides hints for the developer.
Let's say I'm using retro-lambda library and I created an interface that has only one method:
public interface Callback{
void onResult(boolean isSuccess, Object result);
}
When I create an instance:
Callback callback = new Callback() {
public void onResult(boolean isSuccess, Object result) {
}
}
Here the retro-lambda will create a hind for the developer to use the lambda function as following:
Callback callback = (isSuccess, result) -> {
}
What do I need to learn about how to create library that inspects the code and adds hints to the user ?
For providing an IDE hint you will want to build an Android Studio plugin.
For inspecting, modifying or generating Java source code at compile-time you will want an annotation processor.

Creating platform specific code in Xamarin?

So I want to implement a twitter login into my Xamarin App, but if I follow the tutorial, the Portable App will not let me do this function:
var ui = auth.GetUI(this);
when auth is this:
var auth = new OAuth1Authenticator(
"DynVhdIjJDXXXXXXXXXXXXX",
"REvU5dCUQI4MvjV6aWwXXXXXXXXXXXXXXXXXXXXXXX",
new Uri("https://api.twitter.com/oauth/request_token"),
new Uri("https://api.twitter.com/oauth/authorize"),
new Uri("https://api.twitter.com/oauth/access_token"),
new Uri("http://twitter.com"));
So I need to add it into the Android Project, but how do I show the button from there?
Thanks for any help! :)
Based on OAuth1Authenticator and GetUI() I assume you use Xamarin.Auth.
Xamarin.Auth supports Xamarin.Forms with 2 implementations for GetUI(), so called Presenters (actually Dependency Service/Injection) and CustomRenderers. Presenters are more tested (thus more evidence of stabilty), but you can check the code in the repo.
Samples how to use Xamarin.Auth with the Xamarin.Forms:
https://github.com/moljac/Xamarin.Auth.Samples.NugetReferences/tree/master/Xamarin.Forms/Evolve16Labs
NOTE: this repo contains extracted samples from the main Xamarin.Auth repo, so the handling is easier and samples are updated more often.
Creating platform specific code in Xamarin?
You can use DependencyService to implement this function. Here is the document and example. The document explain that :
DependencyService allows apps to call into platform-specific functionality from shared code. This functionality enables Xamarin.Forms apps to do anything that a native app can do.
Create a ILogin interface in PCL :
public interface ILogin
{
void GetUI();
}
Implement the interface in Xamarin.Android :
[assembly: Xamarin.Forms.Dependency(typeof(TwitterLogin))]
namespace TwitterDemo.Droid
{
public class TwitterLogin : ILogin
{
public TwitterLogin()
{
}
public void GetUI()
{
var auth = new OAuth1Authenticator("DynVhdIjJDXXXXXXXXXXXXX", "REvU5dCUQI4MvjV6aWwXXXXXXXXXXXXXXXXXXXXXXX",
new Uri("https://api.twitter.com/oauth/request_token"),
new Uri("https://api.twitter.com/oauth/authorize"),
new Uri("https://api.twitter.com/oauth/access_token"),
new Uri("http://twitter.com"));
Intent intent = auth.GetUI(Android.App.Application.Context);
Forms.Context.StartActivity(intent);
}
}
}
Use it in Xamarin.Forms:
private void Button_Clicked(object sender, EventArgs e)
{
Xamarin.Forms.DependencyService.Register<ILogin>();
DependencyService.Get<ILogin>().GetUI();
}

Overriden MvxAndroidSetup.CreateIocProvider breaks binding with MvxBind:Error: View type not found - LinearLayout (TextView, EditText...)

I have a couple of PCLs which use Ninject for IoC. And now I am trying to create an Android Xamarin project with MvvmCross. The guide says I can follow two steps and continue using Ninject instead of MvvmCross implementation.
Here is my Setup.cs:
public class Setup : MvxAndroidSetup
{
...
protected override IMvxIoCProvider CreateIocProvider()
{
return new NinjectMvxIocProvider(... some NinjectModule[]...);
}
}
And I took the implementation of NinjectMvxIocProvider here.
It look quite okay for me, but causes this kind of output for all views that are in my layout:
MvxBind:Error: 70.85 View type not found - EditText [0:]
MvxBind:Error: 70.85 View type not found - EditText
11-02 15:56:05.872 I/mono-stdout( 4824): MvxBind:Error: 70.85 View type not found - EditText
and bindings do not work, though ViewModels are created correctly with proper service implementations.
If I remove override IMvxIoCProvider CreateIocProvider() from Setup.cs the binding works.
Is there something wrong with this implementation that I just cannot see? Maybe someone has another implementation and is ready to share?
What about doing the setup something like this?
public static class App
{
public static StandardKernel Container { get; set; }
public static void Initialize()
{
var kernel = new Ninject.StandardKernel(new NinjectDemoModule());
App.Container = kernel;
}
}
Then for resolving:
var viewModel = App.Container.Get<MainViewModel> ();
Here is a working sample: IoC Containers with Xamarin

Android - Anything similar to the iPhone SDK Delegate Callbacks?

I just switched over from iPhone to Android and am looking for something similar to where in the iPhone SDK, when a class finishes a certain task, it calls delegate methods in objects set as it's delegates.
I don't need too many details. I went through the docs and didn't find anything (the closest I got was "broadcast intents" which seem more like iOS notifications).
Even if someone can point me to the correct documentation, it would be great.
Thanks!
Never mind... found the answer here :)
http://www.javaworld.com/javaworld/javatips/jw-javatip10.html
Pasting from the article so as to preserve it:
Developers conversant in the event-driven programming model of MS-Windows and the X Window System are accustomed to passing function pointers that are invoked (that is, "called back") when something happens. Java's object-oriented model does not currently support method pointers, and thus seems to preclude using this comfortable mechanism. But all is not lost!
Java's support of interfaces provides a mechanism by which we can get the equivalent of callbacks. The trick is to define a simple interface that declares the method we wish to be invoked.
For example, suppose we want to be notified when an event happens. We can define an interface:
public interface InterestingEvent
{
// This is just a regular method so it can return something or
// take arguments if you like.
public void interestingEvent ();
}
This gives us a grip on any objects of classes that implement the interface. So, we need not concern ourselves with any other extraneous type information. This is much nicer than hacking trampoline C functions that use the data field of widgets to hold an object pointer when using C++ code with Motif.
The class that will signal the event needs to expect objects that implement the InterestingEvent interface and then invoke the interestingEvent() method as appropriate.
public class EventNotifier
{
private InterestingEvent ie;
private boolean somethingHappened;
public EventNotifier (InterestingEvent event)
{
// Save the event object for later use.
ie = event;
// Nothing to report yet.
somethingHappened = false;
}
//...
public void doWork ()
{
// Check the predicate, which is set elsewhere.
if (somethingHappened)
{
// Signal the even by invoking the interface's method.
ie.interestingEvent ();
}
//...
}
// ...
}
In that example, I used the somethingHappened predicate to track whether or not the event should be triggered. In many instances, the very fact that the method was called is enough to warrant signaling the interestingEvent().
The code that wishes to receive the event notification must implement the InterestingEvent interface and just pass a reference to itself to the event notifier.
public class CallMe implements InterestingEvent
{
private EventNotifier en;
public CallMe ()
{
// Create the event notifier and pass ourself to it.
en = new EventNotifier (this);
}
// Define the actual handler for the event.
public void interestingEvent ()
{
// Wow! Something really interesting must have occurred!
// Do something...
}
//...
}
That's all there is to it. I hope use this simple Java idiom will make your transition to Java a bit less jittery.
The pendant for kotlin.
Define your interface: In my example I scan a credit card with an external library.
interface ScanIOInterface {
fun onScannedCreditCard(creditCard: CreditCard)
}
Create a class where you can register your Activity / Fragment.
class ScanIOScanner {
var scannerInterface: ScanIOInterface? = null
fun startScanningCreditCard() {
val creditCard = Library.whichScanCreditCard() //returns CreditCard model
scannerInterface?.onScannedCreditCard(creditCard)
}
}
Implement the interface in your Activity / Fragment.
class YourClassActivity extends AppCompatActivity, ScanIOInterface {
//called when credit card was scanned
override fun onScannedCreditCard(creditCard: CreditCard) {
//do stuff with the credit card information
}
//call scanIOScanner to register your interface
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val scanIOScanner = ScanIOScanner()
scanIOScanner.scannerInterface = this
}
}
CreditCard is a model and could be define however you like. In my case it includes brand, digits, expiry date ...
After that you can call scanIOScanner.startScanningCreditCard() wherever you like.
The main content of this video tutorial is to show how to use interfaces to delegate methods / data exchange between different Fragments and activities, but it is great example to learn how delegate pattern can be implemented in Java for Android.
Java callback is not the same thing like ios delegate, in ios you can use a callback almost the same way like in Android. In Android there is startActivityForResult that can help you to implement the tasks for what ios delegate is used.
I believe ListAdapter is a example of delegation pattern in Android.
Kotlin's official Delegation pattern:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
See: https://kotlinlang.org/docs/delegation.html

Categories

Resources