Android 13 compatibility update

This commit is contained in:
Ming Ming 2023-09-02 02:15:41 +08:00
parent 601f5e1af2
commit 150c4c4831
8 changed files with 129 additions and 16 deletions

View file

@ -45,7 +45,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.nkming.nc_photos" applicationId "com.nkming.nc_photos"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 31 targetSdkVersion 33
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
ndk { ndk {

View file

@ -3,10 +3,13 @@
package="com.nkming.nc_photos"> package="com.nkming.nc_photos">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" android:maxSdkVersion="29"
tools:ignore="ScopedStorage" /> tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application <application
android:name=".App" android:name=".App"

View file

@ -3,15 +3,24 @@ import 'package:nc_photos/stream_extension.dart';
import 'package:np_platform_permission/np_platform_permission.dart'; import 'package:np_platform_permission/np_platform_permission.dart';
Future<Map<String, int>> requestPermissionsForResult( Future<Map<String, int>> requestPermissionsForResult(
List<String> permissions) async { List<String> permissions) =>
_doRequest(() => Permission.request(permissions));
Future<Map<String, int>> requestReadExternalStorageForResult() =>
_doRequest(() => Permission.requestReadExternalStorage());
Future<Map<String, int>> requestPostNotificationsForResult() =>
_doRequest(() => Permission.requestPostNotifications());
Future<Map<String, int>> _doRequest(Future Function() op) async {
Map<String, int>? result; Map<String, int>? result;
final resultFuture = Permission.stream final resultFuture = Permission.stream
.whereType<PermissionRequestResult>() .whereType<PermissionRequestResult>()
.first .first
.then((ev) => result = ev.grantResults); .then((ev) => result = ev.grantResults);
await Permission.request(permissions); await op();
await resultFuture; await resultFuture;
_log.info("[requestPermissionsForResult] Result: $result"); _log.info("[_doRequest] Result: $result");
return result!; return result!;
} }

View file

@ -341,11 +341,11 @@ class _EnhancedPhotoBrowserState extends State<EnhancedPhotoBrowser>
if (getRawPlatform() == NpPlatform.android) { if (getRawPlatform() == NpPlatform.android) {
if (AndroidInfo().sdkInt >= AndroidVersion.R) { if (AndroidInfo().sdkInt >= AndroidVersion.R) {
if (!await Permission.hasReadExternalStorage()) { if (!await Permission.hasReadExternalStorage()) {
final results = await requestPermissionsForResult([ final results = await requestReadExternalStorageForResult();
Permission.READ_EXTERNAL_STORAGE,
]);
return results[Permission.READ_EXTERNAL_STORAGE] == return results[Permission.READ_EXTERNAL_STORAGE] ==
PermissionRequestResult.granted; PermissionRequestResult.granted ||
results[Permission.READ_MEDIA_IMAGES] ==
PermissionRequestResult.granted;
} }
} else { } else {
if (!await Permission.hasWriteExternalStorage()) { if (!await Permission.hasWriteExternalStorage()) {

View file

@ -11,6 +11,7 @@ import 'package:nc_photos/entity/pref.dart';
import 'package:nc_photos/entity/sqlite/database.dart' as sql; import 'package:nc_photos/entity/sqlite/database.dart' as sql;
import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/mobile/android/activity.dart'; import 'package:nc_photos/mobile/android/activity.dart';
import 'package:nc_photos/mobile/android/permission_util.dart';
import 'package:nc_photos/use_case/compat/v29.dart'; import 'package:nc_photos/use_case/compat/v29.dart';
import 'package:nc_photos/use_case/compat/v46.dart'; import 'package:nc_photos/use_case/compat/v46.dart';
import 'package:nc_photos/use_case/compat/v55.dart'; import 'package:nc_photos/use_case/compat/v55.dart';
@ -19,6 +20,7 @@ import 'package:nc_photos/widget/home.dart';
import 'package:nc_photos/widget/setup.dart'; import 'package:nc_photos/widget/setup.dart';
import 'package:nc_photos/widget/sign_in.dart'; import 'package:nc_photos/widget/sign_in.dart';
import 'package:np_codegen/np_codegen.dart'; import 'package:np_codegen/np_codegen.dart';
import 'package:np_platform_permission/np_platform_permission.dart';
import 'package:np_platform_util/np_platform_util.dart'; import 'package:np_platform_util/np_platform_util.dart';
import 'package:to_string/to_string.dart'; import 'package:to_string/to_string.dart';
@ -38,7 +40,7 @@ class Splash extends StatefulWidget {
@npLog @npLog
class _SplashState extends State<Splash> { class _SplashState extends State<Splash> {
@override @override
initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_doWork(); _doWork();
@ -46,6 +48,9 @@ class _SplashState extends State<Splash> {
} }
Future<void> _doWork() async { Future<void> _doWork() async {
if (!await Permission.hasPostNotifications()) {
await requestPostNotificationsForResult();
}
if (Pref().getFirstRunTime() == null) { if (Pref().getFirstRunTime() == null) {
await Pref().setFirstRunTime(clock.now().millisecondsSinceEpoch); await Pref().setFirstRunTime(clock.now().millisecondsSinceEpoch);
} }

View file

@ -4,6 +4,8 @@ import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -20,14 +22,20 @@ interface PermissionUtil {
} }
fun hasReadExternalStorage(context: Context): Boolean { fun hasReadExternalStorage(context: Context): Boolean {
return ContextCompat.checkSelfPermission( return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context, Manifest.permission.READ_EXTERNAL_STORAGE hasReadExternalStorage33(context)
) == PackageManager.PERMISSION_GRANTED } else {
hasReadExternalStorage0(context)
}
} }
fun requestReadExternalStorage(activity: Activity) = request( fun requestReadExternalStorage(activity: Activity) {
activity, Manifest.permission.READ_EXTERNAL_STORAGE return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
) requestReadExternalStorage33(activity)
} else {
requestReadExternalStorage0(activity)
}
}
fun hasWriteExternalStorage(context: Context): Boolean { fun hasWriteExternalStorage(context: Context): Boolean {
return ContextCompat.checkSelfPermission( return ContextCompat.checkSelfPermission(
@ -38,5 +46,53 @@ interface PermissionUtil {
fun requestWriteExternalStorage(activity: Activity) = request( fun requestWriteExternalStorage(activity: Activity) = request(
activity, Manifest.permission.WRITE_EXTERNAL_STORAGE activity, Manifest.permission.WRITE_EXTERNAL_STORAGE
) )
fun hasPostNotifications(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
hasPostNotifications33(context)
} else {
true
}
}
fun requestPostNotifications(activity: Activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPostNotifications33(activity)
}
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun hasReadExternalStorage33(context: Context): Boolean {
return ContextCompat.checkSelfPermission(
context, Manifest.permission.READ_MEDIA_IMAGES
) == PackageManager.PERMISSION_GRANTED
}
private fun hasReadExternalStorage0(context: Context): Boolean {
return ContextCompat.checkSelfPermission(
context, Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun requestReadExternalStorage33(activity: Activity) = request(
activity, Manifest.permission.READ_MEDIA_IMAGES
)
private fun requestReadExternalStorage0(activity: Activity) = request(
activity, Manifest.permission.READ_EXTERNAL_STORAGE
)
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun hasPostNotifications33(context: Context): Boolean {
return ContextCompat.checkSelfPermission(
context, Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun requestPostNotifications33(activity: Activity) = request(
activity, Manifest.permission.POST_NOTIFICATIONS
)
} }
} }

View file

@ -93,6 +93,34 @@ internal class PermissionChannelHandler(context: Context) :
} }
} }
"requestReadExternalStorage" -> {
try {
PermissionUtil.requestReadExternalStorage(activity!!)
result.success(null)
} catch (e: Throwable) {
result.error("systemException", e.toString(), null)
}
}
"hasPostNotifications" -> {
try {
result.success(
PermissionUtil.hasPostNotifications(context)
)
} catch (e: Throwable) {
result.error("systemException", e.toString(), null)
}
}
"requestPostNotifications" -> {
try {
PermissionUtil.requestPostNotifications(activity!!)
result.success(null)
} catch (e: Throwable) {
result.error("systemException", e.toString(), null)
}
}
else -> result.notImplemented() else -> result.notImplemented()
} }
} }

View file

@ -9,6 +9,8 @@ import 'package:np_platform_permission/src/k.dart' as k;
class Permission { class Permission {
static const READ_EXTERNAL_STORAGE = static const READ_EXTERNAL_STORAGE =
"android.permission.READ_EXTERNAL_STORAGE"; "android.permission.READ_EXTERNAL_STORAGE";
static const READ_MEDIA_IMAGES =
"android.permission.READ_MEDIA_IMAGES";
static const WRITE_EXTERNAL_STORAGE = static const WRITE_EXTERNAL_STORAGE =
"android.permission.WRITE_EXTERNAL_STORAGE"; "android.permission.WRITE_EXTERNAL_STORAGE";
@ -26,6 +28,16 @@ class Permission {
return (await _methodChannel.invokeMethod<bool>("hasReadExternalStorage"))!; return (await _methodChannel.invokeMethod<bool>("hasReadExternalStorage"))!;
} }
static Future<void> requestReadExternalStorage() =>
_methodChannel.invokeMethod("requestReadExternalStorage");
static Future<bool> hasPostNotifications() async {
return (await _methodChannel.invokeMethod<bool>("hasPostNotifications"))!;
}
static Future<void> requestPostNotifications() =>
_methodChannel.invokeMethod("requestPostNotifications");
static Stream get stream => _eventStream; static Stream get stream => _eventStream;
static final _eventStream = static final _eventStream =