Application lock (iOS)

This commit is contained in:
niuhuan 2022-05-14 21:45:00 +08:00
parent 7a8e70e693
commit 5f3b73d12c
8 changed files with 157 additions and 30 deletions

View File

@ -37,7 +37,7 @@ PODS:
- image_cropper (0.0.4):
- Flutter
- TOCropViewController (~> 2.6.1)
- image_picker (0.0.1):
- image_picker_ios (0.0.1):
- Flutter
- "permission_handler (5.1.0+2)":
- Flutter
@ -53,7 +53,7 @@ DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@ -72,8 +72,8 @@ EXTERNAL SOURCES:
:path: Flutter
image_cropper:
:path: ".symlinks/plugins/image_cropper/ios"
image_picker:
:path: ".symlinks/plugins/image_picker/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
permission_handler:
:path: ".symlinks/plugins/permission_handler/ios"
url_launcher_ios:
@ -85,7 +85,7 @@ SPEC CHECKSUMS:
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
image_cropper: 60c2789d1f1a78c873235d4319ca0c34a69f2d98
image_picker: 541dcbb3b9cf32d87eacbd957845d8651d6c62c3
image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
SDWebImage: 0905f1b7760fc8ac4198cae0036600d67478751e
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
@ -94,4 +94,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
COCOAPODS: 1.11.2
COCOAPODS: 1.11.3

View File

@ -1,6 +1,7 @@
import UIKit
import Flutter
import Mobile
import LocalAuthentication
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
@ -34,6 +35,18 @@ import Mobile
result(FlutterError(code: "", message: "params error", details: ""))
}
}
else if call.method == "verifyAuthentication"{
let context = LAContext()
let can = context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil)
guard can == true else {
result(false)
return
}
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "身份验证") { (success, error) in
result(success)
}
}
else if call.method == "iosSaveFileToImage"{
if let args = call.arguments as? Dictionary<String, Any>,
let path = args["path"] as? String{

View File

@ -717,4 +717,8 @@ class Method {
List list = json.decode(rsp);
return list.map((e) => Collection.fromJson(e)).toList();
}
Future<bool> verifyAuthentication() async {
return await _channel.invokeMethod("verifyAuthentication");
}
}

View File

@ -0,0 +1,48 @@
import 'dart:io';
import 'package:flutter/material.dart';
import '../Common.dart';
import '../Method.dart';
const _propertyName = "authentication";
late bool _authentication;
Future<void> initAuthentication() async {
_authentication =
(await method.loadProperty(_propertyName, "false")) == "true";
}
bool currentAuthentication() {
return _authentication;
}
Future<void> _chooseAuthentication(BuildContext context) async {
if (await method.verifyAuthentication()) {
String? result =
await chooseListDialog<String>(context, "进入APP时验证身份", ["", ""]);
if (result != null) {
var target = result == "";
await method.saveProperty(_propertyName, "$target");
_authentication = target;
}
}
}
Widget authenticationSetting() {
if (Platform.isIOS != true) {
return Container();
}
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: const Text("进入APP时验证身份"),
subtitle: Text(_authentication ? "" : ""),
onTap: () async {
await _chooseAuthentication(context);
setState(() {});
},
);
},
);
}

View File

@ -63,6 +63,9 @@ Future<dynamic> _inputChooserRoot(BuildContext context) async {
}
Widget chooserRootSetting() {
if (Platform.isIOS) {
return Container();
}
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(

View File

@ -5,6 +5,7 @@ import 'package:pikapika/basic/Method.dart';
import 'package:pikapika/basic/config/Themes.dart';
import 'package:pikapika/basic/enum/ErrorTypes.dart';
import 'package:pikapika/screens/RegisterScreen.dart';
import 'package:pikapika/screens/SettingsScreen.dart';
import 'package:pikapika/screens/components/NetworkSetting.dart';
import 'AppScreen.dart';
@ -59,6 +60,19 @@ class _AccountScreenState extends State<AccountScreen> {
appBar: AppBar(
title: const Text('配置选项'),
actions: [
IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SettingsScreen(
hiddenAccountInfo: true,
),
),
);
},
icon: const Text('设置'),
),
IconButton(
onPressed: () {
if (androidNightModeDisplay) {

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:pikapika/basic/config/Address.dart';
import 'package:pikapika/basic/config/AndroidDisplayMode.dart';
import 'package:pikapika/basic/config/AndroidSecureFlag.dart';
import 'package:pikapika/basic/config/Authentication.dart';
import 'package:pikapika/basic/config/AutoClean.dart';
import 'package:pikapika/basic/config/AutoFullScreen.dart';
import 'package:pikapika/basic/config/ChooserRoot.dart';
@ -43,6 +44,8 @@ class InitScreen extends StatefulWidget {
}
class _InitScreenState extends State<InitScreen> {
var _authenticating = false;
@override
initState() {
_init();
@ -83,7 +86,51 @@ class _InitScreenState extends State<InitScreen> {
await initExportRename();
await initVersion();
await initUsingRightClickPop();
await initAuthentication();
autoCheckNewVersion();
setState(() {
_authenticating = currentAuthentication();
});
if (_authenticating) {
_goAuthentication();
} else {
_goApplication();
}
}
@override
Widget build(BuildContext context) {
if (_authenticating) {
return Scaffold(
appBar: AppBar(
title: const Text("身份验证"),
),
body: Center(
child: Container(
padding: const EdgeInsets.all(20),
child: MaterialButton(
onPressed: () {
_goAuthentication();
},
child: const Text('您在之前使用APP时开启了身份验证, 请点这段文字进行身份核查, 核查通过后将会进入APP'),
),
),
),
);
}
return Scaffold(
backgroundColor: const Color(0xfffffced),
body: ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Image.asset(
"lib/assets/init.jpg",
fit: BoxFit.contain,
),
),
);
}
Future _goApplication() async {
// , token失效重新登录, 1
if (await method.preLogin()) {
// token或username+password有效则直接进入登录好的界面
@ -100,17 +147,9 @@ class _InitScreenState extends State<InitScreen> {
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xfffffced),
body: ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Image.asset(
"lib/assets/init.jpg",
fit: BoxFit.contain,
),
),
);
Future _goAuthentication() async {
if (await method.verifyAuthentication()) {
_goApplication();
}
}
}

View File

@ -29,13 +29,17 @@ import 'package:pikapika/basic/config/shadowCategoriesMode.dart';
import 'package:pikapika/screens/components/NetworkSetting.dart';
import 'package:pikapika/screens/components/RightClickPop.dart';
import '../basic/config/Authentication.dart';
import '../basic/config/UsingRightClickPop.dart';
import 'CleanScreen.dart';
import 'MigrateScreen.dart';
import 'ModifyPasswordScreen.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({Key? key}) : super(key: key);
final bool hiddenAccountInfo;
const SettingsScreen({Key? key, this.hiddenAccountInfo = false})
: super(key: key);
@override
Widget build(BuildContext context) {
@ -51,16 +55,18 @@ class SettingsScreen extends StatelessWidget {
body: ListView(
children: [
const Divider(),
ListTile(
onTap: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ModifyPasswordScreen()),
);
},
title: const Text('修改密码'),
),
hiddenAccountInfo
? Container()
: ListTile(
onTap: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ModifyPasswordScreen()),
);
},
title: const Text('修改密码'),
),
const Divider(),
const NetworkSetting(),
const Divider(),
@ -94,6 +100,7 @@ class SettingsScreen extends StatelessWidget {
const Divider(),
androidDisplayModeSetting(),
androidSecureFlagSetting(),
authenticationSetting(),
const Divider(),
chooserRootSetting(),
downloadThreadCountSetting(),
@ -131,5 +138,4 @@ class SettingsScreen extends StatelessWidget {
}
return Container();
}
}