diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index a881bd4..2e0145d 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
diff --git a/android/app/src/main/kotlin/niuhuan/pikapika/MainActivity.kt b/android/app/src/main/kotlin/niuhuan/pikapika/MainActivity.kt
index 8659a3d..6aecdc3 100644
--- a/android/app/src/main/kotlin/niuhuan/pikapika/MainActivity.kt
+++ b/android/app/src/main/kotlin/niuhuan/pikapika/MainActivity.kt
@@ -1,11 +1,12 @@
package niuhuan.pikapika
import android.content.ContentValues
+import android.content.DialogInterface
import android.graphics.Bitmap
import android.graphics.BitmapFactory
+import android.hardware.biometrics.BiometricPrompt
import android.os.*
import android.provider.MediaStore
-import android.util.DisplayMetrics
import android.util.Log
import android.view.Display
import android.view.KeyEvent
@@ -27,6 +28,8 @@ import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.file.Files
import java.util.concurrent.Executors
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
class MainActivity : FlutterActivity() {
@@ -70,13 +73,16 @@ class MainActivity : FlutterActivity() {
super.configureFlutterEngine(flutterEngine)
Mobile.initApplication(androidDataLocal())
// Method Channel
- MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "method").setMethodCallHandler { call, result ->
+ MethodChannel(
+ flutterEngine.dartExecutor.binaryMessenger,
+ "method"
+ ).setMethodCallHandler { call, result ->
result.withCoroutine {
when (call.method) {
"flatInvoke" -> {
Mobile.flatInvoke(
- call.argument("method")!!,
- call.argument("params")!!
+ call.argument("method")!!,
+ call.argument("params")!!
)
}
"androidSaveFileToImage" -> {
@@ -96,6 +102,7 @@ class MainActivity : FlutterActivity() {
// 获取可以迁移数据地址
"androidGetExtendDirs" -> androidGetExtendDirs()
"androidSecureFlag" -> androidSecureFlag(call.argument("flag")!!)
+ "verifyAuthentication" -> auth()
else -> {
notImplementedToken
}
@@ -107,25 +114,25 @@ class MainActivity : FlutterActivity() {
val eventMutex = Mutex()
var eventSink: EventChannel.EventSink? = null
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "flatEvent")
- .setStreamHandler(object : EventChannel.StreamHandler {
- override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
- events?.let { events ->
- scope.launch {
- eventMutex.lock()
- eventSink = events
- eventMutex.unlock()
- }
- }
- }
-
- override fun onCancel(arguments: Any?) {
+ .setStreamHandler(object : EventChannel.StreamHandler {
+ override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
+ events?.let { events ->
scope.launch {
eventMutex.lock()
- eventSink = null
+ eventSink = events
eventMutex.unlock()
}
}
- })
+ }
+
+ override fun onCancel(arguments: Any?) {
+ scope.launch {
+ eventMutex.lock()
+ eventSink = null
+ eventMutex.unlock()
+ }
+ }
+ })
Mobile.eventNotify { message ->
scope.launch {
eventMutex.lock()
@@ -143,7 +150,7 @@ class MainActivity : FlutterActivity() {
//
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "volume_button")
- .setStreamHandler(volumeStreamHandler)
+ .setStreamHandler(volumeStreamHandler)
}
@@ -239,16 +246,17 @@ class MainActivity : FlutterActivity() {
put(MediaStore.MediaColumns.IS_PENDING, 1)
}
}
- contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)?.let { uri ->
- contentResolver.openOutputStream(uri)?.use { fos ->
- bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos)
+ contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
+ ?.let { uri ->
+ 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) {
uiThreadHandler.post {
if (flag) {
- window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
+ window.setFlags(
+ WindowManager.LayoutParams.FLAG_SECURE,
+ WindowManager.LayoutParams.FLAG_SECURE
+ )
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
}
}
- private fun compressBitMap(bitmap: Bitmap): ByteArray {
- val bos = ByteArrayOutputStream()
- bos.use { bos ->
- Log.d("BITMAP", bitmap.width.toString())
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos)
+ // withCoroutine -> queue
+ private fun auth(): Boolean {
+ var queue = LinkedBlockingQueue()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ 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
}
diff --git a/android/build.gradle b/android/build.gradle
index 7603b16..80a5a45 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -13,8 +13,7 @@ buildscript {
allprojects {
repositories {
- google()
- jcenter()
+ maven { url('https://maven.aliyun.com/repository/public') }
}
}
diff --git a/lib/basic/config/Authentication.dart b/lib/basic/config/Authentication.dart
index 7a251e0..4a6ecb1 100644
--- a/lib/basic/config/Authentication.dart
+++ b/lib/basic/config/Authentication.dart
@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:flutter/material.dart';
+import 'package:pikapika/basic/config/Platform.dart';
import '../Common.dart';
import '../Method.dart';
@@ -30,19 +31,32 @@ Future _chooseAuthentication(BuildContext context) async {
}
Widget authenticationSetting() {
- if (Platform.isIOS != true) {
- return Container();
+ if (Platform.isIOS) {
+ 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(
- 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();
}