小米、Vivo、Oppo后台弹出界面权限检测
记录一个开发中遇到App退到后台startActivity无法跳转问题
背景
公司App需求,从App切到第三方App时,需要在最顶层展示一个“返回”按钮,点击后一键切换回自己App~
然后用WindowManager撸了一个悬浮框,点击悬浮框时startActivity,华为手机一切正常。
测了一台小米手机才发现,startActivity调用了不生效并不会跳转~但我确信不是代码问题,肯定是雷布斯又做了什么定制
问题原因
度娘了一下才知道,原来小米、vivo等厂商为了不让后台应用乱弹广告,增加了一项“后台弹出界面”的权限,默认是禁止的,小米手机可见:小米关于默认关闭“后台弹出页面”权限的通知
不得不说出发点是好的,但并没有提供代码申请此权限,甚至连授权权限的页面都各不一样,设置里找半天才能找到这个块设置
由于我们小团队小项目,也没资格找厂商谈判默认打开,所以只能通过提示引导用户去手动打开~
但又不能一股脑的就喊用户去设置,有些手机是不需要这个权限的,至少得判断当前是否有这个权限,没权限的时候再喊用户去设置,这就合理多了,然后又开始了一轮度娘~
检测方法
直接上代码
小米:
private fun isXiaomiBgStartPermissionAllowed(context: Context): Boolean {
val ops = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
try {
val op = 10021
val method: Method = ops.javaClass.getMethod("checkOpNoThrow", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType, String::class.java)
val result = method.invoke(ops, op, android.os.Process.myUid(), context.packageName) as Int
return result == AppOpsManager.MODE_ALLOWED
} catch (e: Exception) {
e.printStackTrace()
}
return false
}
Vivo:
private fun isVivoBgStartPermissionAllowed(context: Context): Boolean {
return getVivoBgStartPermissionStatus(context) == 0
}
/**
* 判断Vivo后台弹出界面状态, 1无权限,0有权限
* @param context context
*/
private fun getVivoBgStartPermissionStatus(context: Context): Int {
val uri: Uri = Uri.parse("content://com.vivo.permissionmanager.provider.permission/start_bg_activity")
val selection = "pkgname = ?"
val selectionArgs = arrayOf(context.packageName)
var state = 1
try {
context.contentResolver.query(uri, null, selection, selectionArgs, null)?.use {
if (it.moveToFirst()) {
state = it.getInt(it.getColumnIndex("currentstate"))
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return state
}
判断当前手机厂商:
fun isXiaoMi(): Boolean {
return checkManufacturer("xiaomi")
}
fun isOppo(): Boolean {
return checkManufacturer("oppo")
}
fun isVivo(): Boolean {
return checkManufacturer("vivo")
}
private fun checkManufacturer(manufacturer: String): Boolean {
return manufacturer.equals(Build.MANUFACTURER, true)
}
完整代码:
object RomUtils {
private val TAG = RomUtils::class.java.simpleName
fun isXiaoMi(): Boolean {
return checkManufacturer("xiaomi")
}
fun isOppo(): Boolean {
return checkManufacturer("oppo")
}
fun isVivo(): Boolean {
return checkManufacturer("vivo")
}
private fun checkManufacturer(manufacturer: String): Boolean {
return manufacturer.equals(Build.MANUFACTURER, true)
}
fun isBackgroundStartAllowed(context: Context): Boolean {
if (isXiaoMi()) {
return isXiaomiBgStartPermissionAllowed(context)
}
if (isVivo()) {
return isVivoBgStartPermissionAllowed(context)
}
if (isOppo() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return Settings.canDrawOverlays(context)
}
return true
}
private fun isXiaomiBgStartPermissionAllowed(context: Context): Boolean {
val ops = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
try {
val op = 10021
val method: Method = ops.javaClass.getMethod("checkOpNoThrow", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType, String::class.java)
val result = method.invoke(ops, op, android.os.Process.myUid(), context.packageName) as Int
return result == AppOpsManager.MODE_ALLOWED
} catch (e: Exception) {
e.printStackTrace()
}
return false
}
private fun isVivoBgStartPermissionAllowed(context: Context): Boolean {
return getVivoBgStartPermissionStatus(context) == 0
}
/**
* 判断Vivo后台弹出界面状态, 1无权限,0有权限
* @param context context
*/
private fun getVivoBgStartPermissionStatus(context: Context): Int {
val uri: Uri = Uri.parse("content://com.vivo.permissionmanager.provider.permission/start_bg_activity")
val selection = "pkgname = ?"
val selectionArgs = arrayOf(context.packageName)
var state = 1
try {
context.contentResolver.query(uri, null, selection, selectionArgs, null)?.use {
if (it.moveToFirst()) {
state = it.getInt(it.getColumnIndex("currentstate"))
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return state
}
}