This commit is contained in:
TJ Lambert 2022-01-24 15:29:45 -06:00
Родитель 8cd05dce4e
Коммит a4088aa640
6 изменённых файлов: 72 добавлений и 90 удалений

Просмотреть файл

@ -1,7 +1,6 @@
using LocalAuthentication;
namespace StoryboardTable;
/*
* https://developer.apple.com/ios/human-interface-guidelines/user-interaction/authentication/
*
@ -19,9 +18,9 @@ namespace StoryboardTable;
/// </remarks>
partial class AuthenticationViewController : UIViewController
{
LAContextReplyHandler replyHandler;
LAContextReplyHandler? replyHandler;
/// <summary>String to use for display</summary>
string BiometryType = "";
string BiometryType = string.Empty;
public AuthenticationViewController (IntPtr handle) : base (handle)
{
@ -32,30 +31,22 @@ partial class AuthenticationViewController : UIViewController
base.ViewWillAppear (animated);
// bind every time, to reflect deletion in the Detail view
unAuthenticatedLabel.Text = "";
unAuthenticatedLabel.Text = string.Empty;
var context = new LAContext ();
var buttonText = "";
if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out var authError1))
{ // has Biometrics (Touch or Face)
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
var buttonText = string.Empty;
if (context.CanEvaluatePolicy (LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out var authError1)) { // has Biometrics (Touch or Face)
if (UIDevice.CurrentDevice.CheckSystemVersion (11, 0)) {
context.LocalizedReason = "Authorize for access to secrets"; // iOS 11
BiometryType = context.BiometryType == LABiometryType.TouchId ? "Touch ID" : "Face ID";
buttonText = $"Login with {BiometryType}";
}
else
{ // no FaceID before iOS 11
} else { // no FaceID before iOS 11
buttonText = $"Login with Touch ID";
}
}
else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out var authError2))
{
} else if (context.CanEvaluatePolicy (LAPolicy.DeviceOwnerAuthentication, out var authError2)) {
buttonText = $"Login"; // with device PIN
BiometryType = "Device PIN";
}
else
{
} else {
// Application might choose to implement a custom username/password
buttonText = "Use unsecured";
BiometryType = "none";
@ -72,76 +63,49 @@ partial class AuthenticationViewController : UIViewController
// because LocalAuthentication APIs have been extended over time, need to check iOS version before setting some properties
context.LocalizedFallbackTitle = "Fallback"; // iOS 8
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
if (UIDevice.CurrentDevice.CheckSystemVersion (10, 0)) {
context.LocalizedCancelTitle = "Cancel"; // iOS 10
}
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIDevice.CurrentDevice.CheckSystemVersion (11, 0)) {
context.LocalizedReason = "Authorize for access to secrets"; // iOS 11
BiometryType = context.BiometryType == LABiometryType.TouchId ? "TouchID" : "FaceID";
}
//Use canEvaluatePolicy method to test if device is TouchID or FaceID enabled
//Use the LocalAuthentication Policy DeviceOwnerAuthenticationWithBiometrics
if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError))
{
Console.WriteLine("TouchID/FaceID available/enrolled");
replyHandler = new LAContextReplyHandler((success, error) =>
{
if (context.CanEvaluatePolicy (LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError)) {
replyHandler = new LAContextReplyHandler ( (success, error) => {
//Make sure it runs on MainThread, not in Background
this.InvokeOnMainThread(() =>
{
if (success)
{
Console.WriteLine($"You logged in with {BiometryType}!");
this.InvokeOnMainThread ( () => {
if (success) {
PerformSegue ("AuthenticationSegue", this);
}
else
{
Console.WriteLine(error.LocalizedDescription);
} else {
//Show fallback mechanism here
unAuthenticatedLabel.Text = $"{BiometryType} Authentication Failed";
//AuthenticateButton.Hidden = true;
}
});
});
//Use evaluatePolicy to start authentication operation and show the UI as an Alert view
//Use the LocalAuthentication Policy DeviceOwnerAuthenticationWithBiometrics
context.EvaluatePolicy (LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason, replyHandler);
}
else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out AuthError))
{
Console.WriteLine("When TouchID/FaceID aren't available or enrolled, use the device PIN");
replyHandler = new LAContextReplyHandler((success, error) =>
{
else if (context.CanEvaluatePolicy (LAPolicy.DeviceOwnerAuthentication, out AuthError)) {
replyHandler = new LAContextReplyHandler ( (success, error) => {
//Make sure it runs on MainThread, not in Background
this.InvokeOnMainThread(() =>
{
if (success)
{
Console.WriteLine($"You logged in with {BiometryType}!");
this.InvokeOnMainThread ( () => {
if (success) {
PerformSegue ("AuthenticationSegue", this);
}
else
{
Console.WriteLine(error.LocalizedDescription);
} else {
//Show fallback mechanism here
unAuthenticatedLabel.Text = "Device PIN Authentication Failed";
AuthenticateButton.Hidden = true;
}
});
});
//Use evaluatePolicy to start authentication operation and show the UI as an Alert view
//Use the LocalAuthentication Policy DeviceOwnerAuthenticationWithBiometrics
context.EvaluatePolicy (LAPolicy.DeviceOwnerAuthentication, localizedReason, replyHandler);
}
else
{
} else {
// User hasn't configured a PIN or any biometric auth.
// App may implement its own login, or choose to allow open access
unAuthenticatedLabel.Text = "No device auth configured";

Просмотреть файл

@ -2,7 +2,7 @@
public partial class DetailViewController : UIViewController
{
object detailItem;
object? detailItem;
public DetailViewController (IntPtr handle) : base (handle)
{
@ -21,7 +21,7 @@ public partial class DetailViewController : UIViewController
void ConfigureView ()
{
// Update the user interface for the detail item
if (IsViewLoaded && detailItem != null)
if (IsViewLoaded && detailItem is not null)
detailDescriptionLabel.Text = detailItem.ToString ();
}

Просмотреть файл

@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>", Scope = "member", Target = "~M:StoryboardTable.SecretTableSource.GetCell(UIKit.UITableView,Foundation.NSIndexPath)~UIKit.UITableViewCell")]

Просмотреть файл

@ -11,7 +11,7 @@ public class SecretItem {
}
public int Id { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public string Name { get; set; } = string.Empty;
public string Notes { get; set; } = string.Empty;
public bool Done { get; set; }
}

Просмотреть файл

@ -14,16 +14,26 @@ public class SecretTableSource : UITableViewSource {
}.ToArray ();
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return tableItems.Length;
}
=> tableItems.Length;
public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
// in a Storyboard, Dequeue will ALWAYS return a cell,
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
// now set the properties as normal
// Beginning in iOS 14, UITableViewCell has to use cell.ContentConfiguration
// to add text
if (UIDevice.CurrentDevice.CheckSystemVersion(14, 0)) {
var content = cell.DefaultContentConfiguration;
content.Text = tableItems[indexPath.Row].Name;
content.SecondaryText = tableItems[indexPath.Row].Notes;
cell.ContentConfiguration = content;
} else {
cell.TextLabel.Text = tableItems[indexPath.Row].Name;
cell.DetailTextLabel.Text = tableItems[indexPath.Row].Notes;
}
return cell;
}
public override void RowSelected (UITableView tableView, Foundation.NSIndexPath indexPath)