Skip to content

Commit 0e6d7e0

Browse files
authored
[API breaking] Support localizedCancelTitle (iOS) and allowedAuthenticatorsOn{Enable,Authenticate} (Android) #90
ref DEV-3176 ref DEV-3177
2 parents 9cf568c + d15a34b commit 0e6d7e0

File tree

15 files changed

+421
-360
lines changed

15 files changed

+421
-360
lines changed

.github/workflows/ci.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ jobs:
2929
- run: make example-flutter-pub-get
3030
- run: make example-flutter-test
3131
- run: make example-flutter-analyze
32+
# It is extremely important that you have `pub get` run before `dart format`.
33+
# Otherwise, the result is unpredictable.
34+
# https://github.com/dart-lang/sdk/issues/60163#issuecomment-2680372038
3235
- run: make example-dart-format
3336
- run: make example-pod-install
3437
- run: make example-build-unsigned-ios-app
@@ -50,6 +53,9 @@ jobs:
5053
- run: make example-flutter-pub-get
5154
- run: make example-flutter-test
5255
- run: make example-flutter-analyze
56+
# It is extremely important that you have `pub get` run before `dart format`.
57+
# Otherwise, the result is unpredictable.
58+
# https://github.com/dart-lang/sdk/issues/60163#issuecomment-2680372038
5359
- run: make example-dart-format
5460
- run: make example-build-unsigned-android-aab
5561

@@ -68,6 +74,9 @@ jobs:
6874
- run: make sdk-flutter-pub-get
6975
- run: make sdk-flutter-test
7076
- run: make sdk-flutter-analyze
77+
# It is extremely important that you have `pub get` run before `dart format`.
78+
# Otherwise, the result is unpredictable.
79+
# https://github.com/dart-lang/sdk/issues/60163#issuecomment-2680372038
7180
- run: make sdk-dart-format
7281
# Install the latest dartdoc to avoid a bug
7382
# See DEVELOPER.md
@@ -100,6 +109,9 @@ jobs:
100109
- run: make example-flutter-pub-get
101110
- run: make example-flutter-test
102111
- run: make example-flutter-analyze
112+
# It is extremely important that you have `pub get` run before `dart format`.
113+
# Otherwise, the result is unpredictable.
114+
# https://github.com/dart-lang/sdk/issues/60163#issuecomment-2680372038
103115
- run: make example-dart-format
104116
- run: make example-pod-install
105117
- uses: authgear/gh-actions-install-apple-certificate-and-provisioning-profile@v1
@@ -140,6 +152,9 @@ jobs:
140152
- run: make example-flutter-pub-get
141153
- run: make example-flutter-test
142154
- run: make example-flutter-analyze
155+
# It is extremely important that you have `pub get` run before `dart format`.
156+
# Otherwise, the result is unpredictable.
157+
# https://github.com/dart-lang/sdk/issues/60163#issuecomment-2680372038
143158
- run: make example-dart-format
144159
- name: Build aab
145160
if: ${{ github.ref == 'refs/heads/main' }}

android/build.gradle

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ group 'com.authgear.flutter'
22
version '0.1.0'
33

44
buildscript {
5-
ext.kotlin_version = '1.6.10'
5+
ext.kotlin_version = '2.1.0'
66
repositories {
77
google()
88
mavenCentral()
99
}
1010

1111
dependencies {
12-
classpath 'com.android.tools.build:gradle:7.3.1'
12+
classpath 'com.android.tools.build:gradle:8.7.3'
1313
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1414
}
1515
}
@@ -25,29 +25,29 @@ apply plugin: 'com.android.library'
2525
apply plugin: 'kotlin-android'
2626

2727
android {
28-
compileSdkVersion 31
2928
namespace = "com.authgear.flutter"
3029

30+
compileSdk = 35
31+
3132
compileOptions {
32-
sourceCompatibility JavaVersion.VERSION_1_8
33-
targetCompatibility JavaVersion.VERSION_1_8
33+
sourceCompatibility JavaVersion.VERSION_11
34+
targetCompatibility JavaVersion.VERSION_11
3435
}
3536

3637
kotlinOptions {
37-
jvmTarget = '1.8'
38+
jvmTarget = JavaVersion.VERSION_11
3839
}
3940

4041
sourceSets {
4142
main.java.srcDirs += 'src/main/kotlin'
4243
}
4344

4445
defaultConfig {
45-
minSdkVersion 16
46+
minSdk = 16
4647
}
4748
}
4849

4950
dependencies {
50-
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
5151
implementation "androidx.core:core-ktx:1.12.0"
5252
implementation "androidx.browser:browser:1.4.0"
5353
// NOTE(backup): Please search NOTE(backup) before you update security-crypto or tink-android.

android/src/main/kotlin/com/authgear/flutter/AuthgearPlugin.kt

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,7 @@ class AuthgearPlugin: FlutterPlugin, ActivityAware, MethodCallHandler, PluginReg
198198
}
199199
"checkBiometricSupported" -> {
200200
val android = call.argument<Map<String, Any>>("android")!!
201-
val constraint = android["constraint"] as ArrayList<String>
202-
val flags = constraintToFlag(constraint)
203-
this.checkBiometricSupported(flags, result)
201+
this.checkBiometricSupported(android, result)
204202
}
205203
"createBiometricPrivateKey" -> {
206204
val kid = call.argument<String>("kid")!!
@@ -566,14 +564,17 @@ class AuthgearPlugin: FlutterPlugin, ActivityAware, MethodCallHandler, PluginReg
566564
}
567565
}
568566

569-
private fun checkBiometricSupported(flag: Int, result: Result) {
567+
private fun checkBiometricSupported(android: Map<String, Any>, result: Result) {
570568
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
571569
result.biometricAPILevel()
572570
return
573571
}
574572

573+
val allowedAuthenticatorsOnEnable = android["allowedAuthenticatorsOnEnable"] as ArrayList<String>
574+
val allowedAuthenticatorsOnEnableFlags = constraintToFlag(allowedAuthenticatorsOnEnable)
575+
575576
val manager = BiometricManager.from(pluginBinding?.applicationContext!!)
576-
val can = manager.canAuthenticate(flag)
577+
val can = manager.canAuthenticate(allowedAuthenticatorsOnEnableFlags)
577578
if (can == BiometricManager.BIOMETRIC_SUCCESS) {
578579
result.success(null)
579580
return
@@ -595,13 +596,16 @@ class AuthgearPlugin: FlutterPlugin, ActivityAware, MethodCallHandler, PluginReg
595596
return
596597
}
597598

598-
val constraint = android["constraint"] as ArrayList<String>
599+
val allowedAuthenticatorsOnEnable = android["allowedAuthenticatorsOnEnable"] as ArrayList<String>
600+
val allowedAuthenticatorsOnAuthenticate = android["allowedAuthenticatorsOnAuthenticate"] as ArrayList<String>
601+
val allowedAuthenticatorsOnEnableFlags = constraintToFlag(allowedAuthenticatorsOnEnable)
602+
val allowedAuthenticatorsOnAuthenticateFlags = constraintToFlag(allowedAuthenticatorsOnAuthenticate)
603+
599604
val invalidatedByBiometricEnrollment = android["invalidatedByBiometricEnrollment"] as Boolean
600-
val flags = constraintToFlag(constraint)
601605
val alias = "com.authgear.keys.biometric." + kid
602-
val promptInfo = buildPromptInfo(android, flags)
606+
val promptInfo = buildPromptInfo(android, allowedAuthenticatorsOnEnableFlags)
603607

604-
val spec = makeBiometricKeyPairSpec(alias, authenticatorTypesToKeyProperties(flags), invalidatedByBiometricEnrollment)
608+
val spec = makeBiometricKeyPairSpec(alias, authenticatorTypesToKeyProperties(allowedAuthenticatorsOnAuthenticateFlags), invalidatedByBiometricEnrollment)
605609

606610
try {
607611
val keyPair = createKeyPair(spec)
@@ -683,10 +687,11 @@ class AuthgearPlugin: FlutterPlugin, ActivityAware, MethodCallHandler, PluginReg
683687
return
684688
}
685689

686-
val constraint = android["constraint"] as ArrayList<String>
687-
val flags = constraintToFlag(constraint)
690+
val allowedAuthenticatorsOnAuthenticate = android["allowedAuthenticatorsOnAuthenticate"] as ArrayList<String>
691+
val allowedAuthenticatorsOnAuthenticateFlags = constraintToFlag(allowedAuthenticatorsOnAuthenticate)
692+
688693
val alias = "com.authgear.keys.biometric." + kid
689-
val promptInfo = buildPromptInfo(android, flags)
694+
val promptInfo = buildPromptInfo(android, allowedAuthenticatorsOnAuthenticateFlags)
690695

691696
try {
692697
val keyPair = getKeyPair(alias)

example/android/app/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ android {
1111
ndkVersion = flutter.ndkVersion
1212

1313
compileOptions {
14-
sourceCompatibility = JavaVersion.VERSION_1_8
15-
targetCompatibility = JavaVersion.VERSION_1_8
14+
sourceCompatibility = JavaVersion.VERSION_11
15+
targetCompatibility = JavaVersion.VERSION_11
1616
}
1717

1818
kotlinOptions {
19-
jvmTarget = JavaVersion.VERSION_1_8
19+
jvmTarget = JavaVersion.VERSION_11
2020
}
2121

2222
sourceSets {

example/lib/main.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class MyApp extends StatefulWidget {
5757

5858
final ios = BiometricOptionsIOS(
5959
localizedReason: "Use biometric to sign in",
60+
localizedCancelTitle: "Customized Cancel",
6061
constraint: BiometricAccessConstraintIOS.biometryCurrentSet,
6162
policy: BiometricLAPolicy.deviceOwnerAuthenticationWithBiometrics,
6263
);
@@ -65,8 +66,14 @@ final android = BiometricOptionsAndroid(
6566
title: "Sign in with biometric",
6667
subtitle: "Sign in securely with biometric",
6768
description: "Use your enrolled biometric to sign in",
68-
negativeButtonText: "Cancel",
69-
constraint: [BiometricAccessConstraintAndroid.biometricStrong],
69+
negativeButtonText: "Customized Cancel",
70+
allowedAuthenticatorsOnEnable: [
71+
BiometricAuthenticatorAndroid.biometricStrong
72+
],
73+
allowedAuthenticatorsOnAuthenticate: [
74+
BiometricAuthenticatorAndroid.biometricStrong,
75+
BiometricAuthenticatorAndroid.deviceCredential
76+
],
7077
invalidatedByBiometricEnrollment: true,
7178
);
7279

ios/Classes/SwiftAuthgearPlugin.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,9 +397,10 @@ public class SwiftAuthgearPlugin: NSObject, FlutterPlugin, ASWebAuthenticationPr
397397
private func checkBiometricSupported(arguments: [String: AnyObject], result: @escaping FlutterResult) {
398398
let ios = arguments["ios"] as! [String: Any]
399399
let policyString = ios["policy"] as! String
400+
let localizedCancelTitle = ios["localizedCancelTitle"] as? String
400401
if #available(iOS 11.3, *) {
401402
let policy = LAPolicy(policyString: policyString)
402-
let laContext = LAContext(policy: policy)
403+
let laContext = LAContext(policy: policy, localizedCancelTitle: localizedCancelTitle)
403404
var nsError: NSError? = nil
404405
_ = laContext.canEvaluatePolicy(policy, error: &nsError)
405406
if let nsError = nsError {
@@ -418,13 +419,14 @@ public class SwiftAuthgearPlugin: NSObject, FlutterPlugin, ASWebAuthenticationPr
418419
let ios = arguments["ios"] as! [String: Any]
419420
let constraint = ios["constraint"] as! String
420421
let localizedReason = ios["localizedReason"] as! String
422+
let localizedCancelTitle = ios["localizedCancelTitle"] as? String
421423
let policyString = ios["policy"] as! String
422424
let tag = "com.authgear.keys.biometric.\(kid)"
423425

424426
if #available(iOS 11.3, *) {
425427
let policy = LAPolicy(policyString: policyString)
426428
let flags = SecAccessControlCreateFlags(constraint: constraint)
427-
let laContext = LAContext(policy: policy)
429+
let laContext = LAContext(policy: policy, localizedCancelTitle: localizedCancelTitle)
428430
laContext.evaluatePolicy(policy, localizedReason: localizedReason) { _, error in
429431
DispatchQueue.main.async {
430432
if let error = error {
@@ -511,12 +513,13 @@ public class SwiftAuthgearPlugin: NSObject, FlutterPlugin, ASWebAuthenticationPr
511513
let payload = arguments["payload"] as! [String: Any]
512514
let ios = arguments["ios"] as! [String: Any]
513515
let localizedReason = ios["localizedReason"] as! String
516+
let localizedCancelTitle = ios["localizedCancelTitle"] as? String
514517
let policyString = ios["policy"] as! String
515518
let tag = "com.authgear.keys.biometric.\(kid)"
516519

517520
if #available(iOS 11.3, *) {
518521
let policy = LAPolicy(policyString: policyString)
519-
let laContext = LAContext(policy: policy)
522+
let laContext = LAContext(policy: policy, localizedCancelTitle: localizedCancelTitle)
520523
laContext.evaluatePolicy(policy, localizedReason: localizedReason) { _, error in
521524
DispatchQueue.main.async {
522525
if let error = error {
@@ -961,13 +964,14 @@ fileprivate extension LAPolicy {
961964
}
962965

963966
fileprivate extension LAContext {
964-
convenience init(policy: LAPolicy) {
967+
convenience init(policy: LAPolicy, localizedCancelTitle: String?) {
965968
self.init()
966969
if case .deviceOwnerAuthenticationWithBiometrics = policy {
967970
// Hide the fallback button
968971
// https://developer.apple.com/documentation/localauthentication/lacontext/1514183-localizedfallbacktitle
969972
self.localizedFallbackTitle = ""
970973
}
974+
self.localizedCancelTitle = localizedCancelTitle
971975
}
972976
}
973977

lib/flutter_authgear.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export 'src/type.dart'
2424
AuthenticationPage,
2525
SettingsPage,
2626
UserInfo,
27-
BiometricAccessConstraintAndroid,
27+
BiometricAuthenticatorAndroid,
2828
BiometricAccessConstraintIOS,
2929
BiometricOptionsAndroid,
3030
BiometricOptionsIOS,

0 commit comments

Comments
 (0)