【Android】MIUI不能点小浮窗回到应用问题

1,762 阅读2分钟

问题描述

在我们的交互设计中,当应用退到后台时,会显示一个小的悬浮窗,点击这个悬浮窗就跳回应用。

跳回应用的代码实现:

private fun backToApp() {
		val intent = Intent(this, MainActivity::class.java)
		try {
			val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
			pendingIntent.send()
		} catch (e: Exception) {
			e.printStackTrace()
			RNLog.e(e.toString())
		}
}
  • 注意,这里一定要用PendingIntent,不能直接startActivity,不然回到应用的速度非常慢,在1s以上。

讲道理,这个代码没有任何问题,然后测试报了个bug说,小米MIX3机型上,点击悬浮窗没有反应。


问题分析

打日志,看到点击悬浮窗后,logcat有一条报错日志:

ExtraActivityManagerService: MIUILOG- Permission Denied Activity

上网一搜,发现这是MIUI自己搞事情: MIUI默认关闭"后台弹出页面"权限

所以,想要能正常跳回应用,还需要开启一个权限: MIUI权限


问题解决

解决这个问题,思路是明确的:

  1. 判断是MIUI系统
  2. 代码实现检测“后台弹出界面”是否已授权
  3. 跳转应用权限设置,让用户设置“后台弹出界面”权限

网上有一些文章写了这个问题怎么处理了,但是讲得都不那么全,有的还有一些奇奇怪怪的处理方法。我把这些东西大致看了一下,大胆假设,小心求证,去伪存真,总结出了正确答案。

// 判断是MIUI系统
private fun isMIUI(): Boolean {
		val device = Build.MANUFACTURER
		if (device == "Xiaomi") {
			val code = SystemPropertiesProxy.get("ro.miui.ui.version.code", "")
			val version = SystemPropertiesProxy.get("ro.miui.ui.version.name", "")
			Logger.d("The device is MIUI $code, version: $version" )
			if (code.isNotEmpty() || version.isNotEmpty()) {
				return true
			}
		}
		return false
}

// SystemPropertiesProxy这个是对SystemProperties hidden API的反射封装,GitHub上一搜一大把
// 代码实现检测“后台弹出界面”是否已授权
// op: 10021 这个是某位大哥在评论里回复的,测试可用
private fun checkPermissionInternal(): Boolean {
		val manager = mReactContext.getSystemService(APP_OPS_SERVICE) as AppOpsManager
		return try {
			val clazz = AppOpsManager::class.java
			val method = clazz.getDeclaredMethod("checkOp", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType, String::class.java)
			val op = 10021
			AppOpsManager.MODE_ALLOWED == method.invoke(manager, op, getCallingUid(), mReactContext.packageName) as Int
		} catch (e: Exception) {
			Logger.e(getStackTraceString(e))
			false
		}
}
// 跳转应用权限设置,让用户设置“后台弹出界面”权限
// 这个在小米官方dev文档里有写
fun requestBackPermission() {
		val intent = Intent()
		intent.action = "miui.intent.action.APP_PERM_EDITOR"
		intent.addCategory(Intent.CATEGORY_DEFAULT)
		intent.putExtra("extra_pkgname", mReactContext.packageName)
		currentActivity?.let {
			it.startActivity(intent)
		}
}

参考

juejin.cn/post/684490…

dev.mi.com/docs/appsma…

www.jianshu.com/p/366ad637e…

gist.github.com/olegcherr/d…