Application lock (Android)

This commit is contained in:
niuhuan 2022-05-15 02:04:54 +08:00
parent 5f3b73d12c
commit b1b020ed83
4 changed files with 115 additions and 51 deletions

View File

@ -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>

View File

@ -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,13 +73,16 @@ 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" -> {
Mobile.flatInvoke( Mobile.flatInvoke(
call.argument("method")!!, call.argument("method")!!,
call.argument("params")!! call.argument("params")!!
) )
} }
"androidSaveFileToImage" -> { "androidSaveFileToImage" -> {
@ -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
} }
@ -107,25 +114,25 @@ class MainActivity : FlutterActivity() {
val eventMutex = Mutex() val eventMutex = Mutex()
var eventSink: EventChannel.EventSink? = null var eventSink: EventChannel.EventSink? = null
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "flatEvent") EventChannel(flutterEngine.dartExecutor.binaryMessenger, "flatEvent")
.setStreamHandler(object : EventChannel.StreamHandler { .setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
events?.let { events -> events?.let { events ->
scope.launch {
eventMutex.lock()
eventSink = events
eventMutex.unlock()
}
}
}
override fun onCancel(arguments: Any?) {
scope.launch { scope.launch {
eventMutex.lock() eventMutex.lock()
eventSink = null eventSink = events
eventMutex.unlock() eventMutex.unlock()
} }
} }
}) }
override fun onCancel(arguments: Any?) {
scope.launch {
eventMutex.lock()
eventSink = null
eventMutex.unlock()
}
}
})
Mobile.eventNotify { message -> Mobile.eventNotify { message ->
scope.launch { scope.launch {
eventMutex.lock() eventMutex.lock()
@ -143,7 +150,7 @@ class MainActivity : FlutterActivity() {
// //
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "volume_button") EventChannel(flutterEngine.dartExecutor.binaryMessenger, "volume_button")
.setStreamHandler(volumeStreamHandler) .setStreamHandler(volumeStreamHandler)
} }
@ -239,16 +246,17 @@ 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)
contentResolver.openOutputStream(uri)?.use { fos -> ?.let { uri ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos) contentResolver.openOutputStream(uri)?.use { fos ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //this one
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { //this one
contentValues.clear()
contentValues.put(MediaStore.Video.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
}
}
} }
} }
@ -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)
}
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 bos.toByteArray()
return queue.poll(5, TimeUnit.MINUTES) ?: false
} }

View File

@ -13,8 +13,7 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
google() maven { url('https://maven.aliyun.com/repository/public') }
jcenter()
} }
} }

View File

@ -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,19 +31,32 @@ Future<void> _chooseAuthentication(BuildContext context) async {
} }
Widget authenticationSetting() { Widget authenticationSetting() {
if (Platform.isIOS != true) { if (Platform.isIOS) {
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(() {});
},
);
},
);
} 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 StatefulBuilder( return Container();
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: const Text("进入APP时验证身份"),
subtitle: Text(_authentication ? "" : ""),
onTap: () async {
await _chooseAuthentication(context);
setState(() {});
},
);
},
);
} }