diff --git a/packages/local_auth/local_auth/lib/src/local_auth.dart b/packages/local_auth/local_auth/lib/src/local_auth.dart index 9046743dd5d398d8f4f0de62eab0f2c697046c1c..20c33701a89b446e9f314849d256b5841887e4e8 100644 --- a/packages/local_auth/local_auth/lib/src/local_auth.dart +++ b/packages/local_auth/local_auth/lib/src/local_auth.dart @@ -15,6 +15,7 @@ import 'package:local_auth_android/local_auth_android.dart'; import 'package:local_auth_darwin/local_auth_darwin.dart'; import 'package:local_auth_platform_interface/local_auth_platform_interface.dart'; import 'package:local_auth_windows/local_auth_windows.dart'; +import 'package:local_auth_ohos/local_auth_ohos.dart'; /// A Flutter plugin for authenticating the user identity locally. class LocalAuthentication { @@ -41,7 +42,8 @@ class LocalAuthentication { Iterable authMessages = const [ IOSAuthMessages(), AndroidAuthMessages(), - WindowsAuthMessages() + WindowsAuthMessages(), + OhosAuthMessages() ], AuthenticationOptions options = const AuthenticationOptions()}) { return LocalAuthPlatform.instance.authenticate( diff --git a/packages/local_auth/local_auth/pubspec.yaml b/packages/local_auth/local_auth/pubspec.yaml index 0527dddb7ffeea726af8fb05a9afbe211b24af4d..c553b99d71d6cf16510fa47deff104c0cba1b8ff 100644 --- a/packages/local_auth/local_auth/pubspec.yaml +++ b/packages/local_auth/local_auth/pubspec.yaml @@ -20,6 +20,8 @@ flutter: default_package: local_auth_darwin windows: default_package: local_auth_windows + ohos: + default_package: local_auth_ohos dependencies: flutter: @@ -28,6 +30,10 @@ dependencies: local_auth_darwin: ^1.4.0 local_auth_platform_interface: ^1.0.1 local_auth_windows: ^1.0.0 + local_auth_ohos: + git: + url: "https://gitee.com/openharmony-sig/flutter_packages.git" + path: "packages/local_auth/local_auth_ohos" dev_dependencies: flutter_test: diff --git a/packages/local_auth/local_auth_ohos/.gitignore b/packages/local_auth/local_auth_ohos/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7ec225305d1580562b9856e4c9e0488a2ea19b63 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/.gitignore @@ -0,0 +1,51 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +pubspec.lock +GeneratedPluginRegistrant* +ohos/**/oh_modules +ohos/**.har +ohos/**/BuildProfile.ets +ohos/**/oh-package-lock.json5 \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/AUTHORS b/packages/local_auth/local_auth_ohos/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..54d96d2b314204b862f67d8a9daa5e7d2a3a1d33 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/AUTHORS @@ -0,0 +1,80 @@ +# Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +The Chromium Authors +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> +Bodhi Mulders diff --git a/packages/local_auth/local_auth_ohos/CHANGELOG.md b/packages/local_auth/local_auth_ohos/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..b74748c3f2e992990311f9c9577cb48b1e7135a2 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/CHANGELOG.md @@ -0,0 +1,92 @@ +## NEXT + +* Updates compileSdkVersion to 33. + +## 1.0.19 + +* Updates links for the merge of flutter/plugins into flutter/packages. + +## 1.0.18 + +* Updates minimum Flutter version to 3.0. +* Updates androidx.core version to 1.9.0. +* Upgrades compile SDK version to 33. + +## 1.0.17 + +* Adds compatibility with `intl` 0.18.0. + +## 1.0.16 + +* Updates androidx.fragment version to 1.5.5. + +## 1.0.15 + +* Updates androidx.fragment version to 1.5.4. + +## 1.0.14 + +* Fixes device credential authentication for API versions before R. + +## 1.0.13 + +* Updates imports for `prefer_relative_imports`. + +## 1.0.12 + +* Updates androidx.fragment version to 1.5.2. +* Updates minimum Flutter version to 2.10. + +## 1.0.11 + +* Fixes avoid_redundant_argument_values lint warnings and minor typos. + +## 1.0.10 + +* Updates `local_auth_platform_interface` constraint to the correct minimum + version. + +## 1.0.9 + +* Updates androidx.fragment version to 1.5.1. + +## 1.0.8 + +* Removes usages of `FingerprintManager` and other `BiometricManager` deprecated method usages. + +## 1.0.7 + +* Updates gradle version to 7.2.1. + +## 1.0.6 + +* Updates androidx.core version to 1.8.0. + +## 1.0.5 + +* Updates references to the obsolete master branch. + +## 1.0.4 + +* Minor fixes for new analysis options. + +## 1.0.3 + +* Removes unnecessary imports. +* Fixes library_private_types_in_public_api, sort_child_properties_last and use_key_in_widget_constructors + lint warnings. + +## 1.0.2 + +* Fixes `getEnrolledBiometrics` to match documented behaviour: + Present biometrics that are not enrolled are no longer returned. +* `getEnrolledBiometrics` now only returns `weak` and `strong` biometric types. +* `deviceSupportsBiometrics` now returns the correct value regardless of enrollment state. + +## 1.0.1 + +* Adopts `Object.hash`. + +## 1.0.0 + +* Initial release from migration to federated architecture. diff --git a/packages/local_auth/local_auth_ohos/LICENSE b/packages/local_auth/local_auth_ohos/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..c6823b81eb845db89cee59cbbc7ee0b0b63d86ec --- /dev/null +++ b/packages/local_auth/local_auth_ohos/LICENSE @@ -0,0 +1,25 @@ +Copyright 2013 The Flutter Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/local_auth/local_auth_ohos/README.md b/packages/local_auth/local_auth_ohos/README.md new file mode 100644 index 0000000000000000000000000000000000000000..07244912f23100f3bcecc6c38ccfa4a7a1e86237 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/README.md @@ -0,0 +1,11 @@ +# local\_auth\_android + +The Android implementation of [`local_auth`][1]. + +## Usage + +This package is [endorsed][2], which means you can simply use `local_auth` +normally. This package will be automatically included in your app when you do. + +[1]: https://pub.dev/packages/local_auth +[2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/lib/main.dart b/packages/local_auth/local_auth_ohos/example/lib/main.dart new file mode 100644 index 0000000000000000000000000000000000000000..23abdda0ed5d73188b673fa31ef6720e8dfc13fb --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/lib/main.dart @@ -0,0 +1,247 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs, avoid_print + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:local_auth_ohos/local_auth_ohos.dart'; +import 'package:local_auth_platform_interface/local_auth_platform_interface.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + _SupportState _supportState = _SupportState.unknown; + bool? _deviceSupportsBiometrics; + List? _enrolledBiometrics; + String _authorized = 'Not Authorized'; + bool _isAuthenticating = false; + + @override + void initState() { + super.initState(); + LocalAuthPlatform.instance.isDeviceSupported().then( + (bool isSupported) => setState(() => _supportState = isSupported + ? _SupportState.supported + : _SupportState.unsupported), + ); + } + + Future _checkBiometrics() async { + late bool deviceSupportsBiometrics; + try { + deviceSupportsBiometrics = + await LocalAuthPlatform.instance.deviceSupportsBiometrics(); + } on PlatformException catch (e) { + deviceSupportsBiometrics = false; + print(e); + } + if (!mounted) { + return; + } + + setState(() { + _deviceSupportsBiometrics = deviceSupportsBiometrics; + }); + } + + Future _getEnrolledBiometrics() async { + late List availableBiometrics; + try { + availableBiometrics = + await LocalAuthPlatform.instance.getEnrolledBiometrics(); + } on PlatformException catch (e) { + availableBiometrics = []; + print(e); + } + if (!mounted) { + return; + } + + setState(() { + _enrolledBiometrics = availableBiometrics; + }); + } + + Future _authenticate() async { + bool authenticated = false; + try { + setState(() { + _isAuthenticating = true; + _authorized = 'Authenticating'; + }); + authenticated = await LocalAuthPlatform.instance.authenticate( + localizedReason: 'Let OS determine authentication method', + authMessages: [const OhosAuthMessages()], + options: const AuthenticationOptions( + stickyAuth: true, + ), + ); + setState(() { + _isAuthenticating = false; + }); + } on PlatformException catch (e) { + print(e); + setState(() { + _isAuthenticating = false; + _authorized = 'Error - ${e.message}'; + }); + return; + } + if (!mounted) { + return; + } + + setState( + () => _authorized = authenticated ? 'Authorized' : 'Not Authorized'); + } + + Future _authenticateWithBiometrics() async { + bool authenticated = false; + try { + setState(() { + _isAuthenticating = true; + _authorized = 'Authenticating'; + }); + authenticated = await LocalAuthPlatform.instance.authenticate( + localizedReason: + 'Scan your fingerprint (or face or whatever) to authenticate', + authMessages: [const OhosAuthMessages()], + options: const AuthenticationOptions( + stickyAuth: true, + biometricOnly: true, + ), + ); + setState(() { + _isAuthenticating = false; + _authorized = 'Authenticating'; + }); + } on PlatformException catch (e) { + print(e); + setState(() { + _isAuthenticating = false; + _authorized = 'Error - ${e.message}'; + }); + return; + } + if (!mounted) { + return; + } + + final String message = authenticated ? 'Authorized' : 'Not Authorized'; + setState(() { + _authorized = message; + }); + } + + Future _cancelAuthentication() async { + bool result = await LocalAuthPlatform.instance.stopAuthentication(); + setState(() { + _isAuthenticating = !result; + _authorized = result ? 'Not Authorized' : 'Authorized'; + }); + + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + ), + body: ListView( + padding: const EdgeInsets.only(top: 30), + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (_supportState == _SupportState.unknown) + const CircularProgressIndicator() + else if (_supportState == _SupportState.supported) + const Text('This device is supported') + else + const Text('This device is not supported'), + const Divider(height: 100), + Text( + 'Device supports biometrics: $_deviceSupportsBiometrics\n'), + ElevatedButton( + onPressed: _checkBiometrics, + child: const Text('Check biometrics'), + ), + const Divider(height: 100), + Text('Enrolled biometrics: $_enrolledBiometrics\n'), + ElevatedButton( + onPressed: _getEnrolledBiometrics, + child: const Text('Get enrolled biometrics'), + ), + const Divider(height: 100), + Text('Current State: $_authorized\n'), + if (_authorized == 'Authorized') + ElevatedButton( + onPressed: _cancelAuthentication, + // TODO(goderbauer): Make this const when this package requires Flutter 3.8 or later. + // ignore: prefer_const_constructors + child: Row( + mainAxisSize: MainAxisSize.min, + children: const [ + Text('Cancel Authentication'), + Icon(Icons.cancel), + ], + ), + ) + else + Column( + children: [ + ElevatedButton( + onPressed: _authenticate, + // TODO(goderbauer): Make this const when this package requires Flutter 3.8 or later. + // ignore: prefer_const_constructors + child: Row( + mainAxisSize: MainAxisSize.min, + children: const [ + Text('Authenticate'), + Icon(Icons.perm_device_information), + ], + ), + ), + ElevatedButton( + onPressed: _authenticateWithBiometrics, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(_isAuthenticating + ? 'Cancel' + : 'Authenticate: biometrics only'), + const Icon(Icons.fingerprint), + ], + ), + ), + ], + ), + ], + ), + ], + ), + ), + ); + } +} + +enum _SupportState { + unknown, + supported, + unsupported, +} diff --git a/packages/local_auth/local_auth_ohos/example/ohos/.gitignore b/packages/local_auth/local_auth_ohos/example/ohos/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..8c3bb454497b4401fbc4825e5f56899f45dc5ccf --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/.gitignore @@ -0,0 +1,15 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.hvigor +entry/src/main/resources/rawfile/flutter_assets +*.har +oh-package-lock.json5 diff --git a/packages/local_auth/local_auth_ohos/example/ohos/AppScope/app.json5 b/packages/local_auth/local_auth_ohos/example/ohos/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..95acd4629d7cbc9feb6a2d22efce8e12bc1acacc --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.local_auth_ohos_example", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/AppScope/resources/base/element/string.json b/packages/local_auth/local_auth_ohos/example/ohos/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..0bc2f8e2eda41feb2d0d2f653aa83ce6ccd70a90 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "local_auth_ohos_example" + } + ] +} diff --git a/packages/local_auth/local_auth_ohos/example/ohos/AppScope/resources/base/media/app_icon.png b/packages/local_auth/local_auth_ohos/example/ohos/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521 Binary files /dev/null and b/packages/local_auth/local_auth_ohos/example/ohos/AppScope/resources/base/media/app_icon.png differ diff --git a/packages/local_auth/local_auth_ohos/example/ohos/build-profile.json5 b/packages/local_auth/local_auth_ohos/example/ohos/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d209fee432db4515940449ca8f4516144ae32cf6 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/build-profile.json5 @@ -0,0 +1,35 @@ +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.0.0(12)", + "runtimeOS": "HarmonyOS" + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/.gitignore b/packages/local_auth/local_auth_ohos/example/ohos/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5cc1fcb7c5b5cbf9307dfff2f0798a9ce60e397b --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/.gitignore @@ -0,0 +1,9 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test +libs/arm64-v8a/libapp.so +*.har +oh-package-lock.json5 diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/build-profile.json5 b/packages/local_auth/local_auth_ohos/example/ohos/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..afe4b6619c102a381c5c535258b912e9a7917022 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/build-profile.json5 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "apiType": "stageMode", + "buildOption": { + "arkOptions": { + // "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */ + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/hvigorfile.ts b/packages/local_auth/local_auth_ohos/example/ohos/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..289eb09d575335c3b76321c431525640545e7049 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/libs/arm64-v8a/libc++_shared.so b/packages/local_auth/local_auth_ohos/example/ohos/entry/libs/arm64-v8a/libc++_shared.so new file mode 100644 index 0000000000000000000000000000000000000000..831c9353702073d45889352a4dafb93103d67d20 Binary files /dev/null and b/packages/local_auth/local_auth_ohos/example/ohos/entry/libs/arm64-v8a/libc++_shared.so differ diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/oh-package.json5 b/packages/local_auth/local_auth_ohos/example/ohos/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c2fac3759806d90a8f2f39bbeef4e9b17873cb0b --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/oh-package.json5 @@ -0,0 +1,13 @@ +{ + "license": "", + "devDependencies": {}, + "author": "", + "name": "entry", + "description": "Please describe the basic information.", + "main": "", + "version": "1.0.0", + "dependencies": { + "@ohos/flutter_ohos": "file:../har/flutter.har", + "local_auth_ohos": "file:../har/local_auth_ohos.har" + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..8502b052bb2785b2aef69e1503b0f2ffbbdc25ee --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,26 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import { FlutterAbility } from '@ohos/flutter_ohos' +import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant'; +import FlutterEngine from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine'; + +export default class EntryAbility extends FlutterAbility { + configureFlutterEngine(flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) + GeneratedPluginRegistrant.registerWith(flutterEngine); + } +} + diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/ets/pages/Index.ets b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..1125f9fdd95f4310a182c1c9e3680f37f73686c9 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import common from '@ohos.app.ability.common'; +import { FlutterPage } from '@ohos/flutter_ohos' + +let storage = LocalStorage.getShared() +const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS' + +@Entry(storage) +@Component +struct Index { + private context = getContext(this) as common.UIAbilityContext + @LocalStorageLink('viewId') viewId: string = ""; + + build() { + Column() { + FlutterPage({ viewId: this.viewId }) + } + } + + onBackPress(): boolean { + this.context.eventHub.emit(EVENT_BACK_PRESS) + return true + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/module.json5 b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..976a6cbc0211e98389da6e262c4efe91599093e6 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/module.json5 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:icon", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.ACCESS_BIOMETRIC", + "reason": "$string:EntryAbility_accessBiometricReason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "inuse" + } + } + ] + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/element/color.json b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/element/string.json b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..ca79dc3fe77f03ef1a1e0e5caa0277402367e949 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "local_auth_demo" + }, + { + "name": "EntryAbility_accessBiometricReason", + "value": "Verify User" + } + ] +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/media/icon.png b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd45accb1dfd2fd0da16c732c72faa6e46b26521 Binary files /dev/null and b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/media/icon.png differ diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/media/startIcon.png b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..366f76459ffd4494ec40d0ddd5c59385b9c5da11 Binary files /dev/null and b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/media/startIcon.png differ diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/profile/main_pages.json b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/en_US/element/string.json b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..ca79dc3fe77f03ef1a1e0e5caa0277402367e949 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "local_auth_demo" + }, + { + "name": "EntryAbility_accessBiometricReason", + "value": "Verify User" + } + ] +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/zh_CN/element/string.json b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f2eebb81d783eca0262c0aca6d5f9aa8a7a80db4 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "local_auth_demo" + }, + { + "name": "EntryAbility_accessBiometricReason", + "value": "验证用户" + } + ] +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/hvigor/hvigor-config.json5 b/packages/local_auth/local_auth_ohos/example/ohos/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ba720309263e55532a56354c49cdbc813c391ff6 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/hvigor/hvigor-config.json5 @@ -0,0 +1,8 @@ +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "properties": { + "ohos.nativeResolver": false + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/ohos/hvigorfile.ts b/packages/local_auth/local_auth_ohos/example/ohos/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec5481b0543b1a9418477b73524d8f40a1ddaf30 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/hvigorfile.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/packages/local_auth/local_auth_ohos/example/ohos/oh-package.json5 b/packages/local_auth/local_auth_ohos/example/ohos/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a3984770aa288e27e687fa3d638714afb1714a0a --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/ohos/oh-package.json5 @@ -0,0 +1,20 @@ +{ + "modelVersion": "5.0.0", + "name": "local_auth_ohos_example", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "@ohos/flutter_ohos": "file:./har/flutter.har" + }, + "devDependencies": { + "@ohos/hypium": "1.0.6" + }, + "overrides": { + "@ohos/flutter_ohos": "file:./har/flutter.har", + "local_auth_ohos": "file:./har/local_auth_ohos.har", + "@ohos/flutter_module": "file:./entry" + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/example/pubspec.yaml b/packages/local_auth/local_auth_ohos/example/pubspec.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e818924c7d57ecbb98936881ee8a083aec95538c --- /dev/null +++ b/packages/local_auth/local_auth_ohos/example/pubspec.yaml @@ -0,0 +1,110 @@ +# Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +name: local_auth_ohos_example +description: Demonstrates how to use the local_auth_ohos plugin. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0 + +environment: + sdk: ">=2.14.0 <3.0.0" + flutter: ">=3.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + local_auth: + path: ../../local_auth + local_auth_platform_interface: ^1.0.0 + intl: 0.18.1 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dependency_overrides: + local_auth_ohos: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/local_auth/local_auth_ohos/lib/local_auth_ohos.dart b/packages/local_auth/local_auth_ohos/lib/local_auth_ohos.dart new file mode 100644 index 0000000000000000000000000000000000000000..af31b3b5f82c1ecdbedbf40eceb65bf2fc1f251c --- /dev/null +++ b/packages/local_auth/local_auth_ohos/lib/local_auth_ohos.dart @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:local_auth_platform_interface/local_auth_platform_interface.dart'; + +import 'types/auth_messages_ohos.dart'; + +export 'package:local_auth_ohos/types/auth_messages_ohos.dart'; +export 'package:local_auth_platform_interface/types/auth_messages.dart'; +export 'package:local_auth_platform_interface/types/auth_options.dart'; +export 'package:local_auth_platform_interface/types/biometric_type.dart'; + +const MethodChannel _channel = + MethodChannel('plugins.flutter.io/local_auth_ohos'); + +/// The implementation of [LocalAuthPlatform] for Ohos. +class LocalAuthOhos extends LocalAuthPlatform { + /// Registers this class as the default instance of [LocalAuthPlatform]. + static void registerWith() { + LocalAuthPlatform.instance = LocalAuthOhos(); + } + + @override + Future authenticate({ + required String localizedReason, + required Iterable authMessages, + AuthenticationOptions options = const AuthenticationOptions(), + }) async { + assert(localizedReason.isNotEmpty); + final Map args = { + 'localizedReason': localizedReason, + 'useErrorDialogs': options.useErrorDialogs, + 'stickyAuth': options.stickyAuth, + 'sensitiveTransaction': options.sensitiveTransaction, + 'biometricOnly': options.biometricOnly, + }; + args.addAll(const OhosAuthMessages().args); + for (final AuthMessages messages in authMessages) { + if (messages is OhosAuthMessages) { + args.addAll(messages.args); + } + } + return (await _channel.invokeMethod('authenticate', args)) ?? false; + } + + @override + Future deviceSupportsBiometrics() async { + return (await _channel.invokeMethod('deviceSupportsBiometrics')) ?? + false; + } + + @override + Future> getEnrolledBiometrics() async { + final List result = (await _channel.invokeListMethod( + 'getEnrolledBiometrics', + )) ?? + []; + final List biometrics = []; + for (final String value in result) { + switch (value) { + case 'face': + biometrics.add(BiometricType.face); + break; + case 'fingerprint': + biometrics.add(BiometricType.fingerprint); + break; + } + } + return biometrics; + } + + @override + Future isDeviceSupported() async => + (await _channel.invokeMethod('isDeviceSupported')) ?? false; + + @override + Future stopAuthentication() async => + await _channel.invokeMethod('stopAuthentication') ?? false; +} diff --git a/packages/local_auth/local_auth_ohos/lib/types/auth_messages_ohos.dart b/packages/local_auth/local_auth_ohos/lib/types/auth_messages_ohos.dart new file mode 100644 index 0000000000000000000000000000000000000000..c9a53a4965d29b5a91fc2a38aa602f5e0391ea80 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/lib/types/auth_messages_ohos.dart @@ -0,0 +1,200 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; +import 'package:local_auth_platform_interface/types/auth_messages.dart'; + +/// Ohos side authentication messages. +/// +/// Provides default values for all messages. +@immutable +class OhosAuthMessages extends AuthMessages { + /// Constructs a new instance. + const OhosAuthMessages({ + this.biometricHint, + this.biometricNotRecognized, + this.biometricRequiredTitle, + this.biometricSuccess, + this.cancelButton, + this.deviceCredentialsRequiredTitle, + this.deviceCredentialsSetupDescription, + this.goToSettingsButton, + this.goToSettingsDescription, + this.signInTitle, + this.authType, + }); + + /// Hint message advising the user how to authenticate with biometrics. + /// Maximum 60 characters. + final String? biometricHint; + + /// Message to let the user know that authentication was failed. + /// Maximum 60 characters. + final String? biometricNotRecognized; + + /// Message shown as a title in a dialog which indicates the user + /// has not set up biometric authentication on their device. + /// Maximum 60 characters. + final String? biometricRequiredTitle; + + /// Message to let the user know that authentication was successful. + /// Maximum 60 characters + final String? biometricSuccess; + + /// Message shown on a button that the user can click to leave the + /// current dialog. + /// Maximum 30 characters. + final String? cancelButton; + + /// Message shown as a title in a dialog which indicates the user + /// has not set up credentials authentication on their device. + /// Maximum 60 characters. + final String? deviceCredentialsRequiredTitle; + + /// Message advising the user to go to the settings and configure + /// device credentials on their device. + final String? deviceCredentialsSetupDescription; + + /// Message shown on a button that the user can click to go to settings pages + /// from the current dialog. + /// Maximum 30 characters. + final String? goToSettingsButton; + + /// Message advising the user to go to the settings and configure + /// biometric on their device. + final String? goToSettingsDescription; + + /// Message shown as a title in a dialog which indicates the user + /// that they need to scan biometric to continue. + /// Maximum 60 characters. + final String? signInTitle; + + /// This is used to select the biometric type: + /// FACE、FINGERPRINT、PIN. + final String? authType; + + @override + Map get args { + return { + 'biometricHint': biometricHint ?? ohosBiometricHint, + 'biometricNotRecognized': + biometricNotRecognized ?? ohosBiometricNotRecognized, + 'biometricSuccess': biometricSuccess ?? ohosBiometricSuccess, + 'biometricRequired': + biometricRequiredTitle ?? ohosBiometricRequiredTitle, + 'cancelButton': cancelButton ?? ohosCancelButton, + 'deviceCredentialsRequired': deviceCredentialsRequiredTitle ?? + ohosDeviceCredentialsRequiredTitle, + 'deviceCredentialsSetupDescription': deviceCredentialsSetupDescription ?? + ohosDeviceCredentialsSetupDescription, + 'goToSetting': goToSettingsButton ?? goToSettings, + 'goToSettingDescription': + goToSettingsDescription ?? ohosGoToSettingsDescription, + 'signInTitle': signInTitle ?? ohosSignInTitle, + 'authType': authType ?? '', + }; + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is OhosAuthMessages && + runtimeType == other.runtimeType && + biometricHint == other.biometricHint && + biometricNotRecognized == other.biometricNotRecognized && + biometricRequiredTitle == other.biometricRequiredTitle && + biometricSuccess == other.biometricSuccess && + cancelButton == other.cancelButton && + deviceCredentialsRequiredTitle == + other.deviceCredentialsRequiredTitle && + deviceCredentialsSetupDescription == + other.deviceCredentialsSetupDescription && + goToSettingsButton == other.goToSettingsButton && + goToSettingsDescription == other.goToSettingsDescription && + signInTitle == other.signInTitle && + authType == other.authType; + + @override + int get hashCode => Object.hash( + super.hashCode, + biometricHint, + biometricNotRecognized, + biometricRequiredTitle, + biometricSuccess, + cancelButton, + deviceCredentialsRequiredTitle, + deviceCredentialsSetupDescription, + goToSettingsButton, + goToSettingsDescription, + signInTitle, + authType); +} + +// Default strings for OhosAuthMessages. Currently supports English. +// Intl.message must be string literals. + +/// Message shown on a button that the user can click to go to settings pages +/// from the current dialog. +String get goToSettings => Intl.message('Go to settings', + desc: 'Message shown on a button that the user can click to go to ' + 'settings pages from the current dialog. Maximum 30 characters.'); + +/// Hint message advising the user how to authenticate with biometrics. +String get ohosBiometricHint => Intl.message('Verify identity', + desc: 'Hint message advising the user how to authenticate with biometrics. ' + 'Maximum 60 characters.'); + +/// Message to let the user know that authentication was failed. +String get ohosBiometricNotRecognized => + Intl.message('Not recognized. Try again.', + desc: 'Message to let the user know that authentication was failed. ' + 'Maximum 60 characters.'); + +/// Message to let the user know that authentication was successful. It +String get ohosBiometricSuccess => Intl.message('Success', + desc: 'Message to let the user know that authentication was successful. ' + 'Maximum 60 characters.'); + +/// Message shown on a button that the user can click to leave the +/// current dialog. +String get ohosCancelButton => Intl.message('Cancel', + desc: 'Message shown on a button that the user can click to leave the ' + 'current dialog. Maximum 30 characters.'); + +/// Message shown as a title in a dialog which indicates the user +/// that they need to scan biometric to continue. +String get ohosSignInTitle => Intl.message('Authentication required', + desc: 'Message shown as a title in a dialog which indicates the user ' + 'that they need to scan biometric to continue. Maximum 60 characters.'); + +/// Message shown as a title in a dialog which indicates the user +/// has not set up biometric authentication on their device. +String get ohosBiometricRequiredTitle => Intl.message('Biometric required', + desc: 'Message shown as a title in a dialog which indicates the user ' + 'has not set up biometric authentication on their device. ' + 'Maximum 60 characters.'); + +/// Message shown as a title in a dialog which indicates the user +/// has not set up credentials authentication on their device. +String get ohosDeviceCredentialsRequiredTitle => + Intl.message('Device credentials required', + desc: 'Message shown as a title in a dialog which indicates the user ' + 'has not set up credentials authentication on their device. ' + 'Maximum 60 characters.'); + +/// Message advising the user to go to the settings and configure +/// device credentials on their device. +String get ohosDeviceCredentialsSetupDescription => + Intl.message('Device credentials required', + desc: 'Message advising the user to go to the settings and configure ' + 'device credentials on their device.'); + +/// Message advising the user to go to the settings and configure +/// biometric on their device. +String get ohosGoToSettingsDescription => Intl.message( + 'Biometric authentication is not set up on your device. Go to ' + "'Settings > Security' to add biometric authentication.", + desc: 'Message advising the user to go to the settings and configure ' + 'biometric on their device.'); diff --git a/packages/local_auth/local_auth_ohos/ohos/.gitignore b/packages/local_auth/local_auth_ohos/ohos/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6f7b4f89c49a6abadc383d9665d3b4c171d466bc --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/.gitignore @@ -0,0 +1,17 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test + +/entry/libs/arm64-v8a/libflutter.so +/entry/src/main/resources/rawfile/flutter_assets +**.har +**/oh-package-lock.json5 +BuildProfile.ets diff --git a/packages/local_auth/local_auth_ohos/ohos/build-profile.json5 b/packages/local_auth/local_auth_ohos/ohos/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..afe4b6619c102a381c5c535258b912e9a7917022 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/build-profile.json5 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "apiType": "stageMode", + "buildOption": { + "arkOptions": { + // "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */ + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/ohos/hvigorfile.ts b/packages/local_auth/local_auth_ohos/ohos/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..d13d36380b4131e863f787e793a684a1e156273a --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/hvigorfile.ts @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { harTasks } from '@ohos/hvigor-ohos-plugin'; \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/ohos/index.ets b/packages/local_auth/local_auth_ohos/ohos/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..154028b8344684840b9dc076cafdd676ddc41257 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/index.ets @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import LocalAuthPlugin from './src/main/ets/io/flutter/plugins/localauth/LocalAuthPlugin'; +export default LocalAuthPlugin; \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/ohos/obfuscation-rules.txt b/packages/local_auth/local_auth_ohos/ohos/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..985b2aeb7658286b17bd26eab8f217c3fe75ea8b --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/obfuscation-rules.txt @@ -0,0 +1,18 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/ohos/oh-package.json5 b/packages/local_auth/local_auth_ohos/ohos/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0ff298b3fc8c211e02d792ca03b85e83633cf393 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/oh-package.json5 @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "name": "local_auth_ohos", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "index.ets", + "author": "", + "license": "Apache-2.0", + "dependencies": { + "@ohos/flutter_ohos": "file:./har/flutter.har" + } +} diff --git a/packages/local_auth/local_auth_ohos/ohos/src/main/ets/io/flutter/plugins/localauth/AuthenticationHelper.ets b/packages/local_auth/local_auth_ohos/ohos/src/main/ets/io/flutter/plugins/localauth/AuthenticationHelper.ets new file mode 100644 index 0000000000000000000000000000000000000000..c15934f2123ed98875f898bb74b25d021cc40d81 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/src/main/ets/io/flutter/plugins/localauth/AuthenticationHelper.ets @@ -0,0 +1,120 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import userAuth from '@ohos.userIAM.userAuth'; +import common from '@ohos.app.ability.common'; +import { + AbilityPluginBinding +} from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/ability/AbilityPluginBinding'; +import MethodCall from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodCall'; +import { MethodResult } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel'; +import Log from '@ohos/flutter_ohos/src/main/ets/util/Log'; +import { AuthCallback } from './LocalAuthPlugin'; + +/** + * Authenticates the user with biometrics and sends corresponding response back to Flutter. + * + *

One instance per call is generated to ensure readable separation of executable paths across + * method calls. + */ + +const TAG = "AuthenticationHelper"; + +export class AuthenticationHelper { + private binding: AbilityPluginBinding | null = null; + private authCallback: userAuth.IAuthCallback | null = null; + private authParam : userAuth.AuthParam = { + challenge: new Uint8Array([49, 49, 49, 49, 49, 49]), + authType: [ + userAuth.UserAuthType.PIN, + userAuth.UserAuthType.FINGERPRINT + ], + authTrustLevel: userAuth.AuthTrustLevel.ATL1, + }; + private widgetParam :userAuth.WidgetParam = { + title: '请输入锁屏密码', + } + + private userAuthInstance: userAuth.UserAuthInstance | null = null; + + constructor(abilityPluginBinding: AbilityPluginBinding | null, + call: MethodCall, + allowCredentials: boolean) { + this.binding = abilityPluginBinding; + if (allowCredentials) { + this.authParam = { + challenge: new Uint8Array([49, 49, 49, 49, 49, 49]), + authType: [], + authTrustLevel: userAuth.AuthTrustLevel.ATL1, + }; + const argAuthType:string = call.argument("authType") + switch (argAuthType) { + case 'FACE': + this.authParam.authType.push(userAuth.UserAuthType.FACE); + break; + case 'FINGERPRINT': + this.authParam.authType.push(userAuth.UserAuthType.FINGERPRINT); + break; + case 'PIN': + this.authParam.authType.push(userAuth.UserAuthType.PIN); + break; + default: + this.authParam.authType = [ + userAuth.UserAuthType.FINGERPRINT, + userAuth.UserAuthType.FACE, + userAuth.UserAuthType.PIN + ]; + break; + } + this.widgetParam = { + title: call.argument("localizedReason"), + } + } + this.userAuthInstance = userAuth.getUserAuthInstance(this.authParam, this.widgetParam); + Log.i(TAG, 'get userAuth instance success'); + } + + getContext(): common.UIAbilityContext | undefined { + return this.binding?.getAbility().context; + } + + /** Start the biometric listener. */ + authenticate(methodResult: MethodResult): void { + try { + this.authCallback = new AuthCallback(methodResult, true); + let that = this.authCallback; + this.userAuthInstance?.on('result', { + onResult(result) { + that.onResult(result); + } + }); + + this.userAuthInstance?.start(); + Log.i(TAG, 'auth start success'); + } catch (error) { + Log.e(TAG, 'auth catch error: ' + JSON.stringify(error)); + } + } + + /** Cancels the biometric authentication. */ + stopAuthentication(): void { + try { + this.userAuthInstance?.cancel(); + Log.i(TAG, 'auth cancel success'); + } catch (error) { + Log.e(TAG, 'auth catch error: ' + JSON.stringify(error)); + } + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/ohos/src/main/ets/io/flutter/plugins/localauth/LocalAuthPlugin.ets b/packages/local_auth/local_auth_ohos/ohos/src/main/ets/io/flutter/plugins/localauth/LocalAuthPlugin.ets new file mode 100644 index 0000000000000000000000000000000000000000..a6cdeceaa6afc4fcb9ff1b36d3fc5895226a5110 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/src/main/ets/io/flutter/plugins/localauth/LocalAuthPlugin.ets @@ -0,0 +1,304 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import AbilityAware from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/ability/AbilityAware'; +import { AbilityPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/ability/AbilityPluginBinding'; +import { FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin'; +import { MethodCallHandler, MethodResult } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel'; +import MethodChannel from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel'; +import MethodCall from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodCall'; +import Log from '@ohos/flutter_ohos/src/main/ets/util/Log'; +import userAuth from '@ohos.userIAM.userAuth'; +import { AuthenticationHelper } from './AuthenticationHelper'; +import screenLock from '@ohos.screenLock'; +import { BusinessError } from '@ohos.base'; + +const TAG = "LocalAuthPlugin"; +const CHANNEL_NAME = "plugins.flutter.io/local_auth_ohos"; + +/** + * Flutter plugin providing access to local authentication. + * + *

Instantiate this in an add to app scenario to gracefully handle activity and context changes. + */ + +let authInProgress: boolean = false; +export default class LocalAuthPlugin implements FlutterPlugin, AbilityAware, MethodCallHandler { + private authHelper: AuthenticationHelper | null = null; + private abilityPluginBinding: AbilityPluginBinding | null = null; + + private channel: MethodChannel | null = null; + + getUniqueClassName(): string { + return "LocalAuthPlugin"; + } + + onAttachedToAbility(binding: AbilityPluginBinding) { + this.abilityPluginBinding = binding; + this.channel?.setMethodCallHandler(this); + } + + onDetachedFromAbility() { + } + + onAttachedToEngine(binding: FlutterPluginBinding): void { + Log.d(TAG, 'onAttachedToEngine local auth') + this.channel = new MethodChannel(binding.getBinaryMessenger(), CHANNEL_NAME); + this.channel.setMethodCallHandler(this); + } + + onDetachedFromEngine(binding: FlutterPluginBinding): void { + } + + onMethodCall(call: MethodCall, result: MethodResult): void { + Log.d(TAG, 'onMethodCall step in') + switch (call.method) { + case "authenticate": + this.authenticate(call, result); + break; + case "getEnrolledBiometrics": + this.getEnrolledBiometrics(result); + break; + case "isDeviceSupported": + this.isDeviceSupported(result); + break; + case "stopAuthentication": + this.stopAuthentication(result); + break; + case "deviceSupportsBiometrics": + this.deviceSupportsBiometrics(result); + break; + default: + result.notImplemented(); + break; + } + } + + + async isDeviceSupported(result: MethodResult): Promise { + Log.d(TAG, 'isDeviceSupported start') + let isDeviceSupported: boolean = await this.checkDeviceSupported(); + Log.d(TAG, `isDeviceSupported, ${isDeviceSupported}`) + result.success(isDeviceSupported); + } + + async checkDeviceSupported(): Promise { + if (this.canAuthenticateWithBiometrics()) { + return true; + } + return await isDeviceSecure(); + } + + getEnrolledBiometrics(result: MethodResult) { + Log.d(TAG, 'getEnrolledBiometrics start') + let biometrics: Array = new Array(); + if (this.getAvailableStatus(userAuth.UserAuthType.FACE, userAuth.AuthTrustLevel.ATL1)) { + biometrics.push("face"); + } + if (this.getAvailableStatus(userAuth.UserAuthType.FINGERPRINT, userAuth.AuthTrustLevel.ATL1)) { + biometrics.push("fingerprint"); + } + Log.d(TAG, `getEnrolledBiometrics, ${biometrics}`) + result.success(biometrics); + } + + deviceSupportsBiometrics(result: MethodResult) { + Log.d(TAG, 'deviceSupportsBiometrics start') + let deviceCanSupportBiometrics: Boolean = this.deviceCanSupportBiometrics(); + Log.d(TAG, `deviceCanSupportBiometrics: ${deviceCanSupportBiometrics}`) + result.success(deviceCanSupportBiometrics); + } + + /** + * Cancels any in-progress authentication. + * + *

Returns true only if authentication was in progress, and was successfully cancelled. + */ + stopAuthentication(result: MethodResult): void { + try { + if (this.authHelper != null && authInProgress) { + this.authHelper.stopAuthentication(); + this.authHelper = null; + } + authInProgress = false; + result.success(true); + } catch (e) { + result.success(false); + } + } + + + canAuthenticateWithBiometrics(): boolean { + Log.i(TAG, `canAuthenticateWithBiometrics`); + return this.getAvailableStatus(userAuth.UserAuthType.PIN, userAuth.AuthTrustLevel.ATL1) + || this.getAvailableStatus(userAuth.UserAuthType.FINGERPRINT, userAuth.AuthTrustLevel.ATL1) + || this.getAvailableStatus(userAuth.UserAuthType.FACE, userAuth.AuthTrustLevel.ATL1); + } + + private getAvailableStatus(authType: userAuth.UserAuthType, authTrustLevel: userAuth.AuthTrustLevel): boolean { + try { + Log.i(TAG, `getAvailableStatus start, authType: ${authType}, authTrustLevel: ${authTrustLevel}`); + userAuth.getAvailableStatus(authType, authTrustLevel); + } catch (err) { + Log.e(TAG, `Failed to getAvailableStatus, Code: ${err?.code}, message: ${err?.message}`); + return false; + } + Log.d(TAG, `getAvailableStatus success, authType: ${authType}, authTrustLevel: ${authTrustLevel}`); + return true; + } + + /** + * Returns true if this device can support biometric authentication, whether any biometrics are + * enrolled or not. + */ + deviceCanSupportBiometrics(): Boolean { + return this.supportHardware(userAuth.UserAuthType.FINGERPRINT, userAuth.AuthTrustLevel.ATL1) + || this.supportHardware(userAuth.UserAuthType.FACE, userAuth.AuthTrustLevel.ATL1); + } + + private supportHardware(authType: userAuth.UserAuthType, authTrustLevel: userAuth.AuthTrustLevel): boolean { + try { + Log.i(TAG, `supportHardware start, authType: ${authType}, authTrustLevel: ${authTrustLevel}`); + userAuth.getAvailableStatus(authType, authTrustLevel); + } catch (err) { + Log.e(TAG, `Failed to getAvailableStatus, Code: ${err?.code}, message: ${err?.message}`); + return err?.code != userAuth.UserAuthResultCode.TYPE_NOT_SUPPORT; + } + Log.d(TAG, `supportHardware success, authType: ${authType}, authTrustLevel: ${authTrustLevel}`); + return true; + } + + /** + * Attempts to authenticate the user with the provided [options], and using [strings] for any + * UI. + */ + async authenticate(call: MethodCall, result: MethodResult): Promise { + if (authInProgress) { + result.error("auth_in_progress", "Authentication in progress", null); + return; + } + + if (this.abilityPluginBinding?.getAbility() == null) { + result.error("no_ability", "local_auth plugin requires a foreground ability", null); + return; + } + + let isDeviceSupported: boolean = await this.checkDeviceSupported(); + if (!isDeviceSupported) { + authInProgress = false; + result.error("NotAvailable", "Required security features not enabled", null); + return; + } + authInProgress = true; + let isBiometricOnly: boolean = call.argument("biometricOnly"); + let allowCredentials: boolean = isBiometricOnly && await this.canAuthenticateWithDeviceCredential(); + this.sendAuthenticationRequest(call, result, allowCredentials); + } + + sendAuthenticationRequest(call: MethodCall, + result: MethodResult, + allowCredentials: boolean ): void { + this.authHelper = new AuthenticationHelper(this.abilityPluginBinding, call, allowCredentials); + this.authHelper.authenticate(result); + } + + async canAuthenticateWithDeviceCredential(): Promise { + return await isDeviceSecure(); + } +} + +async function isDeviceSecure(): Promise { + Log.i(TAG, `isDeviceSecure`); + let result = await screenLock.isSecureMode().then((data: Boolean) => { + console.info(`Succeeded in Obtaining whether the device is in secure mode. result: ${data}`); + return true; + }).catch((err: BusinessError) => { + console.error(`Failed to obtain whether the device is in secure mode, Code: ${err.code}, message: ${err.message}`); + return false; + }); + return result; +} + + +export class AuthCallback implements userAuth.IAuthCallback { + private result: MethodResult; + private authInProgress: boolean; + + constructor(result: MethodResult, authInProgress: boolean) { + this.result = result; + this.authInProgress = authInProgress; + } + + onResult(result: userAuth.UserAuthResult): void { + if (authInProgress) { + setAuthInProgress(false); + } + switch (result.result) { + case userAuth.UserAuthResultCode.SUCCESS: + this.result.success(true); + this.stop(); + break; + case userAuth.UserAuthResultCode.FAIL: + this.result.success(false); + break; + case userAuth.UserAuthResultCode.GENERAL_ERROR: + this.result.error(result.result.toLocaleString(), "General error occured.", null); + break; + case userAuth.UserAuthResultCode.TIMEOUT: + this.result.error(result.result.toLocaleString(), "This operation is time out.", null); + break; + case userAuth.UserAuthResultCode.TYPE_NOT_SUPPORT: + this.result.error(result.result.toLocaleString(), "Security credentials not available.", null); + break; + case userAuth.UserAuthResultCode.TRUST_LEVEL_NOT_SUPPORT: + this.result.error(result.result.toLocaleString(), "Unsupported authentication level.", null); + break; + case userAuth.UserAuthResultCode.BUSY: + this.result.error(result.result.toLocaleString(), "The device is busy.", null); + break; + case userAuth.UserAuthResultCode.LOCKED: + this.result.error(result.result.toLocaleString(), "The operation was canceled because the API is locked out" + + " due to too many attempts. This occurs after 5 failed attempts, and lasts for 60 seconds.", null); + break; + case userAuth.UserAuthResultCode.NOT_ENROLLED: + this.result.error(result.result.toLocaleString(), "No Biometrics enrolled on this device.", null); + break; + case userAuth.UserAuthResultCode.CANCELED_FROM_WIDGET: + this.result.error(result.result.toLocaleString(), "The operation was cancelled by the user from the widget.", null); + break; + case userAuth.UserAuthResultCode.CANCELED: + default: + this.result.success(false); + } + } + + /** Stops the biometric listener. */ + stop(): void { + try { + // this.off('result', { + // onResult (result) { + // Log.i(TAG, 'auth off result: ' + JSON.stringify(result)); + // } + // }); + Log.i(TAG, 'auth off success'); + } catch (error) { + Log.e(TAG, 'auth catch error: ' + JSON.stringify(error)); + } + } +} + +function setAuthInProgress(inProgress: boolean) { + authInProgress = inProgress; +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/ohos/src/main/module.json5 b/packages/local_auth/local_auth_ohos/ohos/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..858f897181edd30f359e3c08fe7985ddf5781793 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/src/main/module.json5 @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "module": { + "name": "local_auth_ohos", + "type": "har", + "deviceTypes": [ + "default", + ] + } +} \ No newline at end of file diff --git a/packages/local_auth/local_auth_ohos/ohos/src/main/resources/base/element/string.json b/packages/local_auth/local_auth_ohos/ohos/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..1e76de0c66777cfe83568615c5c2e68c61d23fed --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/src/main/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from npm package" + } + ] +} diff --git a/packages/local_auth/local_auth_ohos/ohos/src/main/resources/en_US/element/string.json b/packages/local_auth/local_auth_ohos/ohos/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..1e76de0c66777cfe83568615c5c2e68c61d23fed --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/src/main/resources/en_US/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from npm package" + } + ] +} diff --git a/packages/local_auth/local_auth_ohos/ohos/src/main/resources/zh_CN/element/string.json b/packages/local_auth/local_auth_ohos/ohos/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..1e76de0c66777cfe83568615c5c2e68c61d23fed --- /dev/null +++ b/packages/local_auth/local_auth_ohos/ohos/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "page_show", + "value": "page from npm package" + } + ] +} diff --git a/packages/local_auth/local_auth_ohos/pubspec.yaml b/packages/local_auth/local_auth_ohos/pubspec.yaml new file mode 100644 index 0000000000000000000000000000000000000000..af848eac805e6d68eb6a93626448fe0db2d18bc2 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/pubspec.yaml @@ -0,0 +1,42 @@ +# Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: local_auth_ohos +description: Ohos implementation of the local_auth plugin. +repository: https://gitee.com/openharmony-sig/flutter_packages/tree/master/packages/local_auth/local_auth_ohos +issue_tracker: https://gitee.com/openharmony-sig/flutter_packages/issues +version: 1.0.0 + +environment: + sdk: ">=3.0.0" + flutter: ">=3.19.0" + +flutter: + plugin: + implements: local_auth + platforms: + ohos: + package: io.flutter.plugins.localauth + pluginClass: LocalAuthPlugin + dartPluginClass: LocalAuthOhos + +dependencies: + flutter: + sdk: flutter +# intl: ">=0.17.0 <0.19.0" +# local_auth_platform_interface: ^1.0.1 + intl: ">=0.17.0 <0.20.0" + local_auth_platform_interface: ^1.0.1 +dev_dependencies: + flutter_test: + sdk: flutter diff --git a/packages/local_auth/local_auth_ohos/test/local_auth_test.dart b/packages/local_auth/local_auth_ohos/test/local_auth_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..136613d4824518d060b0ca1ba9320225a9667a51 --- /dev/null +++ b/packages/local_auth/local_auth_ohos/test/local_auth_test.dart @@ -0,0 +1,184 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:local_auth_android/local_auth_android.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('LocalAuth', () { + const MethodChannel channel = MethodChannel( + 'plugins.flutter.io/local_auth_android', + ); + + final List log = []; + late LocalAuthAndroid localAuthentication; + + setUp(() { + _ambiguate(TestDefaultBinaryMessengerBinding.instance)! + .defaultBinaryMessenger + .setMockMethodCallHandler(channel, (MethodCall methodCall) { + log.add(methodCall); + switch (methodCall.method) { + case 'getEnrolledBiometrics': + return Future>.value(['weak', 'strong']); + default: + return Future.value(true); + } + }); + localAuthentication = LocalAuthAndroid(); + log.clear(); + }); + + test('deviceSupportsBiometrics calls platform', () async { + final bool result = await localAuthentication.deviceSupportsBiometrics(); + + expect( + log, + [ + isMethodCall('deviceSupportsBiometrics', arguments: null), + ], + ); + expect(result, true); + }); + + test('getEnrolledBiometrics calls platform', () async { + final List result = + await localAuthentication.getEnrolledBiometrics(); + + expect( + log, + [ + isMethodCall('getEnrolledBiometrics', arguments: null), + ], + ); + expect(result, [ + BiometricType.weak, + BiometricType.strong, + ]); + }); + + test('isDeviceSupported calls platform', () async { + await localAuthentication.isDeviceSupported(); + expect( + log, + [ + isMethodCall('isDeviceSupported', arguments: null), + ], + ); + }); + + test('stopAuthentication calls platform', () async { + await localAuthentication.stopAuthentication(); + expect( + log, + [ + isMethodCall('stopAuthentication', arguments: null), + ], + ); + }); + + group('With device auth fail over', () { + test('authenticate with no args.', () async { + await localAuthentication.authenticate( + authMessages: [const AndroidAuthMessages()], + localizedReason: 'Needs secure', + options: const AuthenticationOptions(biometricOnly: true), + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + 'biometricOnly': true, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); + + test('authenticate with no sensitive transaction.', () async { + await localAuthentication.authenticate( + authMessages: [const AndroidAuthMessages()], + localizedReason: 'Insecure', + options: const AuthenticationOptions( + sensitiveTransaction: false, + useErrorDialogs: false, + biometricOnly: true, + ), + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Insecure', + 'useErrorDialogs': false, + 'stickyAuth': false, + 'sensitiveTransaction': false, + 'biometricOnly': true, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); + }); + + group('With biometrics only', () { + test('authenticate with no args.', () async { + await localAuthentication.authenticate( + authMessages: [const AndroidAuthMessages()], + localizedReason: 'Needs secure', + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Needs secure', + 'useErrorDialogs': true, + 'stickyAuth': false, + 'sensitiveTransaction': true, + 'biometricOnly': false, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); + + test('authenticate with no sensitive transaction.', () async { + await localAuthentication.authenticate( + authMessages: [const AndroidAuthMessages()], + localizedReason: 'Insecure', + options: const AuthenticationOptions( + sensitiveTransaction: false, + useErrorDialogs: false, + ), + ); + expect( + log, + [ + isMethodCall('authenticate', + arguments: { + 'localizedReason': 'Insecure', + 'useErrorDialogs': false, + 'stickyAuth': false, + 'sensitiveTransaction': false, + 'biometricOnly': false, + }..addAll(const AndroidAuthMessages().args)), + ], + ); + }); + }); + }); +} + +/// This allows a value of type T or T? to be treated as a value of type T?. +/// +/// We use this so that APIs that have become non-nullable can still be used +/// with `!` and `?` on the stable branch. +T? _ambiguate(T? value) => value;