@capgo/capacitor-native-biometric 6.0.3 → 7.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CapgoCapacitorNativeBiometric.podspec +1 -1
  2. package/README.md +31 -36
  3. package/android/build.gradle +7 -7
  4. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  5. package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  6. package/android/gradlew +13 -9
  7. package/android/gradlew.bat +12 -10
  8. package/android/src/main/java/ee/forgr/biometric/AuthActivity.java +49 -15
  9. package/android/src/main/java/ee/forgr/biometric/NativeBiometric.java +56 -53
  10. package/dist/docs.json +57 -43
  11. package/dist/esm/definitions.d.ts +7 -0
  12. package/dist/esm/definitions.js.map +1 -1
  13. package/dist/esm/web.js +4 -0
  14. package/dist/esm/web.js.map +1 -1
  15. package/dist/plugin.cjs.js +4 -0
  16. package/dist/plugin.cjs.js.map +1 -1
  17. package/dist/plugin.js +4 -0
  18. package/dist/plugin.js.map +1 -1
  19. package/ios/Plugin/Plugin.swift +9 -1
  20. package/ios/Plugin.xcodeproj/project.pbxproj +4 -12
  21. package/ios/Podfile +1 -1
  22. package/package.json +49 -42
  23. package/ios/Plugin/Plugin.h +0 -10
  24. package/ios/Plugin/Plugin.m +0 -12
  25. package/ios/Podfile.lock +0 -22
  26. package/ios/Pods/Local Podspecs/Capacitor.podspec.json +0 -31
  27. package/ios/Pods/Local Podspecs/CapacitorCordova.podspec.json +0 -29
  28. package/ios/Pods/Manifest.lock +0 -22
  29. package/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -1610
  30. package/ios/Pods/Target Support Files/Capacitor/Capacitor-Info.plist +0 -26
  31. package/ios/Pods/Target Support Files/Capacitor/Capacitor-dummy.m +0 -5
  32. package/ios/Pods/Target Support Files/Capacitor/Capacitor-prefix.pch +0 -12
  33. package/ios/Pods/Target Support Files/Capacitor/Capacitor-umbrella.h +0 -23
  34. package/ios/Pods/Target Support Files/Capacitor/Capacitor.debug.xcconfig +0 -16
  35. package/ios/Pods/Target Support Files/Capacitor/Capacitor.modulemap +0 -8
  36. package/ios/Pods/Target Support Files/Capacitor/Capacitor.release.xcconfig +0 -16
  37. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-Info.plist +0 -26
  38. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-dummy.m +0 -5
  39. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-prefix.pch +0 -12
  40. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova-umbrella.h +0 -32
  41. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.debug.xcconfig +0 -13
  42. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.modulemap +0 -6
  43. package/ios/Pods/Target Support Files/CapacitorCordova/CapacitorCordova.release.xcconfig +0 -13
  44. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-Info.plist +0 -26
  45. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.markdown +0 -53
  46. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-acknowledgements.plist +0 -91
  47. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-dummy.m +0 -5
  48. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin-umbrella.h +0 -16
  49. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.debug.xcconfig +0 -14
  50. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.modulemap +0 -6
  51. package/ios/Pods/Target Support Files/Pods-Plugin/Pods-Plugin.release.xcconfig +0 -14
  52. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-Info.plist +0 -26
  53. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.markdown +0 -53
  54. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-acknowledgements.plist +0 -91
  55. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-dummy.m +0 -5
  56. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-frameworks.sh +0 -188
  57. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests-umbrella.h +0 -16
  58. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.debug.xcconfig +0 -15
  59. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.modulemap +0 -6
  60. package/ios/Pods/Target Support Files/Pods-PluginTests/Pods-PluginTests.release.xcconfig +0 -15
@@ -8,6 +8,6 @@
8
8
  s.author = 'Martin Donadieu'
9
9
  s.source = { :git => 'https://github.com/Cap-go/capacitor-native-biometric', :tag => s.version.to_s }
10
10
  s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
11
- s.ios.deployment_target = '13.0'
11
+ s.ios.deployment_target = '14.0'
12
12
  s.dependency 'Capacitor'
13
13
  end
package/README.md CHANGED
@@ -92,7 +92,7 @@ This is a plugin specific list of error codes that can be thrown on verifyIdenti
92
92
  ### isAvailable(...)
93
93
 
94
94
  ```typescript
95
- isAvailable(options?: IsAvailableOptions | undefined) => any
95
+ isAvailable(options?: IsAvailableOptions | undefined) => Promise<AvailableResult>
96
96
  ```
97
97
 
98
98
  Checks if biometric authentication hardware is available.
@@ -101,7 +101,7 @@ Checks if biometric authentication hardware is available.
101
101
  | ------------- | ----------------------------------------------------------------- |
102
102
  | **`options`** | <code><a href="#isavailableoptions">IsAvailableOptions</a></code> |
103
103
 
104
- **Returns:** <code>any</code>
104
+ **Returns:** <code>Promise&lt;<a href="#availableresult">AvailableResult</a>&gt;</code>
105
105
 
106
106
  **Since:** 1.0.0
107
107
 
@@ -111,7 +111,7 @@ Checks if biometric authentication hardware is available.
111
111
  ### verifyIdentity(...)
112
112
 
113
113
  ```typescript
114
- verifyIdentity(options?: BiometricOptions | undefined) => any
114
+ verifyIdentity(options?: BiometricOptions | undefined) => Promise<void>
115
115
  ```
116
116
 
117
117
  Prompts the user to authenticate with biometrics.
@@ -120,8 +120,6 @@ Prompts the user to authenticate with biometrics.
120
120
  | ------------- | ------------------------------------------------------------- |
121
121
  | **`options`** | <code><a href="#biometricoptions">BiometricOptions</a></code> |
122
122
 
123
- **Returns:** <code>any</code>
124
-
125
123
  **Since:** 1.0.0
126
124
 
127
125
  --------------------
@@ -130,7 +128,7 @@ Prompts the user to authenticate with biometrics.
130
128
  ### getCredentials(...)
131
129
 
132
130
  ```typescript
133
- getCredentials(options: GetCredentialOptions) => any
131
+ getCredentials(options: GetCredentialOptions) => Promise<Credentials>
134
132
  ```
135
133
 
136
134
  Gets the stored credentials for a given server.
@@ -139,7 +137,7 @@ Gets the stored credentials for a given server.
139
137
  | ------------- | --------------------------------------------------------------------- |
140
138
  | **`options`** | <code><a href="#getcredentialoptions">GetCredentialOptions</a></code> |
141
139
 
142
- **Returns:** <code>any</code>
140
+ **Returns:** <code>Promise&lt;<a href="#credentials">Credentials</a>&gt;</code>
143
141
 
144
142
  **Since:** 1.0.0
145
143
 
@@ -149,7 +147,7 @@ Gets the stored credentials for a given server.
149
147
  ### setCredentials(...)
150
148
 
151
149
  ```typescript
152
- setCredentials(options: SetCredentialOptions) => any
150
+ setCredentials(options: SetCredentialOptions) => Promise<void>
153
151
  ```
154
152
 
155
153
  Stores the given credentials for a given server.
@@ -158,8 +156,6 @@ Stores the given credentials for a given server.
158
156
  | ------------- | --------------------------------------------------------------------- |
159
157
  | **`options`** | <code><a href="#setcredentialoptions">SetCredentialOptions</a></code> |
160
158
 
161
- **Returns:** <code>any</code>
162
-
163
159
  **Since:** 1.0.0
164
160
 
165
161
  --------------------
@@ -168,7 +164,7 @@ Stores the given credentials for a given server.
168
164
  ### deleteCredentials(...)
169
165
 
170
166
  ```typescript
171
- deleteCredentials(options: DeleteCredentialOptions) => any
167
+ deleteCredentials(options: DeleteCredentialOptions) => Promise<void>
172
168
  ```
173
169
 
174
170
  Deletes the stored credentials for a given server.
@@ -177,8 +173,6 @@ Deletes the stored credentials for a given server.
177
173
  | ------------- | --------------------------------------------------------------------------- |
178
174
  | **`options`** | <code><a href="#deletecredentialoptions">DeleteCredentialOptions</a></code> |
179
175
 
180
- **Returns:** <code>any</code>
181
-
182
176
  **Since:** 1.0.0
183
177
 
184
178
  --------------------
@@ -187,13 +181,6 @@ Deletes the stored credentials for a given server.
187
181
  ### Interfaces
188
182
 
189
183
 
190
- #### IsAvailableOptions
191
-
192
- | Prop | Type | Description |
193
- | ----------------- | -------------------- | ----------------------------------------------------------------------------------------------------- |
194
- | **`useFallback`** | <code>boolean</code> | Specifies if should fallback to passcode authentication if biometric authentication is not available. |
195
-
196
-
197
184
  #### AvailableResult
198
185
 
199
186
  | Prop | Type |
@@ -203,25 +190,26 @@ Deletes the stored credentials for a given server.
203
190
  | **`errorCode`** | <code>number</code> |
204
191
 
205
192
 
206
- #### BiometricOptions
193
+ #### IsAvailableOptions
207
194
 
208
- | Prop | Type | Description | Default |
209
- | ------------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
210
- | **`reason`** | <code>string</code> | | |
211
- | **`title`** | <code>string</code> | | |
212
- | **`subtitle`** | <code>string</code> | | |
213
- | **`description`** | <code>string</code> | | |
214
- | **`negativeButtonText`** | <code>string</code> | | |
215
- | **`useFallback`** | <code>boolean</code> | Specifies if should fallback to passcode authentication if biometric authentication fails. | |
216
- | **`fallbackTitle`** | <code>string</code> | Only for iOS. Set the text for the fallback button in the authentication dialog. If this property is not specified, the default text is set by the system. | |
217
- | **`maxAttempts`** | <code>number</code> | Only for Android. Set a maximum number of attempts for biometric authentication. The maximum allowed by android is 5. | <code>1</code> |
195
+ | Prop | Type | Description |
196
+ | ----------------- | -------------------- | ----------------------------------------------------------------------------------------------------- |
197
+ | **`useFallback`** | <code>boolean</code> | Specifies if should fallback to passcode authentication if biometric authentication is not available. |
218
198
 
219
199
 
220
- #### GetCredentialOptions
200
+ #### BiometricOptions
221
201
 
222
- | Prop | Type |
223
- | ------------ | ------------------- |
224
- | **`server`** | <code>string</code> |
202
+ | Prop | Type | Description | Default |
203
+ | -------------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
204
+ | **`reason`** | <code>string</code> | | |
205
+ | **`title`** | <code>string</code> | | |
206
+ | **`subtitle`** | <code>string</code> | | |
207
+ | **`description`** | <code>string</code> | | |
208
+ | **`negativeButtonText`** | <code>string</code> | | |
209
+ | **`useFallback`** | <code>boolean</code> | Specifies if should fallback to passcode authentication if biometric authentication fails. | |
210
+ | **`fallbackTitle`** | <code>string</code> | Only for iOS. Set the text for the fallback button in the authentication dialog. If this property is not specified, the default text is set by the system. | |
211
+ | **`maxAttempts`** | <code>number</code> | Only for Android. Set a maximum number of attempts for biometric authentication. The maximum allowed by android is 5. | <code>1</code> |
212
+ | **`allowedBiometryTypes`** | <code>BiometryType[]</code> | Only for Android. Specify which biometry types are allowed for authentication. If not specified, all available types will be allowed. | |
225
213
 
226
214
 
227
215
  #### Credentials
@@ -232,6 +220,13 @@ Deletes the stored credentials for a given server.
232
220
  | **`password`** | <code>string</code> |
233
221
 
234
222
 
223
+ #### GetCredentialOptions
224
+
225
+ | Prop | Type |
226
+ | ------------ | ------------------- |
227
+ | **`server`** | <code>string</code> |
228
+
229
+
235
230
  #### SetCredentialOptions
236
231
 
237
232
  | Prop | Type |
@@ -306,7 +301,7 @@ public class MainActivity extends BridgeActivity {
306
301
  ## Contributors
307
302
 
308
303
  [Jonthia](https://github.com/jonthia)
309
- [One Click Web Studio](https://github.com/oneclickwebstudio)
304
+ [QliQ.dev](https://github.com/qliqdev)
310
305
  [Brian Weasner](https://github.com/brian-weasner)
311
306
  [Mohamed Diarra](https://github.com/mohdiarra)
312
307
  ### Want to Contribute?
@@ -1,8 +1,8 @@
1
1
  ext {
2
2
  junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
- androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5'
4
- androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1'
5
- androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
3
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
4
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
5
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
6
6
  }
7
7
 
8
8
  buildscript {
@@ -11,7 +11,7 @@ buildscript {
11
11
  mavenCentral()
12
12
  }
13
13
  dependencies {
14
- classpath 'com.android.tools.build:gradle:8.2.1'
14
+ classpath 'com.android.tools.build:gradle:8.7.2'
15
15
  }
16
16
  }
17
17
 
@@ -19,10 +19,10 @@ apply plugin: 'com.android.library'
19
19
 
20
20
  android {
21
21
  namespace "ee.forgr.biometric.capacitornativebiometric"
22
- compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
22
+ compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
23
23
  defaultConfig {
24
- minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
25
- targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
26
26
  versionCode 1
27
27
  versionName "1.0"
28
28
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -1,6 +1,6 @@
1
1
  distributionBase=GRADLE_USER_HOME
2
2
  distributionPath=wrapper/dists
3
- distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
3
+ distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
4
4
  networkTimeout=10000
5
5
  validateDistributionUrl=true
6
6
  zipStoreBase=GRADLE_USER_HOME
package/android/gradlew CHANGED
@@ -15,6 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
  #
18
+ # SPDX-License-Identifier: Apache-2.0
19
+ #
18
20
 
19
21
  ##############################################################################
20
22
  #
@@ -55,7 +57,7 @@
55
57
  # Darwin, MinGW, and NonStop.
56
58
  #
57
59
  # (3) This script is generated from the Groovy template
58
- # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
60
+ # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59
61
  # within the Gradle project.
60
62
  #
61
63
  # You can find Gradle at https://github.com/gradle/gradle/.
@@ -83,7 +85,9 @@ done
83
85
  # This is normally unused
84
86
  # shellcheck disable=SC2034
85
87
  APP_BASE_NAME=${0##*/}
86
- APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
88
+ # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
89
+ APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
90
+ ' "$PWD" ) || exit
87
91
 
88
92
  # Use the maximum available, or set MAX_FD != -1 to use that value.
89
93
  MAX_FD=maximum
@@ -144,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144
148
  case $MAX_FD in #(
145
149
  max*)
146
150
  # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
147
- # shellcheck disable=SC3045
151
+ # shellcheck disable=SC2039,SC3045
148
152
  MAX_FD=$( ulimit -H -n ) ||
149
153
  warn "Could not query maximum file descriptor limit"
150
154
  esac
@@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
152
156
  '' | soft) :;; #(
153
157
  *)
154
158
  # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
155
- # shellcheck disable=SC3045
159
+ # shellcheck disable=SC2039,SC3045
156
160
  ulimit -n "$MAX_FD" ||
157
161
  warn "Could not set maximum file descriptor limit to $MAX_FD"
158
162
  esac
@@ -201,11 +205,11 @@ fi
201
205
  # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
202
206
  DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
203
207
 
204
- # Collect all arguments for the java command;
205
- # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
206
- # shell script including quotes and variable substitutions, so put them in
207
- # double quotes to make sure that they get re-expanded; and
208
- # * put everything else in single quotes, so that it's not re-expanded.
208
+ # Collect all arguments for the java command:
209
+ # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
210
+ # and any embedded shellness will be escaped.
211
+ # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
212
+ # treated as '${Hostname}' itself on the command line.
209
213
 
210
214
  set -- \
211
215
  "-Dorg.gradle.appname=$APP_BASE_NAME" \
@@ -13,6 +13,8 @@
13
13
  @rem See the License for the specific language governing permissions and
14
14
  @rem limitations under the License.
15
15
  @rem
16
+ @rem SPDX-License-Identifier: Apache-2.0
17
+ @rem
16
18
 
17
19
  @if "%DEBUG%"=="" @echo off
18
20
  @rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
43
45
  %JAVA_EXE% -version >NUL 2>&1
44
46
  if %ERRORLEVEL% equ 0 goto execute
45
47
 
46
- echo.
47
- echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48
- echo.
49
- echo Please set the JAVA_HOME variable in your environment to match the
50
- echo location of your Java installation.
48
+ echo. 1>&2
49
+ echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50
+ echo. 1>&2
51
+ echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52
+ echo location of your Java installation. 1>&2
51
53
 
52
54
  goto fail
53
55
 
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57
59
 
58
60
  if exist "%JAVA_EXE%" goto execute
59
61
 
60
- echo.
61
- echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62
- echo.
63
- echo Please set the JAVA_HOME variable in your environment to match the
64
- echo location of your Java installation.
62
+ echo. 1>&2
63
+ echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64
+ echo. 1>&2
65
+ echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66
+ echo location of your Java installation. 1>&2
65
67
 
66
68
  goto fail
67
69
 
@@ -6,13 +6,14 @@ import android.os.Bundle;
6
6
  import android.os.Handler;
7
7
  import androidx.annotation.NonNull;
8
8
  import androidx.appcompat.app.AppCompatActivity;
9
+ import androidx.biometric.BiometricManager;
9
10
  import androidx.biometric.BiometricPrompt;
10
11
  import ee.forgr.biometric.capacitornativebiometric.R;
12
+ import java.util.Objects;
11
13
  import java.util.concurrent.Executor;
12
14
 
13
15
  public class AuthActivity extends AppCompatActivity {
14
16
 
15
- private Executor executor;
16
17
  private int maxAttempts;
17
18
  private int counter = 0;
18
19
 
@@ -23,6 +24,7 @@ public class AuthActivity extends AppCompatActivity {
23
24
 
24
25
  maxAttempts = getIntent().getIntExtra("maxAttempts", 1);
25
26
 
27
+ Executor executor;
26
28
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
27
29
  executor = this.getMainExecutor();
28
30
  } else {
@@ -38,7 +40,7 @@ public class AuthActivity extends AppCompatActivity {
38
40
  new BiometricPrompt.PromptInfo.Builder()
39
41
  .setTitle(
40
42
  getIntent().hasExtra("title")
41
- ? getIntent().getStringExtra("title")
43
+ ? Objects.requireNonNull(getIntent().getStringExtra("title"))
42
44
  : "Authenticate"
43
45
  )
44
46
  .setSubtitle(
@@ -53,18 +55,30 @@ public class AuthActivity extends AppCompatActivity {
53
55
  );
54
56
 
55
57
  boolean useFallback = getIntent().getBooleanExtra("useFallback", false);
58
+ int[] allowedTypes = getIntent().getIntArrayExtra("allowedBiometryTypes");
56
59
 
57
- if (useFallback) {
58
- // TODO: Deprecated function, probably want to migrate to `setAllowedAuthenticators`
59
- builder.setDeviceCredentialAllowed(true);
60
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
61
+ int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG;
62
+ if (useFallback) {
63
+ authenticators |= BiometricManager.Authenticators.DEVICE_CREDENTIAL;
64
+ }
65
+ if (allowedTypes != null) {
66
+ // Filter authenticators based on allowed types
67
+ authenticators = getAllowedAuthenticators(allowedTypes);
68
+ }
69
+ builder.setAllowedAuthenticators(authenticators);
60
70
  } else {
61
- // Note that this option is incompatible with device credential authentication and must NOT be set if the latter is enabled via `setAllowedAuthenticators` or `setDeviceCredentialAllowed`.
62
- // @see https://developer.android.com/reference/androidx/biometric/BiometricPrompt.PromptInfo.Builder#setNegativeButtonText(java.lang.CharSequence)
63
- builder.setNegativeButtonText(
64
- getIntent().hasExtra("negativeButtonText")
65
- ? getIntent().getStringExtra("negativeButtonText")
66
- : "Cancel"
67
- );
71
+ if (useFallback) {
72
+ builder.setDeviceCredentialAllowed(true);
73
+ } else {
74
+ builder.setNegativeButtonText(
75
+ getIntent().hasExtra("negativeButtonText")
76
+ ? Objects.requireNonNull(
77
+ getIntent().getStringExtra("negativeButtonText")
78
+ )
79
+ : "Cancel"
80
+ );
81
+ }
68
82
  }
69
83
 
70
84
  BiometricPrompt.PromptInfo promptInfo = builder.build();
@@ -90,7 +104,7 @@ public class AuthActivity extends AppCompatActivity {
90
104
  @NonNull BiometricPrompt.AuthenticationResult result
91
105
  ) {
92
106
  super.onAuthenticationSucceeded(result);
93
- finishActivity("success");
107
+ finishActivity();
94
108
  }
95
109
 
96
110
  @Override
@@ -109,8 +123,8 @@ public class AuthActivity extends AppCompatActivity {
109
123
  biometricPrompt.authenticate(promptInfo);
110
124
  }
111
125
 
112
- void finishActivity(String result) {
113
- finishActivity(result, null, null);
126
+ void finishActivity() {
127
+ finishActivity("success", null, null);
114
128
  }
115
129
 
116
130
  void finishActivity(String result, Integer errorCode, String errorDetails) {
@@ -158,4 +172,24 @@ public class AuthActivity extends AppCompatActivity {
158
172
  return 0;
159
173
  }
160
174
  }
175
+
176
+ private int getAllowedAuthenticators(int[] allowedTypes) {
177
+ int authenticators = 0;
178
+ for (int type : allowedTypes) {
179
+ switch (type) {
180
+ case 3: // FINGERPRINT
181
+ authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
182
+ break;
183
+ case 4: // FACE_AUTHENTICATION
184
+ authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
185
+ break;
186
+ case 5: // IRIS_AUTHENTICATION
187
+ authenticators |= BiometricManager.Authenticators.BIOMETRIC_STRONG;
188
+ break;
189
+ }
190
+ }
191
+ return authenticators > 0
192
+ ? authenticators
193
+ : BiometricManager.Authenticators.BIOMETRIC_STRONG;
194
+ }
161
195
  }
@@ -15,6 +15,7 @@ import android.security.keystore.StrongBoxUnavailableException;
15
15
  import android.util.Base64;
16
16
  import androidx.activity.result.ActivityResult;
17
17
  import androidx.biometric.BiometricManager;
18
+ import com.getcapacitor.JSArray;
18
19
  import com.getcapacitor.JSObject;
19
20
  import com.getcapacitor.Plugin;
20
21
  import com.getcapacitor.PluginCall;
@@ -24,6 +25,7 @@ import com.getcapacitor.annotation.CapacitorPlugin;
24
25
  import java.io.ByteArrayInputStream;
25
26
  import java.io.ByteArrayOutputStream;
26
27
  import java.io.IOException;
28
+ import java.nio.charset.StandardCharsets;
27
29
  import java.security.GeneralSecurityException;
28
30
  import java.security.InvalidAlgorithmParameterException;
29
31
  import java.security.InvalidKeyException;
@@ -37,6 +39,7 @@ import java.security.SecureRandom;
37
39
  import java.security.UnrecoverableEntryException;
38
40
  import java.security.cert.CertificateException;
39
41
  import java.util.ArrayList;
42
+ import java.util.Objects;
40
43
  import javax.crypto.Cipher;
41
44
  import javax.crypto.CipherInputStream;
42
45
  import javax.crypto.CipherOutputStream;
@@ -44,6 +47,7 @@ import javax.crypto.KeyGenerator;
44
47
  import javax.crypto.NoSuchPaddingException;
45
48
  import javax.crypto.spec.GCMParameterSpec;
46
49
  import javax.crypto.spec.SecretKeySpec;
50
+ import org.json.JSONException;
47
51
 
48
52
  @CapacitorPlugin(name = "NativeBiometric")
49
53
  public class NativeBiometric extends Plugin {
@@ -144,7 +148,7 @@ public class NativeBiometric extends Plugin {
144
148
  }
145
149
 
146
150
  @PluginMethod
147
- public void verifyIdentity(final PluginCall call) {
151
+ public void verifyIdentity(final PluginCall call) throws JSONException {
148
152
  Intent intent = new Intent(getContext(), AuthActivity.class);
149
153
 
150
154
  intent.putExtra("title", call.getString("title", "Authenticate"));
@@ -168,6 +172,16 @@ public class NativeBiometric extends Plugin {
168
172
  intent.putExtra("maxAttempts", call.getInt("maxAttempts"));
169
173
  }
170
174
 
175
+ // Pass allowed biometry types
176
+ JSArray allowedTypes = call.getArray("allowedBiometryTypes");
177
+ if (allowedTypes != null) {
178
+ int[] types = new int[allowedTypes.length()];
179
+ for (int i = 0; i < allowedTypes.length(); i++) {
180
+ types[i] = (int) allowedTypes.toList().get(i);
181
+ }
182
+ intent.putExtra("allowedBiometryTypes", types);
183
+ }
184
+
171
185
  boolean useFallback = Boolean.TRUE.equals(
172
186
  call.getBoolean("useFallback", false)
173
187
  );
@@ -255,7 +269,7 @@ public class NativeBiometric extends Plugin {
255
269
  if (result.getResultCode() == Activity.RESULT_OK) {
256
270
  Intent data = result.getData();
257
271
  if (data != null && data.hasExtra("result")) {
258
- switch (data.getStringExtra("result")) {
272
+ switch (Objects.requireNonNull(data.getStringExtra("result"))) {
259
273
  case "success":
260
274
  call.resolve();
261
275
  break;
@@ -309,18 +323,15 @@ public class NativeBiometric extends Plugin {
309
323
  private String encryptString(String stringToEncrypt, String KEY_ALIAS)
310
324
  throws GeneralSecurityException, IOException {
311
325
  Cipher cipher;
312
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
313
- cipher = Cipher.getInstance(TRANSFORMATION);
314
- cipher.init(
315
- Cipher.ENCRYPT_MODE,
316
- getKey(KEY_ALIAS),
317
- new GCMParameterSpec(128, FIXED_IV)
318
- );
319
- } else {
320
- cipher = Cipher.getInstance(AES_MODE, "BC");
321
- cipher.init(Cipher.ENCRYPT_MODE, getKey(KEY_ALIAS));
322
- }
323
- byte[] encodedBytes = cipher.doFinal(stringToEncrypt.getBytes("UTF-8"));
326
+ cipher = Cipher.getInstance(TRANSFORMATION);
327
+ cipher.init(
328
+ Cipher.ENCRYPT_MODE,
329
+ getKey(KEY_ALIAS),
330
+ new GCMParameterSpec(128, FIXED_IV)
331
+ );
332
+ byte[] encodedBytes = cipher.doFinal(
333
+ stringToEncrypt.getBytes(StandardCharsets.UTF_8)
334
+ );
324
335
  return Base64.encodeToString(encodedBytes, Base64.DEFAULT);
325
336
  }
326
337
 
@@ -329,19 +340,14 @@ public class NativeBiometric extends Plugin {
329
340
  byte[] encryptedData = Base64.decode(stringToDecrypt, Base64.DEFAULT);
330
341
 
331
342
  Cipher cipher;
332
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
333
- cipher = Cipher.getInstance(TRANSFORMATION);
334
- cipher.init(
335
- Cipher.DECRYPT_MODE,
336
- getKey(KEY_ALIAS),
337
- new GCMParameterSpec(128, FIXED_IV)
338
- );
339
- } else {
340
- cipher = Cipher.getInstance(AES_MODE, "BC");
341
- cipher.init(Cipher.DECRYPT_MODE, getKey(KEY_ALIAS));
342
- }
343
+ cipher = Cipher.getInstance(TRANSFORMATION);
344
+ cipher.init(
345
+ Cipher.DECRYPT_MODE,
346
+ getKey(KEY_ALIAS),
347
+ new GCMParameterSpec(128, FIXED_IV)
348
+ );
343
349
  byte[] decryptedData = cipher.doFinal(encryptedData);
344
- return new String(decryptedData, "UTF-8");
350
+ return new String(decryptedData, StandardCharsets.UTF_8);
345
351
  }
346
352
 
347
353
  @SuppressLint("NewAPI") // API level is already checked
@@ -358,30 +364,31 @@ public class NativeBiometric extends Plugin {
358
364
 
359
365
  private Key generateKey(String KEY_ALIAS, boolean isStrongBoxBacked)
360
366
  throws GeneralSecurityException, IOException, StrongBoxUnavailableException {
361
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
362
- KeyGenerator generator = KeyGenerator.getInstance(
363
- KeyProperties.KEY_ALGORITHM_AES,
364
- ANDROID_KEY_STORE
365
- );
366
- KeyGenParameterSpec.Builder paramBuilder =
367
- new KeyGenParameterSpec.Builder(
368
- KEY_ALIAS,
369
- KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
370
- )
371
- .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
372
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
373
- .setRandomizedEncryptionRequired(false);
374
-
375
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
367
+ KeyGenerator generator = KeyGenerator.getInstance(
368
+ KeyProperties.KEY_ALGORITHM_AES,
369
+ ANDROID_KEY_STORE
370
+ );
371
+ KeyGenParameterSpec.Builder paramBuilder = new KeyGenParameterSpec.Builder(
372
+ KEY_ALIAS,
373
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
374
+ )
375
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
376
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
377
+ .setRandomizedEncryptionRequired(false);
378
+
379
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
380
+ if (
381
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
382
+ Build.VERSION.SDK_INT > 34
383
+ ) {
384
+ // Avoiding setUnlockedDeviceRequired(true) due to known issues on Android 12-14
376
385
  paramBuilder.setUnlockedDeviceRequired(true);
377
- paramBuilder.setIsStrongBoxBacked(isStrongBoxBacked);
378
386
  }
379
-
380
- generator.init(paramBuilder.build());
381
- return generator.generateKey();
382
- } else {
383
- return getAESKey(KEY_ALIAS);
387
+ paramBuilder.setIsStrongBoxBacked(isStrongBoxBacked);
384
388
  }
389
+
390
+ generator.init(paramBuilder.build());
391
+ return generator.generateKey();
385
392
  }
386
393
 
387
394
  private Key getKey(String KEY_ALIAS)
@@ -485,7 +492,7 @@ public class NativeBiometric extends Plugin {
485
492
 
486
493
  byte[] bytes = new byte[values.size()];
487
494
  for (int i = 0; i < bytes.length; i++) {
488
- bytes[i] = values.get(i).byteValue();
495
+ bytes[i] = values.get(i);
489
496
  }
490
497
  return bytes;
491
498
  }
@@ -494,10 +501,6 @@ public class NativeBiometric extends Plugin {
494
501
  KeyguardManager keyguardManager = (KeyguardManager) getActivity()
495
502
  .getSystemService(Context.KEYGUARD_SERVICE);
496
503
  // Can only use fallback if the device has a pin/pattern/password lockscreen.
497
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
498
- return keyguardManager.isDeviceSecure();
499
- } else {
500
- return keyguardManager.isKeyguardSecure();
501
- }
504
+ return keyguardManager.isDeviceSecure();
502
505
  }
503
506
  }