/// <summary>
        /// Bespoke method to use touch ID (or iPhone 10 FaceID)
        /// </summary>
        private void BiometricsAuth()
        {
            // throw new NotImplementedException();

            NSError error;

            var context = new LAContext();                                                              // LA Local Authentication - must declare a context for authentication (d'tell us about device capabilities &c)

            if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out error)) // can current device use biometrics?
            {
                // NB Local Authentication MUST be performed on the app's main thread https://developer.apple.com/documentation/localauthentication/logging_a_user_into_your_app_with_face_id_or_touch_id
                // Anonymous function defined for local authentication, which must be async to await EvaluatePolicyAsync
                InvokeOnMainThread(async() =>
                {
                    var result = await context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, "Login");

                    if (result.Item1)        // if on-device local biometric authentication has OK'd the user (get tuple's Item1 https://docs.microsoft.com/en-us/dotnet/api/system.tuple-1.item1?view=netframework-4.8)
                    {
                        hasLoggedIn = true;
                        PerformSegue("tabSegue", this); // once signed-in, navigate to TabsActivity with Delivered/Waiting &c tabs
                    }
                    else
                    {
                        ServerLogin();  // if user not OK'd biometrically, check credentials on server
                    }
                });
            }
            else
            {
                // If biometric local authentication not available, check credentials on server db
                ServerLogin();
            }
        }
示例#2
0
        private async Task BiometricsAuth()
        {
            var context = new LAContext();

            if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out _))
            {
                InvokeOnMainThread(async() =>
                {
                    var authenticated = await context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, "Login");

                    if (authenticated.Item1)
                    {
                        _hasLoggedIn = true;
                        PerformSegue("LoginSegue", this);
                    }
                    else
                    {
                        await TraditionalLogin();
                    }
                });
            }
            else
            {
                await  TraditionalLogin();
            }
        }
        protected override async Task <FingerprintAuthenticationResult> NativeAuthenticateAsync(AuthenticationRequestConfiguration authRequestConfig, CancellationToken cancellationToken = new CancellationToken())
        {
            var result = new FingerprintAuthenticationResult();

            SetupContextProperties(authRequestConfig);

            Tuple <bool, NSError> resTuple;

            using (cancellationToken.Register(CancelAuthentication))
            {
                var policy = GetPolicy(authRequestConfig.AllowAlternativeAuthentication);
                resTuple = await _context.EvaluatePolicyAsync(policy, authRequestConfig.Reason);
            }

            if (resTuple.Item1)
            {
                result.Status = FingerprintAuthenticationResultStatus.Succeeded;
            }
            else
            {
                // #79 simulators return null for any reason
                if (resTuple.Item2 == null)
                {
                    result.Status       = FingerprintAuthenticationResultStatus.UnknownError;
                    result.ErrorMessage = "";
                }
                else
                {
                    result = GetResultFromError(resTuple.Item2);
                }
            }

            CreateNewContext();
            return(result);
        }
示例#4
0
        private void BiometricsAuth()
        {
            NSError error;
            var     context = new LAContext();

            if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out error))
            {
                InvokeOnMainThread(async() =>
                {
                    var result = await context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, "Login");

                    if (result.Item1)
                    {
                        hasLoggedIn = true;
                        PerformSegue("loginSegue", this);
                    }
                    else
                    {
                        TraditionalLogin();
                    }
                });
            }
            else
            {
                TraditionalLogin();
            }
        }
示例#5
0
        private void BiometricAuth()
        {
            NSError error;
            var     contxt = new LAContext();

            if (contxt.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out error))
            {
                InvokeOnMainThread(async() =>
                {
                    var canLogin = await contxt.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, "Login");
                    if (canLogin.Item1)
                    {
                        isLogged = true;
                        PerformSegue("sgeLogin", this);
                    }
                    else
                    {
                        NormalLogin();
                    }
                });
            }
            else
            {
                NormalLogin();
            }
        }
示例#6
0
        /// <summary>
        ///     Authenticate the user using biometrics.
        /// </summary>
        /// <param name="ct">The <see cref="CancellationToken" /> to use.</param>
        /// <returns>A <see cref="BiometryResult" /> enum value.</returns>
        public async Task <BiometryResult> ValidateIdentity(CancellationToken ct)
        {
            var context = new LAContext();

            context.LocalizedReason        = _options.LocalizedReasonBodyText;
            context.LocalizedFallbackTitle = _options.LocalizedFallbackButtonText;
            context.LocalizedCancelTitle   = _options.LocalizedCancelButtonText;

            var capabilities = await GetCapabilities();

            if (!capabilities.PasscodeIsSet)
            {
                throw new Exception(
                          "No passcode/password is set on the device. To avoid catching this exception: call GetCapabilities() and inspect if the passcode/password is set or not before calling this method.");
            }

            if (!capabilities.IsSupported)
            {
                throw new Exception(
                          "Biometrics not available (no hardware support OR user has disabled FaceID/TouchID for the app). To avoid catching this exception: call GetCapabilities() and inspect if the biometrics is supported before calling this method.");
            }

            if (!capabilities.IsEnabled)
            {
                throw new Exception(
                          "Biometrics not enrolled (no finger xor face was added by the user). To avoid catching this exception: call GetCapabilities() and inspect if biometrics is enabled before calling this method.");
            }

            if (context.BiometryType == LABiometryType.FaceId)
            {
                // Verify that info.plist contains NSFaceIDUsageDescription key/value otherwise the app will crash
                var faceIDUsageDescription = ((NSString)NSBundle.MainBundle.InfoDictionary["NSFaceIDUsageDescription"])?.ToString();
                if (string.IsNullOrEmpty(faceIDUsageDescription))
                {
                    throw new BiometryException(0, "Please add a NSFaceIDUsageDescription key in the `Info.plist` file.");
                }
            }

            var(_, laError) = await context.EvaluatePolicyAsync(_localAuthenticationPolicy, context.LocalizedReason);

            var evaluatePolicyResult = GetAuthenticationResultFrom(laError);

            var result = new BiometryResult();

            switch (evaluatePolicyResult)
            {
            case BiometryAuthenticationResult.Granted:
                result.AuthenticationResult = BiometryAuthenticationResult.Granted;
                break;

            case BiometryAuthenticationResult.Cancelled:
                result.AuthenticationResult = BiometryAuthenticationResult.Cancelled;
                break;

            case BiometryAuthenticationResult.Denied:
                result.AuthenticationResult = BiometryAuthenticationResult.Denied;
                break;
            }
            return(result);
        }
示例#7
0
        protected override async Task <FingerprintAuthenticationResult> NativeAuthenticateAsync(AuthenticationRequestConfiguration authRequestConfig, CancellationToken cancellationToken = new CancellationToken())
        {
            var result = new FingerprintAuthenticationResult();

            SetupContextProperties(authRequestConfig);

            Tuple <bool, NSError> resTuple;

            using (cancellationToken.Register(CancelAuthentication))
            {
                var policy = GetPolicy(authRequestConfig.AllowAlternativeAuthentication);
                resTuple = await _context.EvaluatePolicyAsync(policy, authRequestConfig.Reason);
            }

            if (resTuple.Item1)
            {
                result.Status = FingerprintAuthenticationResultStatus.Succeeded;
            }
            else
            {
                switch ((LAStatus)(int)resTuple.Item2.Code)
                {
                case LAStatus.AuthenticationFailed:
                    var description = resTuple.Item2.Description;
                    if (description != null && description.Contains("retry limit exceeded"))
                    {
                        result.Status = FingerprintAuthenticationResultStatus.TooManyAttempts;
                    }
                    else
                    {
                        result.Status = FingerprintAuthenticationResultStatus.Failed;
                    }
                    break;

                case LAStatus.UserCancel:
                case LAStatus.AppCancel:
                    result.Status = FingerprintAuthenticationResultStatus.Canceled;
                    break;

                case LAStatus.UserFallback:
                    result.Status = FingerprintAuthenticationResultStatus.FallbackRequested;
                    break;

                case LAStatus.TouchIDLockout:
                    result.Status = FingerprintAuthenticationResultStatus.TooManyAttempts;
                    break;

                default:
                    result.Status = FingerprintAuthenticationResultStatus.UnknownError;
                    break;
                }

                result.ErrorMessage = resTuple.Item2.LocalizedDescription;
            }

            CreateNewContext();
            return(result);
        }
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            // Perform any additional setup after loading the view, typically from a nib.

            authenticationButton.TouchUpInside += (sender, e) =>
            {
                var context = new LAContext();
                var result  = context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthentication, "Authentication Request").GetAwaiter().GetResult();

                var can = context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out Foundation.NSError error);

                if (result.Item1)
                {
                    UserDialogs.Instance.Alert("Authentication");
                }
                else
                {
                    var code   = Convert.ToInt16(result.Item2.Code);
                    var status = (LAStatus)code;
                    UserDialogs.Instance.Alert(status.ToString());
                }
            };

            authenButton.TouchUpInside += (sender, e) =>
            {
                var context  = new LAContext();
                var myReason = new NSString("To add a new chore");

                if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out NSError AuthError))
                {
                    var replyHandler = new LAContextReplyHandler((success, error) => {
                        this.InvokeOnMainThread(() => {
                            if (success)
                            {
                                UserDialogs.Instance.Alert("Login Success");
                            }
                            else
                            {
                                //Show fallback mechanism here
                            }
                        });
                    });
                    context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, myReason, replyHandler);
                }
                ;
            };
        }
        public async Task <FingerprintAuthenticationResult> AuthenticateAsync(string reason, CancellationToken cancellationToken)
        {
            var result = new FingerprintAuthenticationResult();

            cancellationToken.Register(CancelAuthentication);

            if (!IsAvailable)
            {
                result.Status = FingerprintAuthenticationResultStatus.NotAvailable;
                return(result);
            }

            var resTuple = await _context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, reason);

            if (resTuple.Item1)
            {
                result.Status = FingerprintAuthenticationResultStatus.Succeeded;
            }
            else
            {
                switch ((LAStatus)(int)resTuple.Item2.Code)
                {
                case LAStatus.AuthenticationFailed:
                    result.Status = FingerprintAuthenticationResultStatus.Failed;
                    break;

                case LAStatus.UserCancel:
                    result.Status = FingerprintAuthenticationResultStatus.Canceled;
                    break;

                case LAStatus.UserFallback:
                    result.Status = FingerprintAuthenticationResultStatus.FallbackRequested;
                    break;

                default:
                    result.Status = FingerprintAuthenticationResultStatus.UnknownError;
                    break;
                }

                result.ErrorMessage = resTuple.Item2.LocalizedDescription;
            }

            return(result);
        }
示例#10
0
        /// <summary>
        /// Auths the on main thread.
        /// </summary>
        /// <returns>The on main thread.</returns>
        /// <param name="context">Context.</param>
        /// <param name="reason">Reason can not be null or empty</param>
        private Task <LocalAuthResult> AuthOnMainThreadAsync(LAContext context, string reason)
        {
            var tcs    = new TaskCompletionSource <LocalAuthResult>();
            var result = new LocalAuthResult(false);

            /* ==================================================================================================
             * indicate not allow null or empty reason
             * ================================================================================================*/
            if (string.IsNullOrWhiteSpace(reason))
            {
                result = new LocalAuthResult(false, "Your reason can not be null or empty");
                tcs.SetResult(result);
                return(tcs.Task);
            }

            /* ==================================================================================================
             * indicate the hardware
             * ================================================================================================*/
            if (!context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out NSError authError))
            {
                result = new LocalAuthResult(false, authError?.ToString());
                tcs.SetResult(result);
                return(tcs.Task);
            }

            /* ==================================================================================================
             * begin auth
             * ================================================================================================*/
            var nsReason     = new NSString(reason);
            var evaluateTask = context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, nsReason);

            evaluateTask.ContinueWith(t =>
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    var rs = t.Result;
                    result = new LocalAuthResult(rs.Item1, rs.Item2?.ToString());
                    tcs.SetResult(result);
                });
            });
            return(tcs.Task);
        }
        public async Task <bool> Authenticate(CancellationToken ct)
        {
            if (this.Log().IsEnabled(LogLevel.Debug))
            {
                this.Log().Debug("Authenticating the fingerprint.");
            }

            await AssertTouchIdIsEnabled(ct);

            using (await _asyncLock.LockAsync(ct))
            {
                var context = new LAContext();

                // Using LAPolicy.DeviceOwnerAuthentication will make authentication fallback on the passcode if touch id fails.
                var authenticationPolicy = _fallbackOnPasscodeAuthentication ? LAPolicy.DeviceOwnerAuthentication : LAPolicy.DeviceOwnerAuthenticationWithBiometrics;

                // Must call CanEvaluatePolicy before LAContext.BiometryType can be read
                var canEvaluatePolicy = context.CanEvaluatePolicy(authenticationPolicy, out NSError error);

                if (canEvaluatePolicy && context.BiometryType == LABiometryType.FaceId)
                {
                    // Verify that info.plist Contains NSFaceIDUsageDescription otherwise the app will crash when it tries to authenticate
                    string faceIDUsageDescription = ((NSString)NSBundle.MainBundle.InfoDictionary["NSFaceIDUsageDescription"])?.ToString();

                    if (string.IsNullOrEmpty(faceIDUsageDescription))
                    {
                        throw new MissingFieldException("Please add a NSFaceIDUsageDescription key in Info.plist");
                    }
                }

                var(result, _) = await context.EvaluatePolicyAsync(authenticationPolicy, await _description(ct));

                if (this.Log().IsEnabled(LogLevel.Information))
                {
                    this.Log().Info("Successfully authenticated the fingerprint.");
                }

                return(result);
            }
        }
示例#12
0
        public static async System.Threading.Tasks.Task Authenticate(DialogConfiguration dialogConfiguration)
        {
            _context = new LAContext();
            _context.InvokeOnMainThread(async() =>
            {
                var result    = await _context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthentication, Configuration.DefaultFailAttemptNumberExceededMsg);
                bool success  = result.Item1;
                NSError error = result.Item2;
                if (success)
                {
                    dialogConfiguration.SuccessAction?.Invoke();
                }
                else
                {
                    if (error.Code == -2)
                    {
                        //user cancel
                        return;
                    }
                    else if (error.Code == -1)
                    {
                        //too many failed attempt
                        dialogConfiguration.FailedAction?.Invoke();
                    }
                }
            });
            //NSError AuthError;

            //if (_context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError))
            //{
            //    Tuple<bool, NSError> result = await _context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, dialogConfiguration.DialogDescription);
            //    bool success = result.Item1;
            //    NSError error = result.Item2;
            //    if (result.Item1 == true)
            //        dialogConfiguration.SuccessAction?.Invoke();
            //    else
            //    {
            //        if (error.Code == -2)
            //        {
            //            //User cancel
            //            return;
            //        }else if(error.Code == -1)
            //        {

            //        }

            //        //if (error.LocalizedDescription == "Fallback authentication mechanism selected.")
            //        //{
            //        //    var s = error.Code;
            //        //    result = await _context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthentication, descrptionMessage);
            //        //    if (result.Item1)
            //        //        successAction?.Invoke();
            //        //}
            //    }
            //}
            //else
            //{

            //    _context.InvokeOnMainThread(async () =>
            //    {
            //        var result = await _context.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthentication, Configuration.DefaultFailAttemptNumberExceededMsg);
            //        if (result.Item1)
            //            dialogConfiguration.SuccessAction?.Invoke();
            //    });


            //}
        }
示例#13
0
        public override async void ViewDidLoad()
        {
            base.ViewDidLoad();

            Console.WriteLine("N0rf3n - ViewDidLoad - Begin");

            try
            {
                Console.WriteLine("N0rf3n - ViewDidLoad - Begin/Try");

                var Verifica = new LAContext();                                                                     //Context
                var myReason = new NSString("Autenticación Biométrica");
                var autoriza = await Verifica.EvaluatePolicyAsync(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, //Await, es un proceso Asyncrono y toca cambiar el  public override void  por ->  public override async void y vamos a usar la validación biometrica.
                                                                  myReason);

                if (autoriza.Item1) //el primer elemento Item1 hace refenrecia al OK y el segundo al error.
                {
                    Console.WriteLine("N0rf3n - ViewDidLoad - Ingreso App - TouchID");

                    //Se establece todo el ancho y altura de la vista de la pantalla
                    Altura            = View.Bounds.Width;
                    Ancho             = View.Bounds.Height;
                    AnchoCapaa        = Altura / 2;
                    Altura            = Ancho / 6;
                    CapaImagen        = new CALayer(); //Se define una capa nueva.
                    CapaImagen.Bounds = new CGRect(Altura / 2 - Ancho,
                                                   Ancho / 2 - Altura / 2,
                                                   AnchoCapaa,
                                                   AlturaCapa);

                    CapaImagen.Position = new CGPoint(100, 100); //Se establece una posición.
                    CapaImagen.Contents = UIImage.FromFile("Tanjiro.jpg").CGImage;
                    View.Layer.AddSublayer(CapaImagen);          //Se agrega a la vista la nueva capa
                    var Actualiza = CapaImagen.Frame;            //se obtienen los frames de la capa imagen, para obtener las coordenadas
                    Movimiento = new CMMotionManager();          //instancia nueva del movimiento.


                    if (Movimiento.AccelerometerAvailable) //Validar si el dispositivo tiene el acelerometro esta disponible
                    {
                        //Si el aceleremetro esta disposnible le vamos a definir el intervalo para estar verificando los objectos que estan en el view controller

                        Movimiento.AccelerometerUpdateInterval = 0.02;
                        Movimiento.StartAccelerometerUpdates(NSOperationQueue.CurrentQueue, (data, error) =>//Metodo para detectar el movimiento del dispositivo.
                        {
                            //Se capturan las coordenadas de la capa imagen
                            ActualizaX = CapaImagen.Frame.X;
                            ActualizaY = CapaImagen.Frame.Y;

                            if (ActualizaX + (nfloat)data.Acceleration.X * 10 > 0 &&                 //Si el acelerometro se mueve
                                ActualizaX + (nfloat)data.Acceleration.X * 10 < Altura - AnchoCapaa) //para que el objecto se mantega en la vista actual.
                            {
                                //Se actualiza la posicion.
                                Actualiza.X = ActualizaX + (nfloat)data.Acceleration.X * 10; // el objeto empieza a tener movimiento
                            }

                            if (ActualizaY + (nfloat)data.Acceleration.Y * 10 > 0 &&                //Si el acelerometro se mueve
                                ActualizaY + (nfloat)data.Acceleration.Y * 10 < Ancho - AlturaCapa) //para que el objecto se mantega en la vista actual.
                            {
                                //Se actualiza la posicion.
                                Actualiza.Y = ActualizaY + (nfloat)data.Acceleration.Y * 10; // el objeto empieza a tener movimiento

                                lblValueX.Text = data.Acceleration.X.ToString("00");
                                lblValueY.Text = data.Acceleration.Y.ToString("00");
                                lblValueZ.Text = data.Acceleration.Z.ToString("00");

                                //Se realiza la actualizaciòn de la capa imagen
                                CapaImagen.Frame = Actualiza; //la variable tiene los valores en X y Z
                            }
                        }
                                                             );
                    }
                }
                else
                {
                    // System.Threading.Thread.CurrentThread.Abort();//Salga de la venta,  la coloque en segundo plano y coloque la App en primer plano
                    Console.WriteLine("N0rf3n - ViewDidLoad - Else");
                    Thread.CurrentThread.Abort();
                }

                Console.WriteLine("N0rf3n - ViewDidLoad - End");
            }
            catch (Exception ex)
            {
                Console.WriteLine("N0rf3n - ViewDidLoad - End/Catch Error : " + ex.Message);

                var alerta = UIAlertController.Create("Estado",
                                                      ex.Message,
                                                      UIAlertControllerStyle.Alert);


                alerta.AddAction(UIAlertAction.Create("Aceptar", UIAlertActionStyle.Default, null));

                PresentViewController(alerta, true, null);
            }
        }
示例#14
0
        public override async void ViewDidLoad()
        {
            base.ViewDidLoad();
            // Perform any additional setup after loading the view, typically from a nib.

            try
            {
                var verifica = new LAContext();

                var autoriza = await verifica.EvaluatePolicyAsync
                                   (LAPolicy.
                                   DeviceOwnerAuthenticationWithBiometrics,
                                   "Autotenticacion Biometrica");

                if (autoriza.Item1)
                {
                    Altura            = View.Bounds.Width;
                    Ancho             = View.Bounds.Height;
                    AnchoCapa         = Altura / 2;
                    AlturaCapa        = Ancho / 6;
                    CapaImagen        = new CALayer();
                    CapaImagen.Bounds = new CGRect(Altura / 2 - AnchoCapa / 2, Ancho / 2 -
                                                   AlturaCapa / 2, AnchoCapa, AlturaCapa);

                    CapaImagen.Position = new CGPoint(100, 100);
                    CapaImagen.Contents = UIImage.FromFile("BolaCristal.jpg").CGImage;

                    View.Layer.AddSublayer(CapaImagen);
                    var actualiza = CapaImagen.Frame;
                    Movimiento = new CMMotionManager();

                    if (Movimiento.AccelerometerAvailable)
                    {
                        Movimiento.AccelerometerUpdateInterval = 0.02;
                        Movimiento.StartAccelerometerUpdates(NSOperationQueue.CurrentQueue, (data, error) =>
                        {
                            ActualizaX = CapaImagen.Frame.X;
                            ActualizaY = CapaImagen.Frame.Y;
                            if (ActualizaX + (nfloat)data.Acceleration.X * 10 > 0 &&
                                ActualizaX + (nfloat)data.Acceleration.X * 10 <
                                Altura - AnchoCapa)
                            {
                                actualiza.X = ActualizaX + (nfloat)
                                              data.Acceleration.X * 10;
                            }

                            if (ActualizaY + (nfloat)data.Acceleration.Y * 10 > 0 &&
                                ActualizaY + (nfloat)data.Acceleration.Y * 10 <
                                Ancho - AlturaCapa)
                            {
                                actualiza.Y = ActualizaY + (nfloat)
                                              data.Acceleration.X * 10;
                            }

                            LblX.Text        = data.Acceleration.X.ToString("0.0");
                            LblY.Text        = data.Acceleration.Y.ToString("0.0");
                            LblZ.Text        = data.Acceleration.Z.ToString("0.0");
                            CapaImagen.Frame = actualiza;
                        });
                    }
                }
                else
                {
                    System.Threading.Thread.CurrentThread.Abort();
                }
            }catch (Exception ex) {
                Alerta = UIAlertController.Create("Status", ex.Message, UIAlertControllerStyle.Alert);
                Alerta.AddAction(UIAlertAction.Create("Aceptar", UIAlertActionStyle.Default, null));
                PresentViewController(Alerta, true, null);
            }
        }
示例#15
0
        public override async void ViewDidLoad()
        {
            base.ViewDidLoad();
            var verifica = new LAContext();
            var autoriza = await verifica.EvaluatePolicyAsync
                               (LAPolicy.DeviceOwnerAuthenticationWithBiometrics,
                               "Autenticación FaceID");

            if (autoriza.Item1)
            {
                var voz = new AVSpeechUtterance("Está usted autorizado en la Aplicación, sea Bienvenido");
                voz.Voice = AVSpeechSynthesisVoice.FromLanguage("es-MX");
                habla.SpeakUtterance(voz);
                lblEstatus.Text = "Autorizado";
            }
            else
            {
                lblEstatus.Text = "No Autorizado";

                var Gravedad = new UIGravityBehavior(Imagen, btnConfirmar, btnGuardar, lblEstatus);
                var Colision = new UICollisionBehavior(Imagen, btnConfirmar, btnGuardar, lblEstatus)
                {
                    TranslatesReferenceBoundsIntoBoundary = false
                };
                var Rebote = new UIDynamicItemBehavior(btnConfirmar)
                {
                    Elasticity = 1f
                };
                Animador = new UIDynamicAnimator(View);
                Animador.AddBehaviors(Gravedad, Colision, Rebote);
                System.Threading.Thread.CurrentThread.Abort();
            }
            var Firma = new SignaturePadView(View.Frame)
            {
                StrokeWidth     = 3f,
                StrokeColor     = UIColor.Black,
                BackgroundColor = UIColor.White,
            };

            Firma.Frame                     = new CGRect(10, 500, 350, 200);
            Firma.Layer.BorderWidth         = 1f;
            Firma.SignaturePrompt.TextColor = UIColor.Blue;
            Firma.Caption.TextColor         = UIColor.White;
            Firma.Caption.Text              = "Firmar en esta zona";
            View.AddSubview(Firma);

            btnConfirmar.TouchUpInside += delegate
            {
                Imagen.Image = Firma.GetImage();
            };
            btnGuardar.TouchUpInside += delegate
            {
                var imagenfirma = Firma.GetImage();
                try
                {
                    imagenfirma.SaveToPhotosAlbum(delegate
                                                  (UIImage imagen, NSError error)
                                                  { });
                    lblEstatus.Text = "Guardado en biblioteca";
                }
                catch (Exception ex)
                {
                    lblEstatus.Text = ex.Message;
                }
            };
        }