diff --git a/README.md b/README.md index 9d6f0ad..f7474fb 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,11 @@ If the `PermissionStatus` is `denied` or `unknown`, we can ask the user for the Future permissionStatus = NotificationPermissions.requestNotificationPermissions({NotificationSettingsIos iosSettings, bool openSettings}); ``` -On Android, if the permission is `denied`, this method will open the app settings. +On Android 12 and lower, if the permission is `denied`, this method will open the app settings. +On Android 13 and higher system dialog asking for permission will be displayed. To be able to request permission on Android 13+ add the following permission to `AndroidManifest.xml`: +```xml + +``` In iOS, if the permission is `unknown` or `provisional`, it will show an alert window asking the user for the permission. On the other hand, if the permission is `denied` it has the same behaviour as Android, opening the app settings. Also in iOS if you set `openSettings` to false settings window won't be opened. You will get `denied` status. diff --git a/android/build.gradle b/android/build.gradle index 0b6025c..2579380 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -22,7 +22,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 29 + compileSdkVersion 33 defaultConfig { minSdkVersion 16 diff --git a/android/src/main/java/com/vanethos/notification_permissions/MethodCallHandlerImpl.java b/android/src/main/java/com/vanethos/notification_permissions/MethodCallHandlerImpl.java index e53e1a6..4776c2d 100644 --- a/android/src/main/java/com/vanethos/notification_permissions/MethodCallHandlerImpl.java +++ b/android/src/main/java/com/vanethos/notification_permissions/MethodCallHandlerImpl.java @@ -1,24 +1,36 @@ package com.vanethos.notification_permissions; +import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.provider.Settings; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.NotificationManagerCompat; + import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.PluginRegistry; -public class MethodCallHandlerImpl implements MethodCallHandler { +public class MethodCallHandlerImpl implements MethodCallHandler, PluginRegistry.RequestPermissionsResultListener { private static final String PERMISSION_GRANTED = "granted"; private static final String PERMISSION_DENIED = "denied"; + private static final int REQUEST_CODE = MethodCallHandlerImpl.class.hashCode(); + private final Context applicationContext; - @Nullable private Activity activity; + + @Nullable + private Activity activity; + + @Nullable + private MethodChannel.Result permissionRequestResult; public MethodCallHandlerImpl(Context applicationContext) { this.applicationContext = applicationContext; @@ -26,6 +38,7 @@ public MethodCallHandlerImpl(Context applicationContext) { public void setActivity(@Nullable Activity activity) { this.activity = activity; + this.permissionRequestResult = null; } @Override @@ -41,6 +54,13 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result return; } + // Since TIRAMISU (API level 33) POST_NOTIFICATIONS permission can be requested + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + permissionRequestResult = result; + activity.requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_CODE); + return; + } + // https://stackoverflow.com/a/45192258 final Intent intent = new Intent(); @@ -69,9 +89,26 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result } } + @Override + public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode != REQUEST_CODE || permissions.length == 0) { + return false; + } + + if (permissionRequestResult != null) { + permissionRequestResult.success( + grantResults[0] == PackageManager.PERMISSION_GRANTED + ? PERMISSION_GRANTED + : PERMISSION_DENIED + ); + } + + return true; + } + private String getNotificationPermissionStatus() { return (NotificationManagerCompat.from(applicationContext).areNotificationsEnabled()) - ? PERMISSION_GRANTED - : PERMISSION_DENIED; + ? PERMISSION_GRANTED + : PERMISSION_DENIED; } } diff --git a/android/src/main/java/com/vanethos/notification_permissions/NotificationPermissionsPlugin.java b/android/src/main/java/com/vanethos/notification_permissions/NotificationPermissionsPlugin.java index ac2b454..381ca20 100644 --- a/android/src/main/java/com/vanethos/notification_permissions/NotificationPermissionsPlugin.java +++ b/android/src/main/java/com/vanethos/notification_permissions/NotificationPermissionsPlugin.java @@ -2,8 +2,10 @@ import android.app.Activity; import android.content.Context; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; @@ -27,6 +29,9 @@ public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registra @Nullable private MethodCallHandlerImpl methodCallHandler; + @Nullable + ActivityPluginBinding activityPluginBinding; + @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { onAttachedToEngine(binding.getApplicationContext(), binding.getBinaryMessenger()); @@ -48,7 +53,9 @@ private void onAttachedToEngine(Context applicationContext, BinaryMessenger mess @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { + activityPluginBinding = binding; onActivityChanged(binding.getActivity()); + startListeningForPermissionResult(); } @Override @@ -64,6 +71,7 @@ public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBindin @Override public void onDetachedFromActivity() { onActivityChanged(null); + stopListeningForPermissionResult(); } private void onActivityChanged(@Nullable Activity activity) { @@ -71,4 +79,16 @@ private void onActivityChanged(@Nullable Activity activity) { methodCallHandler.setActivity(activity); } } + + private void startListeningForPermissionResult() { + if (this.activityPluginBinding != null && methodCallHandler != null) { + activityPluginBinding.addRequestPermissionsResultListener(methodCallHandler); + } + } + + private void stopListeningForPermissionResult() { + if (this.activityPluginBinding != null && methodCallHandler != null) { + activityPluginBinding.removeRequestPermissionsResultListener(methodCallHandler); + } + } } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 56bfa9b..004dcd3 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 30 + compileSdkVersion 33 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -45,7 +45,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.example" minSdkVersion 16 - targetSdkVersion 30 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 34dd77e..cb524b4 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,10 +1,14 @@ + + +