首页 > 编程知识 正文

小米手机开启nfc功能为什么没反应,小米手机打开nfc权限

时间:2023-05-03 12:32:07 阅读:230032 作者:499

一、遇到奇葩问题

最近的项目需求有个NFC刷卡的功能,按照正常的流程,在AndroidManifest.xml中添加<uses-permission android:name="android.permission.NFC" />,然后在Activity中正常处理NFC逻辑就行了,我也是这么干的,我的一加七妥妥的正常运行,但是测试拿着一台小米9来跟我说有bug,what the fxxx?

如上图,NFC的权限级别不是normal么?为什么小米会有这个选项?我的一加七就没有。重点是小米如果把这个NFC权限设为拒绝,那就不能正常读卡了。那么问题来,如何判断用户是否已经允许了这个NFC权限呢?

SoEasy啦,很自然的敲下代码,ContextCompat.checkSelfPermission(this, Manifest.permission.NFC),结果呢?无论我把NFC设置成“允许”还是“拒绝”,这个方法都返回PERMISSION_GRANTED!!!那么问题又来了,官方的API已经不能满足了,我们该如何优雅的判断用户是否已经允许了NFC权限呢?

二、解决方法

这里直接上解决方法,后面再一步一步记录一下是怎么找到这个方法的,赶进度的你们直接复制这个代码就行了,后面不用看了。

/** * @param op * * op=10016 对应 NFC * * op=10021 对应 后台弹出界面 * * 其它未知,根据博客的方法自己去找你需要的 * @return true为允许,false为询问或者拒绝。 */fun checkOpPermission(context: Context, op: Int): Boolean { return try { val manager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager val method = manager.javaClass.getMethod("checkOpNoThrow", Int::class.java, Int::class.java, String::class.java) val result = method.invoke(manager, op, Process.myUid(), context.packageName) AppOpsManager.MODE_ALLOWED == result } catch (e: Exception) { e.printStackTrace() false }} 三、寻找解决方法的过程

碰到问题肯定先百度啦,百度了各种方法都不起作用,各种被虐啊,后来经同事提醒,找到了这个博客https://blog.csdn.net/GuangkuoDing/article/details/100324162,这种方法很类似啊,但是它是判断“后台弹出界面”权限的,op=10021,一个op对应这一个权限选项,那么问题来了,我怎么知道“NFC”权限的op是多少呢?

经过各种摸索,终于让我找到了思路,理论上不仅可以找到NFC的,还可以找到所有你看得到的,你需要的。
其实这之前我还尝试了从源码中寻找啊,查看系统LOG啊等等方法,但是都走不通,才想到这个的,本来想全都写下来的,想想还是算了,简单粗暴点,直接给结果。

思路:
1、遍历一个范围内的op,看看那些没有抛异常,就证明那些op有对应的选项,这样就可以知道一个大概范围了。
2、手动把全部权限都关了,只允许NFC权限,遍历一下刚才那个范围的op,会得到一堆已允许的op,其中必定有一个是NFC。
3、把NFC权限也拒绝了,遍历一下上面得到的那一堆已允许的op,其中必定有一个是拒绝的,这个就是NFC了。

1、遍历一定范围op for (op in 10000..10030) { try { val manager = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager val method = manager.javaClass.getMethod("checkOpNoThrow", Int::class.java, Int::class.java, String::class.java) method.invoke(manager, op, Process.myUid(), packageName) Log.i("hello", "op=$op 正常op") } catch (e: Exception) { Log.i("hello", "op=$op 抛异常,无意义op") }}

这里只是遍历了10000…10030,是我随机写的,没想到刚刚好,下面是打印结果,从结果来看op的范围就是10001-10027。

2019-11-28 16:37:47.779 11103-11103/com.audient.androidall I/hello: op=10000 抛异常,无意义op2019-11-28 16:37:47.780 11103-11103/com.audient.androidall I/hello: op=10001 正常op2019-11-28 16:37:47.780 11103-11103/com.audient.androidall I/hello: op=10002 正常op2019-11-28 16:37:47.780 11103-11103/com.audient.androidall I/hello: op=10003 正常op2019-11-28 16:37:47.781 11103-11103/com.audient.androidall I/hello: op=10004 正常op2019-11-28 16:37:47.781 11103-11103/com.audient.androidall I/hello: op=10005 正常op2019-11-28 16:37:47.781 11103-11103/com.audient.androidall I/hello: op=10006 正常op2019-11-28 16:37:47.781 11103-11103/com.audient.androidall I/hello: op=10007 正常op2019-11-28 16:37:47.782 11103-11103/com.audient.androidall I/hello: op=10008 正常op2019-11-28 16:37:47.782 11103-11103/com.audient.androidall I/hello: op=10009 正常op2019-11-28 16:37:47.782 11103-11103/com.audient.androidall I/hello: op=10010 正常op2019-11-28 16:37:47.782 11103-11103/com.audient.androidall I/hello: op=10011 正常op2019-11-28 16:37:47.782 11103-11103/com.audient.androidall I/hello: op=10012 正常op2019-11-28 16:37:47.783 11103-11103/com.audient.androidall I/hello: op=10013 正常op2019-11-28 16:37:47.783 11103-11103/com.audient.androidall I/hello: op=10014 正常op2019-11-28 16:37:47.783 11103-11103/com.audient.androidall I/hello: op=10015 正常op2019-11-28 16:37:47.784 11103-11103/com.audient.androidall I/hello: op=10016 正常op2019-11-28 16:37:47.784 11103-11103/com.audient.androidall I/hello: op=10017 正常op2019-11-28 16:37:47.784 11103-11103/com.audient.androidall I/hello: op=10018 正常op2019-11-28 16:37:47.784 11103-11103/com.audient.androidall I/hello: op=10019 正常op2019-11-28 16:37:47.785 11103-11103/com.audient.androidall I/hello: op=10020 正常op2019-11-28 16:37:47.785 11103-11103/com.audient.androidall I/hello: op=10021 正常op2019-11-28 16:37:47.785 11103-11103/com.audient.androidall I/hello: op=10022 正常op2019-11-28 16:37:47.785 11103-11103/com.audient.androidall I/hello: op=10023 正常op2019-11-28 16:37:47.786 11103-11103/com.audient.androidall I/hello: op=10024 正常op2019-11-28 16:37:47.786 11103-11103/com.audient.androidall I/hello: op=10025 正常op2019-11-28 16:37:47.786 11103-11103/com.audient.androidall I/hello: op=10026 正常op2019-11-28 16:37:47.786 11103-11103/com.audient.androidall I/hello: op=10027 正常op2019-11-28 16:37:47.787 11103-11103/com.audient.androidall I/hello: op=10028 抛异常,无意义op2019-11-28 16:37:47.787 11103-11103/com.audient.androidall I/hello: op=10029 抛异常,无意义op2019-11-28 16:37:47.787 11103-11103/com.audient.androidall I/hello: op=10030 抛异常,无意义op 2、权限全关,只允许NFC权限,继续遍历

val allowedList = ArrayList<Int>()for (op in 10001..10027) { val allowed = checkOpPermission(this, op) if (allowed) { allowedList.add(op) }}LogUtils.e("hello", allowedList)

allowedList代表当前所有已允许的权限op列表。
checkOpPermission在文章开头有。
输出结果为:[10002, 10003, 10005, 10006, 10007, 10009, 10010, 10011, 10012, 10013, 10014, 10015, 10016, 10018, 10022, 10023, 10024, 10027]
证明NFC权限必然在这个列表里面,继续往下走。

3、拒绝NFC权限,继续遍历

for (op in arrayOf(10002, 10003, 10005, 10006, 10007, 10009, 10010, 10011, 10012, 10013, 10014, 10015, 10016, 10018, 10022, 10023, 10024, 10027)) { val allowed = checkOpPermission(this, op) if (!allowed) { LogUtils.e("hello", "NFC权限就是这货了,op=$op") }}

上面代码输出:NFC权限就是这货了,op=10016,大功告成!

四、总结

功夫不负有心人。

权限动态申请已经封装成了一个kotlin文件了,拿来就用。传送:https://blog.csdn.net/qiantujava/article/details/103402239

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。