Application lock (Android)
This commit is contained in:
parent
5f3b73d12c
commit
b1b020ed83
|
@ -7,6 +7,7 @@
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package niuhuan.pikapika
|
package niuhuan.pikapika
|
||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
|
import android.content.DialogInterface
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import android.hardware.biometrics.BiometricPrompt
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Display
|
import android.view.Display
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
@ -27,6 +28,8 @@ import java.io.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity : FlutterActivity() {
|
||||||
|
|
||||||
|
@ -70,7 +73,10 @@ class MainActivity : FlutterActivity() {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
Mobile.initApplication(androidDataLocal())
|
Mobile.initApplication(androidDataLocal())
|
||||||
// Method Channel
|
// Method Channel
|
||||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "method").setMethodCallHandler { call, result ->
|
MethodChannel(
|
||||||
|
flutterEngine.dartExecutor.binaryMessenger,
|
||||||
|
"method"
|
||||||
|
).setMethodCallHandler { call, result ->
|
||||||
result.withCoroutine {
|
result.withCoroutine {
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"flatInvoke" -> {
|
"flatInvoke" -> {
|
||||||
|
@ -96,6 +102,7 @@ class MainActivity : FlutterActivity() {
|
||||||
// 获取可以迁移数据地址
|
// 获取可以迁移数据地址
|
||||||
"androidGetExtendDirs" -> androidGetExtendDirs()
|
"androidGetExtendDirs" -> androidGetExtendDirs()
|
||||||
"androidSecureFlag" -> androidSecureFlag(call.argument("flag")!!)
|
"androidSecureFlag" -> androidSecureFlag(call.argument("flag")!!)
|
||||||
|
"verifyAuthentication" -> auth()
|
||||||
else -> {
|
else -> {
|
||||||
notImplementedToken
|
notImplementedToken
|
||||||
}
|
}
|
||||||
|
@ -239,7 +246,8 @@ class MainActivity : FlutterActivity() {
|
||||||
put(MediaStore.MediaColumns.IS_PENDING, 1)
|
put(MediaStore.MediaColumns.IS_PENDING, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)?.let { uri ->
|
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
|
||||||
|
?.let { uri ->
|
||||||
contentResolver.openOutputStream(uri)?.use { fos ->
|
contentResolver.openOutputStream(uri)?.use { fos ->
|
||||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
|
||||||
}
|
}
|
||||||
|
@ -339,20 +347,62 @@ class MainActivity : FlutterActivity() {
|
||||||
private fun androidSecureFlag(flag: Boolean) {
|
private fun androidSecureFlag(flag: Boolean) {
|
||||||
uiThreadHandler.post {
|
uiThreadHandler.post {
|
||||||
if (flag) {
|
if (flag) {
|
||||||
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
|
window.setFlags(
|
||||||
|
WindowManager.LayoutParams.FLAG_SECURE,
|
||||||
|
WindowManager.LayoutParams.FLAG_SECURE
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compressBitMap(bitmap: Bitmap): ByteArray {
|
// withCoroutine -> queue
|
||||||
val bos = ByteArrayOutputStream()
|
private fun auth(): Boolean {
|
||||||
bos.use { bos ->
|
var queue = LinkedBlockingQueue<Boolean>()
|
||||||
Log.d("BITMAP", bitmap.width.toString())
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos)
|
var mBiometricPrompt = BiometricPrompt.Builder(this)
|
||||||
|
.setTitle("验证身份")
|
||||||
|
.setDescription("需要验证您的身份")
|
||||||
|
.setNegativeButton(
|
||||||
|
"取消", mainExecutor
|
||||||
|
) { _, _ -> queue.add(false) }
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
var mCancellationSignal = CancellationSignal()
|
||||||
|
mCancellationSignal.setOnCancelListener {
|
||||||
|
queue.add(false)
|
||||||
}
|
}
|
||||||
return bos.toByteArray()
|
|
||||||
|
var mAuthenticationCallback = object : BiometricPrompt.AuthenticationCallback() {
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
|
||||||
|
super.onAuthenticationError(errorCode, errString)
|
||||||
|
queue.add(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
super.onAuthenticationFailed()
|
||||||
|
queue.add(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationSucceeded(result1: BiometricPrompt.AuthenticationResult?) {
|
||||||
|
super.onAuthenticationSucceeded(result1)
|
||||||
|
queue.add(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mBiometricPrompt.authenticate(
|
||||||
|
mCancellationSignal,
|
||||||
|
mainExecutor,
|
||||||
|
mAuthenticationCallback
|
||||||
|
)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
queue.add(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queue.poll(5, TimeUnit.MINUTES) ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,7 @@ buildscript {
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
maven { url('https://maven.aliyun.com/repository/public') }
|
||||||
jcenter()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pikapika/basic/config/Platform.dart';
|
||||||
|
|
||||||
import '../Common.dart';
|
import '../Common.dart';
|
||||||
import '../Method.dart';
|
import '../Method.dart';
|
||||||
|
@ -30,9 +31,7 @@ Future<void> _chooseAuthentication(BuildContext context) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget authenticationSetting() {
|
Widget authenticationSetting() {
|
||||||
if (Platform.isIOS != true) {
|
if (Platform.isIOS) {
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
return StatefulBuilder(
|
return StatefulBuilder(
|
||||||
builder: (BuildContext context, void Function(void Function()) setState) {
|
builder: (BuildContext context, void Function(void Function()) setState) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
@ -45,4 +44,19 @@ Widget authenticationSetting() {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} else if (androidVersion >= 29) {
|
||||||
|
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(() {});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue