阅读 142

NFC权限在MIUI系统中需要运行时权限

在谷歌原生系统中NFC权限属于正常权限,但是在MIUI系统中,NFC权限被声明为运行时权限并且在使用相关功能时,系统会弹窗告知用户是否允许,用户也可以在应用设置界面开启或者关闭NFC权限。(暂未查询到MIUI几开始引入)

NFC

Added in API level 9

public static final String NFC 复制代码

Allows applications to perform I/O operations over NFC.

Protection level: normal

Constant Value: "android.permission.NFC"

正常用法:

AndroidManifest.xml文件中声明权限即可正常使用NFC相关功能

    <uses-permission android:name="android.permission.NFC"/> 复制代码

MIUI运行时用户确认

在App首次调用相关NFC系统API时,会触发系统弹窗让用户授权App是否允许使用NFC。用户也可以直接在应用权限管理界面设置NFC权限的开启与关闭。

如果用户未在倒计时结束前允许、主动关闭权限,那么在使用NFC的读卡器模式(其他模式猜测一致)读卡时会报IOException。

MIUI检查App是否获取了NFC权限

利用反射 AppOpsManager#checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName)获取op值对应权限的授权状态,NFC的op为10016,返回值0表示允许,1表示禁止,5表示询问

Android权限管理源码解析就能了解权限相关状态的存储位置为/data/system/appOps/xxx.xml
用一台root的MIUI手机查看相关xml文件能找到NFC的op值为10016

//检查NFC权限的核心代码 @IntDef(value = [PERMISSION_GRANTED, PERMISSION_DENIED, PERMISSION_ASK, PERMISSION_UNKNOWN]) @kotlin.annotation.Retention(     AnnotationRetention.SOURCE ) annotation class PermissionResult {     companion object {         /**          * Permission check result: this is returned by [.check]          * if the permission has been granted to the given package.          */         const val PERMISSION_GRANTED = 0         /**          * Permission check result: this is returned by [.check]          * if the permission has not been granted to the given package.          */         const val PERMISSION_DENIED = -1         const val PERMISSION_ASK = 1         const val PERMISSION_UNKNOWN = 2     } } /**  * 检测NFC权限是否有授权.  */ @PermissionResult @RequiresApi(Build.VERSION_CODES.KITKAT) fun checkNfcPermission(context: Context): Int {     try {         val mAppOps = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager         val pkg = context.applicationContext.packageName         val uid = context.applicationInfo.uid         val appOpsClass = Class.forName(AppOpsManager::class.java.name)         val checkOpNoThrowMethod = appOpsClass.getDeclaredMethod(             "checkOpNoThrow", Integer.TYPE, Integer.TYPE,             String::class.java         )         //the ops of NFC is 10016,check /data/system/appops/xxx.xml         val invoke = checkOpNoThrowMethod.invoke(mAppOps, 10016, uid, pkg)         if (invoke == null) {             Logger.get().println(                 "MIUI check permission checkOpNoThrowMethod(AppOpsManager) invoke result is null"             )             return PERMISSION_UNKNOWN         }         val result = invoke.toString()         Logger.get().println(             "MIUI check permission checkOpNoThrowMethod(AppOpsManager) invoke result = $result"         )         when (result) {             "0" -> return PERMISSION_GRANTED             "1" -> return PERMISSION_DENIED             "5" -> return PERMISSION_ASK         }     } catch (e: Exception) {         Logger.get().println("check nfc permission fail ${e.message}", e)     }     return PERMISSION_UNKNOWN } 复制代码

最佳做法

场景1:用户正常打开NFC读卡界面,等待NFC后续读取到卡标签


作者:河婆墟邓紫棋
链接:https://juejin.cn/post/7030819721851174942

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐