Skip to content

Commit 41628b5

Browse files
[local_auth] Switch to Kotlin Pigeon (#11482)
Replaces the Java Pigeon generator with the Kotlin Pigeon generator, and adjusts the project accordingly: - Adds Kotlin build setings to Gradle. - Updates API signatures for Kotlin/Java differences. - Adds generic Java/Kotlin compat shim to create Result objects from Java, since those haven't been added to the Pigeon generator yet. - Updates tests to use constructors instead of builders, since the Kotlin generator doesn't create builders. - Updates tests to use a Java/Kotlin compat shim to read Kotlin Result values, instead of mocking the Java Pigeon response object. Part of flutter/flutter#158287 ## Pre-Review Checklist [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent 06fee7a commit 41628b5

13 files changed

Lines changed: 742 additions & 1062 deletions

File tree

packages/local_auth/local_auth_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.8
2+
3+
* Updates internal implementation to use Kotlin Pigeon.
4+
15
## 2.0.7
26

37
* Updates build files from Groovy to Kotlin.

packages/local_auth/local_auth_android/android/build.gradle.kts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
13
group = "io.flutter.plugins.localauth"
24
version = "1.0-SNAPSHOT"
35

46
buildscript {
7+
val kotlinVersion = "2.3.20"
58
repositories {
69
google()
710
mavenCentral()
811
}
912

1013
dependencies {
1114
classpath("com.android.tools.build:gradle:8.13.1")
15+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
1216
}
1317
}
1418

@@ -21,6 +25,13 @@ rootProject.allprojects {
2125

2226
plugins {
2327
id("com.android.library")
28+
id("kotlin-android")
29+
}
30+
31+
kotlin {
32+
compilerOptions {
33+
jvmTarget = JvmTarget.fromTarget(JavaVersion.VERSION_17.toString())
34+
}
2435
}
2536

2637
android {

packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
import androidx.lifecycle.DefaultLifecycleObserver;
1717
import androidx.lifecycle.Lifecycle;
1818
import androidx.lifecycle.LifecycleOwner;
19-
import io.flutter.plugins.localauth.Messages.AuthResult;
20-
import io.flutter.plugins.localauth.Messages.AuthResultCode;
2119
import java.util.concurrent.Executor;
2220

2321
/**
@@ -37,7 +35,6 @@ interface AuthCompletionHandler {
3735
private final Lifecycle lifecycle;
3836
private final FragmentActivity activity;
3937
private final AuthCompletionHandler completionHandler;
40-
private final Messages.AuthStrings strings;
4138
private final BiometricPrompt.PromptInfo promptInfo;
4239
private final boolean isAuthSticky;
4340
private final UiThreadExecutor uiThreadExecutor;
@@ -47,14 +44,13 @@ interface AuthCompletionHandler {
4744
AuthenticationHelper(
4845
Lifecycle lifecycle,
4946
FragmentActivity activity,
50-
@NonNull Messages.AuthOptions options,
51-
@NonNull Messages.AuthStrings strings,
47+
@NonNull AuthOptions options,
48+
@NonNull AuthStrings strings,
5249
@NonNull AuthCompletionHandler completionHandler,
5350
boolean allowCredentials) {
5451
this.lifecycle = lifecycle;
5552
this.activity = activity;
5653
this.completionHandler = completionHandler;
57-
this.strings = strings;
5854
this.isAuthSticky = options.getSticky();
5955
this.uiThreadExecutor = new UiThreadExecutor();
6056

@@ -157,14 +153,13 @@ public void onAuthenticationError(int errorCode, @NonNull CharSequence errString
157153
code = AuthResultCode.UNKNOWN_ERROR;
158154
break;
159155
}
160-
completionHandler.complete(
161-
new AuthResult.Builder().setCode(code).setErrorMessage(errString.toString()).build());
156+
completionHandler.complete(new AuthResult(code, errString.toString()));
162157
stop();
163158
}
164159

165160
@Override
166161
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
167-
completionHandler.complete(new AuthResult.Builder().setCode(AuthResultCode.SUCCESS).build());
162+
completionHandler.complete(new AuthResult(AuthResultCode.SUCCESS, null));
168163
stop();
169164
}
170165

packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import android.content.Context;
1212
import android.os.Build;
1313
import androidx.annotation.NonNull;
14+
import androidx.annotation.Nullable;
1415
import androidx.annotation.VisibleForTesting;
1516
import androidx.biometric.BiometricManager;
1617
import androidx.fragment.app.FragmentActivity;
@@ -20,16 +21,13 @@
2021
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
2122
import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter;
2223
import io.flutter.plugins.localauth.AuthenticationHelper.AuthCompletionHandler;
23-
import io.flutter.plugins.localauth.Messages.AuthClassification;
24-
import io.flutter.plugins.localauth.Messages.AuthOptions;
25-
import io.flutter.plugins.localauth.Messages.AuthResult;
26-
import io.flutter.plugins.localauth.Messages.AuthResultCode;
27-
import io.flutter.plugins.localauth.Messages.AuthStrings;
28-
import io.flutter.plugins.localauth.Messages.LocalAuthApi;
29-
import io.flutter.plugins.localauth.Messages.Result;
3024
import java.util.ArrayList;
3125
import java.util.List;
3226
import java.util.concurrent.atomic.AtomicBoolean;
27+
import kotlin.Result;
28+
import kotlin.Unit;
29+
import kotlin.jvm.functions.Function1;
30+
import org.jetbrains.annotations.NotNull;
3331

3432
/**
3533
* Flutter plugin providing access to local authentication.
@@ -54,17 +52,17 @@ public class LocalAuthPlugin implements FlutterPlugin, ActivityAware, LocalAuthA
5452
public LocalAuthPlugin() {}
5553

5654
@Override
57-
public @NonNull Boolean isDeviceSupported() {
55+
public boolean isDeviceSupported() {
5856
return isDeviceSecure() || canAuthenticateWithBiometrics();
5957
}
6058

6159
@Override
62-
public @NonNull Boolean deviceCanSupportBiometrics() {
60+
public boolean deviceCanSupportBiometrics() {
6361
return hasBiometricHardware();
6462
}
6563

6664
@Override
67-
public @NonNull List<AuthClassification> getEnrolledBiometrics() {
65+
public @Nullable List<AuthClassification> getEnrolledBiometrics() {
6866
if (biometricManager == null) {
6967
return null;
7068
}
@@ -81,7 +79,7 @@ public LocalAuthPlugin() {}
8179
}
8280

8381
@Override
84-
public @NonNull Boolean stopAuthentication() {
82+
public boolean stopAuthentication() {
8583
try {
8684
if (authHelper != null && authInProgress.get()) {
8785
authHelper.stopAuthentication();
@@ -98,30 +96,32 @@ public LocalAuthPlugin() {}
9896
public void authenticate(
9997
@NonNull AuthOptions options,
10098
@NonNull AuthStrings strings,
101-
@NonNull Result<AuthResult> result) {
99+
@NonNull Function1<? super @NotNull Result<@NotNull AuthResult>, @NotNull Unit> callback) {
102100
if (authInProgress.get()) {
103-
result.success(new AuthResult.Builder().setCode(AuthResultCode.ALREADY_IN_PROGRESS).build());
101+
ResultUtilsKt.completeWithValue(
102+
callback, new AuthResult(AuthResultCode.ALREADY_IN_PROGRESS, null));
104103
return;
105104
}
106105

107106
if (activity == null || activity.isFinishing()) {
108-
result.success(new AuthResult.Builder().setCode(AuthResultCode.NO_ACTIVITY).build());
107+
ResultUtilsKt.completeWithValue(callback, new AuthResult(AuthResultCode.NO_ACTIVITY, null));
109108
return;
110109
}
111110

112111
if (!(activity instanceof FragmentActivity)) {
113-
result.success(
114-
new AuthResult.Builder().setCode(AuthResultCode.NOT_FRAGMENT_ACTIVITY).build());
112+
ResultUtilsKt.completeWithValue(
113+
callback, new AuthResult(AuthResultCode.NOT_FRAGMENT_ACTIVITY, null));
115114
return;
116115
}
117116

118117
if (!isDeviceSupported()) {
119-
result.success(new AuthResult.Builder().setCode(AuthResultCode.NO_CREDENTIALS).build());
118+
ResultUtilsKt.completeWithValue(
119+
callback, new AuthResult(AuthResultCode.NO_CREDENTIALS, null));
120120
return;
121121
}
122122

123123
authInProgress.set(true);
124-
AuthCompletionHandler completionHandler = createAuthCompletionHandler(result);
124+
AuthCompletionHandler completionHandler = createAuthCompletionHandler(callback);
125125

126126
boolean allowCredentials = !options.getBiometricOnly() && canAuthenticateWithDeviceCredential();
127127

@@ -130,8 +130,8 @@ public void authenticate(
130130

131131
@VisibleForTesting
132132
public @NonNull AuthCompletionHandler createAuthCompletionHandler(
133-
@NonNull final Result<AuthResult> result) {
134-
return authResult -> onAuthenticationCompleted(result, authResult);
133+
@NonNull Function1<? super @NotNull Result<@NotNull AuthResult>, @NotNull Unit> callback) {
134+
return authResult -> onAuthenticationCompleted(callback, authResult);
135135
}
136136

137137
@VisibleForTesting
@@ -152,9 +152,11 @@ public void sendAuthenticationRequest(
152152
authHelper.authenticate();
153153
}
154154

155-
void onAuthenticationCompleted(Result<AuthResult> result, AuthResult value) {
155+
void onAuthenticationCompleted(
156+
@NonNull Function1<? super @NotNull Result<@NotNull AuthResult>, @NotNull Unit> callback,
157+
AuthResult value) {
156158
if (authInProgress.compareAndSet(true, false)) {
157-
result.success(value);
159+
ResultUtilsKt.completeWithValue(callback, value);
158160
}
159161
}
160162

@@ -192,12 +194,12 @@ public boolean canAuthenticateWithDeviceCredential() {
192194

193195
@Override
194196
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
195-
LocalAuthApi.setUp(binding.getBinaryMessenger(), this);
197+
LocalAuthApi.Companion.setUp(binding.getBinaryMessenger(), this);
196198
}
197199

198200
@Override
199201
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
200-
LocalAuthApi.setUp(binding.getBinaryMessenger(), null);
202+
LocalAuthApi.Companion.setUp(binding.getBinaryMessenger(), null);
201203
}
202204

203205
private void setServicesFromActivity(Activity activity) {

0 commit comments

Comments
 (0)