How to log in to Facebook in Xamarin.Forms - xamarin

I want to make a Xamarin.Forms project, targeting iOS, Android and Windows Phone.
My app needs to authenticate users using Facebook.
Should I implement login for each platform independently, or use a manual flow?
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0
I prefer to have a single implementation of the login flow, and use it on all platforms.
How can I get a single implementaion of the Facebook login flow?

UPDATE (10/24/17): While this way of doing things was okay a few years ago, I now strongly advocate for using native UI for doing authentication, as opposed to the webview method shown here. Auth0 is a great way to accomplish native UI login for your apps, using a wide variety of identity providers:
https://auth0.com/docs/quickstart/native/xamarin
EDIT: I finally put a sample for this on Gihub
I posted an answer on the Xamarin Forums. I'll repeat it here.
Let's start with the core of the app, the Xamarin.Forms PCL project. Your App class will look something like this:
namespace OAuth2Demo.XForms
{
public class App
{
static NavigationPage _NavPage;
public static Page GetMainPage ()
{
var profilePage = new ProfilePage();
_NavPage = new NavigationPage(profilePage);
return _NavPage;
}
public static bool IsLoggedIn {
get { return !string.IsNullOrWhiteSpace(_Token); }
}
static string _Token;
public static string Token {
get { return _Token; }
}
public static void SaveToken(string token)
{
_Token = token;
}
public static Action SuccessfulLoginAction
{
get {
return new Action (() => {
_NavPage.Navigation.PopModalAsync();
});
}
}
}
}
The first thing to notice is the GetMainPage() method. This tells the app which screen it should load first upon launching.
We also have a simple property and method for storing the Token that is returned from the auth service, as well as a simple IsLoggedIn property.
There's an Action property as well; something I stuck in here in order to have a way for the platform implementations to perform a Xamarin.Forms navigation action. More on this later.
You'll also notice some red in your IDE because we haven't created the ProfilePage class yet. So, let's do that.
Create a very simple ProfilePage class in the Xamarin.Forms PCL project. We're not even going to do anything fancy with it because that will depend on your particular need. For the sake of simplicity in this sample, it will contain a single label:
namespace OAuth2Demo.XForms
{
public class ProfilePage : BaseContentPage
{
public ProfilePage ()
{
Content = new Label () {
Text = "Profile Page",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
}
}
}
Again, you'll probably have some red in your IDE because we seem to be missing the BaseContentPage class. The sole purpose of the BaseContentPage class is to ensure that none of the app's screens can be displayed until the user has logged in. (In this simplified demo, we're just persisting the user info to memory, so you'll need to re-login every time the app is run. In a real-world app, you'd be storing the authenticated user info to the device's keychain, which would eliminate the need to login at each app start.)
Create a BaseContentPage class in the Xamarin.Forms PCL project:
namespace OAuth2Demo.XForms
{
public class BaseContentPage : ContentPage
{
protected override void OnAppearing ()
{
base.OnAppearing ();
if (!App.IsLoggedIn) {
Navigation.PushModalAsync(new LoginPage());
}
}
}
}
There's a few interesting things going on here:
We're overriding the OnAppearing() method, which is similar to the ViewWillAppear method in an iOS UIViewController. You can execute any code here that you'd like to have run immediately before the screen appears.
The only thing we're doing in this method is checking to see if the user is logged in. If they're not, then we perform a modal push to a class called LoginPage. If you're unfamiliar with the concept of a modal, it's simply a view that takes the user out of the normal application flow in order to perform some special task; in our case, to perform a login.
So, let's create the LoginPage class in the Xamarin.Forms PCL project:
namespace OAuth2Demo.XForms
{
public class LoginPage : ContentPage
{
}
}
Wait...why doesn't this class have a body???
Since we're using the Xamatin.Auth component (which does the job of building and presenting a web view that works with the provided OAuth2 info), we actually don't want any kind of implementation in our LoginPage class. I know that seems weird, but bear with me.
The LoginPageRenderer for iOS
Up until this point, we've been working solely in the Xamarin.Forms PCL project. But now we need to provide the platform-specific implementation of our LoginPage in the iOS project. This is where the concept of a Renderer comes in.
In Xamarin.Forms, when you want to provide platform-specific screens and controls (i.e. screens that do not derive their content from the abstract pages in the Xamarin.Forms PCL project), you do so with Renderers.
Create a LoginPageRenderer class in your iOS platform project:
[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
namespace OAuth2Demo.XForms.iOS
{
public class LoginPageRenderer : PageRenderer
{
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
var auth = new OAuth2Authenticator (
clientId: "", // your OAuth2 client id
scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri (""), // the auth URL for the service
redirectUrl: new Uri ("")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
// We presented the UI, so it's up to us to dimiss it on iOS.
App.SuccessfulLoginAction.Invoke();
if (eventArgs.IsAuthenticated) {
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
} else {
// The user cancelled
}
};
PresentViewController (auth.GetUI (), true, null);
}
}
}
}
There are important things to note:
The [assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))] line at the top (and importantly before the namespace declaration) is using the Xamarin.Forms DependencyService. It's not the most beautiful thing in the world because it's not IoC/DI, but whatever...it works. This is the mechanism that "maps" our LoginPageRenderer to the LoginPage.
This is the class in which we're actually using the Xamarin.Auth component. That's where the OAuth2Authenticator reference comes from.
Once the login is successful, we fire off a Xamarin.Forms navigation via App.SuccessfulLoginAction.Invoke();. This gets us back to the ProfilePage.
Since we're on iOS, we're doing all of our logic sinde of the ViewDidAppear() method.
The LoginPageRenderer for Android
Create a LoginPageRenderer class in your Android platform project. (Note that class name you're creating is identical to the one in the iOS project, but here in the Android project the PageRenderer inherits from Android classes instead of iOS classes.)
[assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))]
namespace OAuth2Demo.XForms.Android
{
public class LoginPageRenderer : PageRenderer
{
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
// this is a ViewGroup - so should be able to load an AXML file and FindView<>
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator (
clientId: "", // your OAuth2 client id
scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri (""), // the auth URL for the service
redirectUrl: new Uri ("")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
if (eventArgs.IsAuthenticated) {
App.SuccessfulLoginAction.Invoke();
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
} else {
// The user cancelled
}
};
activity.StartActivity (auth.GetUI(activity));
}
}
}
Again, let's take a look at some interesting things:
The [assembly: ExportRenderer (typeof (LoginPage), typeof (LoginPageRenderer))] line at the top (and importantly before the namespace declaration) is using the Xamarin.Forms DependencyService. No difference here from the iOS version of LoginPageRenderer.
Again, this is where we're actually using the Xamarin.Auth component. That's where the OAuth2Authenticator reference comes from.
Just as with the iOS version, once the login is successful, we fire off a Xamarin.Forms navigation via App.SuccessfulLoginAction.Invoke();. This gets us back to the ProfilePage.
Unlike the iOS version, we're doing all of the logic inside of the OnModelChanged() method instead of the ViewDidAppear().
Here it is on iOS:
...and Android:
UPDATE:
I've also provided a detailed sample at my blog: http://www.joesauve.com/using-xamarin-auth-with-xamarin-forms/

You could consume either Xamarin.Social or Xamarin.Auth for that. It allows using the same api whatever the platform is.
As of now, those libs aren't PCL yet, but you still can consume them from a Shared Assets Project, or abstract the API you need in an interface and inject in with DependencyService or any other DI container.

I've created a sample project to show how to create a Facebook login using native Facebook component, not through a webview like the solutions suggested here.
You can check it out in this address:
https://github.com/IdoTene/XamarinFormsNativeFacebook

IOS 8: For those who are using #NovaJoe code and are stuck on view, add the code bellow to workaround:
bool hasShown;
public override void ViewDidAppear(bool animated)
{
if (!hasShown)
{
hasShown = true;
// the rest of #novaJoe code
}
}

Here's a good Xamarin.Forms authentication sample. The documentation in the code is nice. It uses a webview to render the login screen, but you can select what login type you want. It also saves a users token so he doesn't have to keep re-logging in.
https://github.com/rlingineni/Xamarin.Forms_Authentication

Another addition to #NovaJoe's code, on iOS8 with Facebook, you'd need to modify the Renderer class as below to close the View after successful authentication.
auth.Completed += (sender, eventArgs) => {
// We presented the UI, so it's up to us to dimiss it on iOS.
/*Importand to add this line */
DismissViewController (true, null);
/* */
if (eventArgs.IsAuthenticated) {
App.Instance.SuccessfulLoginAction.Invoke ();
// Use eventArgs.Account to do wonderful things
App.Instance.SaveToken (eventArgs.Account.Properties ["access_token"]);
} else {
// The user cancelled
}
};

The correct implementation for the Androids PageRenderer is:
using System;
using Android.App;
using Android.Content;
using OAuth2Demo.XForms.Android;
using Xamarin.Auth;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using XamarinAuth;
[assembly: ExportRenderer(typeof(LoginPage), typeof(LoginPageRenderer))]
namespace OAuth2Demo.XForms.Android
{
public class LoginPageRenderer : PageRenderer
{
public LoginPageRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
// this is a ViewGroup - so should be able to load an AXML file and FindView<>
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "<Constants.clientId>", // your OAuth2 client id
scope: "<Constants.scope>", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri("<Constants.authorizeUrl>"), // the auth URL for the service
redirectUrl: new Uri("<Constants.redirectUrl>")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
App.SuccessfulLoginAction.Invoke();
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
}
else
{
// The user cancelled
}
};
activity.StartActivity(auth.GetUI(activity));
}
}
}

Related

How to implement an Alert box in xamarin forms android

I implemented a Dependency Service to display alert box in my xamarin forms app.My app crashes when I call the alert box in android.
Here is My code
Android.App.AlertDialog.Builder _dialog = new AlertDialog.Builder(Android.App.Application.Context);
AlertDialog _alertDialog = _dialog.Create();
_alertDialog.SetTitle("Unauthorized");
_alertDialog.SetMessage("Please login again to continue using the App);
_alertDialog.SetButton("OK", (c, ev) => { CloseApp(); });
_alertDialog.Show();
It throws an exception:-Unable to add window -- token null is not for an application in android.
How to fix this Please help me
Unable to add window -- token null is not valid; is your activity running?
You are using a Application context and you need to use an Activity based one.
So you need the current Activity's context within your Forms' dependancy class which you can obtain that via multiple methods; A static var on the MainActivity, using the "CurrentActivityPlugin", etc...
As a quick fix, add a static Context variable to your MainActivity class and set it in the OnResume override.
public static Context context;
protected override void OnResume()
{
context = this;
base.OnResume();
}
Then change your context to that static one:
Android.App.AlertDialog.Builder _dialog = new Android.App.AlertDialog.Builder(MainActivity.context);

Xamarin.iOS send data from iOS project to Notification Service Extension

In Xamarin.iOS project I am intercepting the push notification and I want to modify it before presenting to the user according to some conditions that are accessible (stored preferences) in the iOS project. How can I pass data from iOS project to the Notification Service Extension, and potentially the other way around as well? Or maybe more precisely, how can I access user preferences from the Xamarin.Forms project in the iOS Notification Service Extension project?
I am mostly interested in accessing user preferences that I stored using Xamarin.Essentials
This is the template code for the Notification Service Extension:
namespace NotifServiceExtension
{
[Register("NotificationService")]
public class NotificationService : UNNotificationServiceExtension
{
Action<UNNotificationContent> ContentHandler { get; set; }
UNMutableNotificationContent BestAttemptContent { get; set; }
protected NotificationService(IntPtr handle) : base(handle)
{
// Note: this .ctor should not contain any initialization logic.
}
public override void DidReceiveNotificationRequest(UNNotificationRequest request, Action<UNNotificationContent> contentHandler)
{
ContentHandler = contentHandler;
BestAttemptContent = (UNMutableNotificationContent)request.Content.MutableCopy();
// Modify the notification content here...
var region = Preferences.Get("region_key", "error"); // I cannot access preferences this way
BestAttemptContent.Title = string.Format("{0}[modified]", BestAttemptContent.Title);
ContentHandler(BestAttemptContent);
}
public override void TimeWillExpire()
{
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
ContentHandler(BestAttemptContent);
}
}
}
The simplest way to do this is by exposing a method on the Xamarin.Forms App class.
In the App.xaml.cs file add a new method like this:
public string GetUserRegion()
{
return Preferences.Get("region_key", "error");
}
and inside your NotificationService class you can get the region like this:
var region = (Xamarin.Forms.Application.Current as App)?.GetUserRegion();

OnAppearing different on iOS and Android

I have found that on iOS, OnAppearing is called when the page literally appears on the screen, whereas on Android, it's called when it's created.
I'm using this event to lazily construct an expensive to construct view but obviously the Android behaviour defeats this.
Is there some way of knowing on Android when a screen literally appears on the screen?
You can use the event:
this.Appearing += YourPageAppearing;
Otherwise, you should use the methods of the Application class that contains the lifecycle methods:
protected override void OnStart()
{
Debug.WriteLine ("OnStart");
}
protected override void OnSleep()
{
Debug.WriteLine ("OnSleep");
}
protected override void OnResume()
{
Debug.WriteLine ("OnResume");
}
On Android, Xamarin.Forms.Page.OnAppearing is called immediately before the page's view is shown to user (not when the page is "created" (constructed)).
If you want an initial view to appear quickly, by omitting an expensive sub-view, use a binding to make that view's IsVisible initially be "false". This will keep it out of the visual tree, avoiding most of the cost of building it. Place the (invisible) view in a grid cell, whose dimensions are constant (either in DPs or "*" - anything other than "Auto".) So that layout will be "ready" for that view, when you make it visible.
APPROACH 1:
Now you just need a binding in view model that will change IsVisible to "true".
The simplest hack is to, in OnAppearing, fire an action that will change that variable after 250 ms.
APPROACH 2:
The clean alternative is to create a custom page renderer, and override "draw".
Have draw, after calling base.draw, check an action property on your page.
If not null, invoke that action, then clear it (so only happens once).
I do this by inheriting from a custom page base class:
XAML for each of my pages (change "ContentPage" to "exodus:ExBasePage"):
<exodus:ExBasePage
xmlns:exodus="clr-namespace:Exodus;assembly=Exodus"
x:Class="YourNamespace.YourPage">
...
</exodus:ExBasePage>
xaml.cs:
using Exodus;
// After creating page, change "ContentPage" to "ExBasePage".
public partial class YourPage : ExBasePage
{
...
my custom ContentPage. NOTE: Includes code not needed for this, related to iOS Safe Area and Android hardward back button:
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace Exodus
{
public abstract partial class ExBasePage : ContentPage
{
public ExBasePage()
{
// Each sub-class calls InitializeComponent(); not needed here.
ExBasePage.SetupForLightStatusBar( this );
}
// Avoids overlapping iOS status bar at top, and sets a dark background color.
public static void SetupForLightStatusBar( ContentPage page )
{
page.On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUseSafeArea( true );
// iOS NOTE: Each ContentPage must set its BackgroundColor to black or other dark color (when using LightContent for status bar).
//page.BackgroundColor = Color.Black;
page.BackgroundColor = Color.FromRgb( 0.3, 0.3, 0.3 );
}
// Per-platform ExBasePageRenderer uses these.
public System.Action NextDrawAction;
/// <summary>
/// Override to do something else (or to do nothing, i.e. suppress back button).
/// </summary>
public virtual void OnHardwareBackButton()
{
// Normal content page; do normal back button behavior.
global::Exodus.Services.NavigatePopAsync();
}
}
}
renderer in Android project:
using System;
using Android.Content;
using Android.Views;
using Android.Graphics;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Exodus;
using Exodus.Android;
[assembly: ExportRenderer( typeof( ExBasePage ), typeof( ExBasePageRenderer ) )]
namespace Exodus.Android
{
public class ExBasePageRenderer : PageRenderer
{
public ExBasePageRenderer( Context context ) : base( context )
{
}
protected override void OnElementChanged( ElementChangedEventArgs<Page> e )
{
base.OnElementChanged( e );
var page = Element as ExBasePage;
if (page != null)
page.firstDraw = true;
}
public override void Draw( Canvas canvas )
{
try
{
base.Draw( canvas );
var page = Element as ExBasePage;
if (page?.NextDrawAction != null)
{
page.NextDrawAction();
page.NextDrawAction = null;
}
}
catch (Exception ex)
{
// TBD: Got Disposed exception on Android Bitmap, after rotating phone (in simulator).
// TODO: Log exception.
Console.WriteLine( "ExBasePageRenderer.Draw exception: " + ex.ToString() );
}
}
}
}
To do some action after the first time the page is drawn:
public partial class YourPage : ExBasePage
{
protected override void OnAppearing()
{
// TODO: OnPlatform code - I don't have it handy.
// On iOS, we call immediately "DeferredOnAppearing();"
// On Android, we set this field, and it is done in custom renderer.
NextDrawAction = DeferredOnAppearing;
}
void DeferredOnAppearing()
{
// Whatever you want to happen after page is drawn first time:
// ((MyViewModel)BindingContext).ExpensiveViewVisible = true;
// Where MyViewModel contains:
// public bool ExpensiveViewVisible { get; set; }
// And your XAML contains:
// <ExpensiveView IsVisible={Binding ExpensiveViewVisible}" ... />
}
}
NOTE: I do this differently on iOS, because Xamarin Forms on iOS (incorrectly - not to spec) calls OnAppearing AFTER the page is drawn.
So I have OnPlatform logic. On iOS, OnAppearing immediately calls DeferredOnAppearing. On Android, the line shown is done.
Hopefully iOS will eventually be fixed to call OnAppearing BEFORE,
for consistency between the two platforms.
If so, I would then add a similar renderer for iOS.
(The current iOS implementation means there is no way to update a view before it appears a SECOND time, due to popping the nav stack.
instead, it appears with outdated content, THEN you get a chance
to correct it. This is not good.)

Embedding Xamarin Forms in Native Xamarin app with MvvmCross 6.0

I'm trying to embed Forms XAML view into Xamarin Native application with MvvmCross 6.0.
I tried to reproduce effect of this solution but I got stuck on registering IMvxFormsViewPresenter. I also followed this tutorial.
I have simple MainContainerActivity with MainFragment (with corresponding MainViewModel in Core) that contains a button to Forms SettingsActivity/SettingsViewModel.
Full source can be found in the test repository.
Currently, I struggle with an exception thrown in base.OnCreate(bundle); while navigating to SettingsViewModel:
MvvmCross.Exceptions.MvxIoCResolveException has been thrown
Failed to resolve type MvvmCross.Forms.Presenters.IMvxFormsViewPresenter
I cannot find a way to register this Forms Presenter. I tried to do it in Setup but with no success.
I also tried to resolve MvxFormsAndroidViewPresenter in SplashActivity but Mvx.Resolve<IMvxViewPresenter>() as MvxFormsAndroidViewPresenter; yields null.
Do you have any idea what should I do to incorporate Forms views into MvvmCross 6.0 native application?
namespace MvvmCrossFormsEmbedding.Droid.Views
{
[Activity(Theme = "#style/AppTheme",
Label = "SettingsActivity")]
public class SettingsActivity : MvxFormsAppCompatActivity<SettingsViewModel>
{
public static SettingsActivity Instance { get; private set; }
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// #1 Initialize
Forms.Init(this, null);
SetContentView(Resource.Layout.activity_settings);
var toolbar = FindViewById<Toolbar>(Resource.Id.layout_toolbar);
SupportActionBar.Title = "Settings";
Instance = this;
// #2 Use it
var frag = new SettingsView().CreateFragment(this);
var ft = FragmentManager.BeginTransaction();
ft.Replace(Resource.Id.fragment_frame_layout, frag, "main");
ft.Commit();
}
}
}

Xamarin iOS Google Sign-in component : App crashes due to error uiDelegate must either be a |UIViewController| or implement

I'm trying to implement google sign in using this component for xamarin.ios: Google Sign-in for iOS
It works great on emulator but when it comes to actual device it's crashing once i tap signin button. (iOS 10.2 - emulator is also using same OS)
I have a custom button which calls SignInUser method on SignIn.SharedInstance
It's crashing with below error (only when the app is deployed on device)
Objective-C exception thrown. Name: NSInvalidArgumentException Reason: uiDelegate must either be a |UIViewController| or implement the |signIn:presentViewController:| and |signIn:dismissViewController:| methods from |GIDSignInUIDelegate|.
I'm calling function below to initialize GoogleSignIn on FinishedLaunching method of AppDelegate.cs
public void Configure()
{
NSError configureError;
Context.SharedInstance.Configure(out configureError);
if (configureError != null)
{
// If something went wrong, assign the clientID manually
Console.WriteLine("Error configuring the Google context: {0}", configureError);
SignIn.SharedInstance.ClientID = googleClientId;
}
SignIn.SharedInstance.Delegate = this;
SignIn.SharedInstance.UIDelegate = new GoogleSignInUIDelegate();
}
Here's my implementation of ISignInUIDelegate():
class GoogleSignInUIDelegate : SignInUIDelegate
{
public override void WillDispatch(SignIn signIn, NSError error)
{
}
public override void PresentViewController(SignIn signIn, UIViewController viewController)
{
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(viewController, true, null);
}
public override void DismissViewController(SignIn signIn, UIViewController viewController)
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
}
}
So the emulator seems to know the methods are implemented, but not the device. Any idea what i am doing wrong here?
After some debugging i found where the actual issue was.
Somehow, the UIDelegate i assigned during initialization was lost when i was calling my login method. So i moved the line below from my initialization step to login
SignIn.SharedInstance.UIDelegate = new GoogleSignInUIDelegate();
Here's how my login method looks like now:
public void Login()
{
SignIn.SharedInstance.UIDelegate = new GoogleSignInUIDelegate(); //moved this here from Configure
SignIn.SharedInstance.SignInUser();
}
This took care of the issue for me but i am still not sure why this is only an issue on the device and not the emulator. Any Ideas?
Add a PreserveAttribute to your GoogleSignInUIDelegate class to prevent the Linker from removing the methods that can not be determined via static analysis.
Add the following class to your project:
public sealed class PreserveAttribute : System.Attribute {
public bool AllMembers;
public bool Conditional;
}
Apply the class attribute:
[Preserve (AllMembers = true)]
class GoogleSignInUIDelegate : SignInUIDelegate
{
~~~~
}
Re: https://developer.xamarin.com/guides/ios/advanced_topics/linker/
Setting PresentingViewController helped me to resolve the issue.
SignIn.SharedInstance.PresentingViewController = this;
Have found such fix here:
https://github.com/googlesamples/google-signin-unity/issues/169#issuecomment-791305225

Resources