Flutter 插件(调用原生方法--Android)

    调用原生方法(以跳转到设置页面设置是否开启通知权限为例):

首先在flutter项目的android下创建一个NotificationSetUtil(kotlin)工具类

首先判断是否开启了通知权限,可以通过NotificationManagerCompat 中的 areNotificationsEnabled()来判断是否开启通知权限

@RequiresApi(api = Build.VERSION_CODES.KITKAT)

fun isNotificationEnabled(context: Context): Boolean {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

        val notificationManagerCompat = NotificationManagerCompat.from(context)

        return notificationManagerCompat.areNotificationsEnabled()

    }

    val CHECK_OP_NO_THROW ="checkOpNoThrow"

    val OP_POST_NOTIFICATION ="OP_POST_NOTIFICATION"

    val mAppOps = context.getSystemService(Context.APP_OPS_SERVICE)as AppOpsManager

    val appInfo = context.applicationInfo

    val pkg = context.applicationContext.packageName

    val uid = appInfo.uid

    var appOpsClass: Class<*>? =null

    /* Context.APP_OPS_MANAGER */

    try {

        appOpsClass = Class.forName(AppOpsManager::class.java.name)

        val checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE,

                String::class.java)

        val opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION)

        val value = opPostNotificationValue[Int::class.java]as Int

        return checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg)as Int == AppOpsManager.MODE_ALLOWED

    }catch (e: Exception) {

        e.printStackTrace()

    }

    return false

}

再生成一个跳转到设置页面开启通知权限的方法(Android 8.0,Android 5.0-7.0,和Android 5.0以下的区分设置):

fun gotoSet(context: Context) {

    val intent = Intent()

    if (Build.VERSION.SDK_INT >=26) {

        // android 8.0引导

        intent.action ="android.settings.APP_NOTIFICATION_SETTINGS"

        intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)

    }else if (Build.VERSION.SDK_INT >=21) {

        // android 5.0-7.0

        intent.action ="android.settings.APP_NOTIFICATION_SETTINGS"

        intent.putExtra("app_package", context.packageName)

        intent.putExtra("app_uid", context.applicationInfo.uid)

    }else {

        // 其他

        intent.action ="android.settings.APPLICATION_DETAILS_SETTINGS"

        intent.data = Uri.fromParts("package", context.packageName, null)

    }

    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

    context.startActivity(intent)

}

再做一个返回结果的监听:

interface OnNextLitener {

    fun onNext()

    fun hasPermission(hasPremission: Boolean)

}

生成判断是否需要打开设置打开通知权限:

@RequiresApi(api = Build.VERSION_CODES.KITKAT)

fun OpenNotificationSetting(context: Context, mOnNextLitener: OnNextLitener?) {

    if (!isNotificationEnabled(context)) {

        mOnNextLitener?.hasPermission(false)

        //                gotoSet(context)

    }else {

        mOnNextLitener?.onNext()

    }

}

至此,这个工具类就完成了(该类的完整代码会在文章最后贴出)。

在相同目录下,生成插件类NotificationtProviderPlugin

首先声明一个Channel名称(要注意这个ChannelName)

private const val ChannelName ="com.example.app_nh.plugins/notification"

注册通知插件(要注意when方法内的methodCall.method的两个值:getNotification、gotoset):

@JvmStatic

fun register(context: Context, messenger: BinaryMessenger) = MethodChannel(messenger,             ChannelName).setMethodCallHandler{ methodCall, result->

       when (methodCall.method) {

            "getNotification" ->if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

                //判断是否需要开启通知栏功能

                NotificationSetUtil.OpenNotificationSetting(context, object : NotificationSetUtil.OnNextLitener {

                    override fun onNext() {

                        result.success(true)

                     }

                    override fun hasPermission(hasPremission: Boolean) {

                        result.success(false)

                    }

                })

            }

            "gotoset" -> NotificationSetUtil.gotoSet(context)

        }

    result.success(null)//没有返回值,所以直接返回为null

}

到这一步,关于Android 设置开启通知权限的代码就完成了,但是还需要在MainActivity文件中注册一次,如下:

NotificationtProviderPlugin.register(this, flutterEngine.dartExecutor.binaryMessenger)

到这里,整个插件开发完成了,剩下的就是需要在flutter代码中调用:

首先要声明一个MethodChannel(下方代码括号中的名称要和上述Android 代码中的ChannelName相匹配,才能达到一对一的关系):

static const _platform = const MethodChannel('com.example.app_nh.plugins/notification');

判断是否有通知权限:

var hasPermission = await _platform.invokeMethod('getNotification');

没有通知权限就弹窗提醒是否跳转至设置页面开启:

if (!hasPermission) {

    showDialog(

        context:context,

          barrierDismissible:true,

          builder: (BuildContext context) {

                return SetPermissionDialog(

                    text:"需要开启通知权限,是否前往设置页面开启",

                      onPressed: () {

                            Navigator.of(context).pop();

                            _platform.invokeMethod('gotoset');

                      },

                );

      });

}

上面代码中_platform.invokeMethod()括号中的字段同样要和上述Android 代码中methodCall.method的两个值一一对应来完成Android 方法的调用。

下面附上NotificationtProviderPlugin类和NotificationSetUtil类的完整代码:

NotificationSetUtil:

import android.app.AppOpsManager

import android.content.Context

import android.content.Intent

import android.net.Uri

import android.os.Build

import androidx.annotation.RequiresApi

import androidx.core.app.NotificationManagerCompat

class NotificationSetUtil {

    interface OnNextLitener {

        fun onNext()

        fun hasPermission(hasPremission: Boolean)

    }

    private var mOnNextLitener: OnNextLitener? =null

    fun setOnNextLitener(mOnNextLitener: OnNextLitener?) {

        this.mOnNextLitener = mOnNextLitener

    }

    companion object {

        //判断是否需要打开设置界面

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)

        fun OpenNotificationSetting(context: Context, mOnNextLitener: OnNextLitener?) {

            if (!isNotificationEnabled(context)) {

                mOnNextLitener?.hasPermission(false)

                //                gotoSet(context)

            }else {

                mOnNextLitener?.onNext()

            }

       }

        //判断该app是否打开了通知

        /**

         * 可以通过NotificationManagerCompat 中的 areNotificationsEnabled()来判断是否开启通知权限。

         * API 在19以下 一直是true

        */

        @RequiresApi(api = Build.VERSION_CODES.KITKAT)

        fun isNotificationEnabled(context: Context): Boolean {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

                val notificationManagerCompat = NotificationManagerCompat.from(context)

                return notificationManagerCompat.areNotificationsEnabled()

            }

            val CHECK_OP_NO_THROW ="checkOpNoThrow"

            val OP_POST_NOTIFICATION ="OP_POST_NOTIFICATION"

            val mAppOps = context.getSystemService(Context.APP_OPS_SERVICE)as AppOpsManager

            val appInfo = context.applicationInfo

            val pkg = context.applicationContext.packageName

            val uid = appInfo.uid

            var appOpsClass: Class<*>? =null

            /* Context.APP_OPS_MANAGER */

            try {

                appOpsClass = Class.forName(AppOpsManager::class.java.name)

                val checkOpNoThrowMethod =appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE,             Integer.TYPE,  String::class.java)

                val opPostNotificationValue =appOpsClass.getDeclaredField(OP_POST_NOTIFICATION)

                val value = opPostNotificationValue[Int::class.java]as Int

                return checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg)as Int == AppOpsManager.MODE_ALLOWED

            }catch (e: Exception) {

                e.printStackTrace()

            }

        return false

  }

        //打开手机设置页面

        fun gotoSet(context: Context) {

            val intent = Intent()

            if (Build.VERSION.SDK_INT >=26) {

                // android 8.0引导

                intent.action ="android.settings.APP_NOTIFICATION_SETTINGS"

                intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)

            }else if (Build.VERSION.SDK_INT >=21) {

                // android 5.0-7.0

                intent.action ="android.settings.APP_NOTIFICATION_SETTINGS"

                intent.putExtra("app_package", context.packageName)

                intent.putExtra("app_uid", context.applicationInfo.uid)

            }else {

                // 其他

                intent.action ="android.settings.APPLICATION_DETAILS_SETTINGS"

                intent.data = Uri.fromParts("package", context.packageName, null)

            }

            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

            context.startActivity(intent)

        }

    }

}

NotificationtProviderPlugin:

import android.content.Context

import android.os.Build

import com.example.app_nh.NotificationSetUtil

import io.flutter.plugin.common.BinaryMessenger

import io.flutter.plugin.common.MethodChannel

object NotificationtProviderPlugin {

    /** Channel名称  **/

    private const val ChannelName ="com.example.app_nh.plugins/notification"

    /**

    * 注册通知插件

    */

    @JvmStatic

    fun register(context: Context, messenger: BinaryMessenger) = MethodChannel(messenger,     ChannelName).setMethodCallHandler{ methodCall, result->

        when (methodCall.method) {

            "getNotification" ->if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

                //判断是否需要开启通知栏功能

                NotificationSetUtil.OpenNotificationSetting(context, object : NotificationSetUtil.OnNextLitener {

                    override fun onNext() {

                        result.success(true)

                    }

                    override fun hasPermission(hasPremission: Boolean) {

                        result.success(false)

                    }

               })

            }

            "gotoset" -> NotificationSetUtil.gotoSet(context)

        }

    result.success(null)//没有返回值,所以直接返回为null

    }

}

你可能感兴趣的:(Flutter 插件(调用原生方法--Android))