Skip to content

Instantly share code, notes, and snippets.

@TheMelody
Last active March 29, 2024 09:05
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save TheMelody/5044dd1b697707b18e94b89f97f55db6 to your computer and use it in GitHub Desktop.
Save TheMelody/5044dd1b697707b18e94b89f97f55db6 to your computer and use it in GitHub Desktop.
打开应用自启动权限-相关代码(自启动权限==白名单管理列表页面)手机系统一直更新,无法保证能一直跳转
/**
* 防止内存泄漏
*/
open class DetachableClickListener(delegate: DialogInterface.OnClickListener?): DialogInterface.OnClickListener {
private var delegateOrNull: DialogInterface.OnClickListener? = delegate
companion object{
fun wrap(delegate: DialogInterface.OnClickListener?): DetachableClickListener? {
return DetachableClickListener(delegate)
}
}
override fun onClick(dialog: DialogInterface?, which: Int) {
delegateOrNull?.onClick(dialog, which)
}
fun clearOnDetach(dialog: AlertDialog) {
dialog.window?.decorView?.viewTreeObserver
?.addOnWindowAttachListener(object : OnWindowAttachListener {
override fun onWindowAttached() {
}
override fun onWindowDetached() {
dialog.window?.decorView?.viewTreeObserver?.removeOnWindowAttachListener(this)
delegateOrNull = null
}
})
}
}
object RomUtil {
private const val TAG = "RomUtil"
private const val HARMONY_OS = "harmony"
private const val ROM_MIUI = "MIUI"
private const val ROM_EMUI = "EMUI"
private const val ROM_FLYME = "FLYME"
private const val ROM_OPPO = "OPPO"
private const val ROM_SMARTISAN = "SMARTISAN"
private const val ROM_VIVO = "VIVO"
private const val ROM_QIKU = "QIKU"
private val KEY_VERSION_MIUI = "ro.miui.ui.version.name"
private val KEY_VERSION_EMUI = "ro.build.version.emui"
private val KEY_VERSION_OPPO = "ro.build.version.opporom"
private val KEY_VERSION_SMARTISAN = "ro.smartisan.version"
private val KEY_VERSION_VIVO = "ro.vivo.os.version"
//华为
fun isEmui(): Boolean {
return check(ROM_EMUI)
}
//小米
fun isMiui(): Boolean {
return check(ROM_MIUI)
}
//vivo
fun isVivo(): Boolean {
return check(ROM_VIVO)
}
//oppo
fun isOppo(): Boolean {
return check(ROM_OPPO)
}
//魅族
fun isFlyme(): Boolean {
return check(ROM_FLYME)
}
//360
fun isQiku(): Boolean {
return check(ROM_QIKU) || check("360")
}
//锤子手机
fun isSmartisan(): Boolean {
return check(ROM_SMARTISAN)
}
//乐视
fun isLetv():Boolean = TextUtils.equals(Build.BRAND.toLowerCase(Locale.getDefault()),"letv")
//三星
fun isSamsung():Boolean = TextUtils.equals(Build.BRAND.toLowerCase(Locale.getDefault()) ,"samsung")
//一加
fun onePlus():Boolean = TextUtils.equals(Build.BRAND.toLowerCase(Locale.getDefault()) , "oneplus")
//鸿蒙系统
fun isHarmonyOS(): Boolean {
try {
val clz = Class.forName("com.huawei.system.BuildEx")
val method: Method = clz.getMethod("getOsBrand")
val classLoader = clz.classLoader
//如果BuildEx为系统提供的,其classloader为BootClassLoader
//如果BuildEx为伪造的,其classloader一般为PathClassLoader
//Log.d(TAG, "classLoader: $classLoader")
//BootClassLoader的parent为null
if (classLoader != null && classLoader.parent == null) {
return HARMONY_OS == method.invoke(clz)
}
} catch (e: ClassNotFoundException) {
} catch (e: NoSuchMethodException) {
} catch (e: Exception) {
}
return false
}
private var sName: String? = null
private var sVersion: String? = null
private fun check(rom: String): Boolean {
if (sName != null) {
return sName == rom
}
if (!TextUtils.isEmpty(getProp(KEY_VERSION_MIUI).also { sVersion = it })) {
sName = ROM_MIUI
} else if (!TextUtils.isEmpty(getProp(KEY_VERSION_EMUI).also { sVersion = it })) {
sName = ROM_EMUI
} else if (!TextUtils.isEmpty(getProp(KEY_VERSION_OPPO).also { sVersion = it })) {
sName = ROM_OPPO
} else if (!TextUtils.isEmpty(getProp(KEY_VERSION_VIVO).also { sVersion = it })) {
sName = ROM_VIVO
} else if (!TextUtils.isEmpty(getProp(KEY_VERSION_SMARTISAN).also {
sVersion = it
})) {
sName = ROM_SMARTISAN
} else {
sVersion = Build.DISPLAY
if (sVersion!!.toUpperCase(Locale.getDefault()).contains(ROM_FLYME)) {
sName = ROM_FLYME
} else {
sVersion = Build.UNKNOWN
sName = Build.MANUFACTURER.toUpperCase(Locale.getDefault())
}
}
return sName == rom
}
private fun getProp(name: String): String? {
val line: String?
var input: BufferedReader? = null
try {
val p = Runtime.getRuntime().exec("getprop $name")
input = BufferedReader(InputStreamReader(p.inputStream), 1024)
line = input.readLine()
input.close()
} catch (ex: IOException) {
Log.e(TAG, "Unable to read prop $name", ex)
return null
} finally {
if (input != null) {
try {
input.close()
} catch (e: IOException) {
Log.e(TAG, "BufferedReader.close()", e)
}
}
}
return line
}
}
<string name="dialog_open_white_list_error_title">跳转失败</string>
<string name="open_white_list_other_tips">由于Android系统限制,请您手动开启本软件自启动权限,并将此软件设置为受保护应用以及允许后台运行,防止被系统关闭</string>
<string name="open_white_list_samsung_tips">请在三星【智能管理器】->【自动运行应用程序】里面找到「划一划手势」并开启,防止被系统关闭</string>
<string name="samsung_open_white_list_failed">请打开【智能管理器】->【自动运行应用程序】里面找到「划一划手势」并开启,加入白名单中,否则设备进入睡眠后会自动杀掉应用进程</string>
<string name="huawei_open_white_list_failed">请打开【手机管家】->【应用启动管理】里面找到「划一划手势」,点击之后弹出【手动管理】窗口,选择「允许后台运行」和「允许自启动」</string>
<string name="flyme_open_white_list_failed">两种方法将应用加入白名单:\n1.找到【手机管家】->【权限管理】->【后台管理】里面找到「划一划手势」选择「允许后台运行」。\n2.打开【设置】->【应用管理】->【所有应用】->【划一划手势】->【权限管理】->【后台管理】选择「允许后台运行」。\n两种方法选择其中一种即可。</string>
<string name="vivo_open_white_list_failed">请按照以下步骤开启应用白名单:\n1.打开【i管家】点击【应用管理】依次打开【自启动管理】和【软件权限管理】找到「划一划手势」并开启选项。\n2.打开【设置】->【电池】->【后台高耗电】找到「划一划手势」并选择开启</string>
<string name="oppo_open_white_list_failed">请打开【设置】->【电池】->【其他】里面找到「划一划手势」点击关闭【后台冻结】和【异常时自动优化】</string>
<string name="miui_open_white_list_failed">请打开【设置】->【电量和性能】->【应用配置】找到「划一划手势」,后台配置选择「不限制」</string>
<string name="oneplus_open_white_list_failed">请打开【设置】->【应用】里面找到「划一划手势」->【电池用量】选择允许后台运行</string>
<string name="smartisan_open_white_list_failed">请按照以下步骤开启应用白名单:\n1.打开【设置】->【安全中心】->【内存清理】找到「划一划手势」并打开「后台常驻」\n2.在【安全中心】->【应用程序权限管理】->【后台自启动】里面找到「划一划手势」,并选择「始终允许」</string>
<string name="other_open_white_list_failed">应用白名单界面跳转失败,请自行前往【手机管家】、【安全管家】或【电池管理】中打开自启动和允许后台运行,将应用加入白名单</string>
////////////////////:具体怎么提示,下面的弹框「仅供参考」////////////////////
/**
* 提示用户打开「白名单管理列表页面」失败(即:自启动权限)
*/
fun openWhiteListErrorDialog(context:Context){
val msgId = when {
RomUtil.isMiui() -> R.string.miui_open_white_list_failed
RomUtil.isSamsung() -> R.string.samsung_open_white_list_failed
RomUtil.isOnePlus() -> R.string.oneplus_open_white_list_failed
RomUtil.isEmui() -> R.string.huawei_open_white_list_failed
RomUtil.isVivo() -> R.string.vivo_open_white_list_failed
RomUtil.isFlyme() -> R.string.flyme_open_white_list_failed
RomUtil.isOppo() -> R.string.oppo_open_white_list_failed
RomUtil.isSmartisan() -> R.string.smartisan_open_white_list_failed
else -> R.string.open_white_list_failed
}
val checkDetachableClickListener = DetachableClickListener.wrap(
DialogInterface.OnClickListener { dialog, _ ->
dialog?.dismiss()
})
val confirmDialog = AlertDialog.Builder(context)
.setTitle(R.string.dialog_open_white_list_error_title)
.setMessage(msgId)
.setPositiveButton(R.string.main_dialog_ok,checkDetachableClickListener).create()
confirmDialog.setCanceledOnTouchOutside(false)
checkDetachableClickListener?.clearOnDetach(confirmDialog)
confirmDialog.show()
}
/**
* 提示用户打开「白名单管理列表页面」(即:自启动权限)
*/
fun openWhiteListDialog(context:Context){
val message = when {
RomUtil.isSmartisan() -> R.string.smartisan_open_white_list_failed
RomUtil.isSamsung() -> R.string.open_white_list_samsung_tips
RomUtil.isEmui() -> R.string.huawei_open_white_list_failed
else -> R.string.open_white_list_common_tips
}
val checkDetachableClickListener = DetachableClickListener.wrap(
DialogInterface.OnClickListener { dialog, _ ->
dialog?.dismiss()
if(!startWhiteListSetting(context)){
openWhiteListErrorDialog()
}
})
val confirmDialog = AlertDialog.Builder(context)
.setMessage(message)
.setPositiveButton(R.string.main_dialog_setting,checkDetachableClickListener).create()
confirmDialog.setCanceledOnTouchOutside(false)
checkDetachableClickListener?.clearOnDetach(confirmDialog)
confirmDialog.show()
}
////////////////////仅供参考:具体怎么提示,上面的弹框「仅供参考」////////////////////
/**
* 跳转到「白名单管理列表页面」(无法保证所有设备系统都能正常跳转,会有无法跳转提示和容错界面)
*/
fun startWhiteListSetting(context: Context):Boolean{
val intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
var componentName: ComponentName? = null
try {
when {
RomUtil.isMiui() -> {
intent.action = "miui.intent.action.OP_AUTO_START"
intent.addCategory(Intent.CATEGORY_DEFAULT)
}
RomUtil.isSamsung() -> componentName = getSanmSungComponentName()
RomUtil.isOnePlus() -> componentName = getOnePlusComponentName()
RomUtil.isEmui() -> componentName = getHuaweiComponentName()
RomUtil.isVivo() -> componentName = getViVoComponentName()
RomUtil.isFlyme() -> componentName = getFlyMeComponentName()
RomUtil.isOppo() -> componentName = getOppoComponentName()
RomUtil.isQiku() -> componentName = get360ComponentName()
RomUtil.isSmartisan() -> intent.action = Settings.ACTION_SETTINGS
RomUtil.isLetv() -> intent.action = "com.letv.android.permissionautoboot"
}
if (null != componentName || null!=intent.action) {
intent.component = componentName
context.startActivity(intent)
return true
}
} catch (e: Exception) {
}
return false
}
private fun getHuaweiComponentName(): ComponentName? {
when {
//鸿蒙系统跳转失败容错:直接打开手机管家首页
isHarmonyOS() -> return ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.mainscreen.MainScreenActivity"
)
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT < Build.VERSION_CODES.P) -> return ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity"
)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> return ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity"
)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> return ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity"
)
else -> return ComponentName(
"com.huawei.systemmanager",
"com.huawei.systemmanager.optimize.process.ProtectActivity"
)
}
}
private fun getSanmSungComponentName(): ComponentName = ComponentName("com.samsung.android.sm_cn",
"com.samsung.android.sm.ui.cstyleboard.SmartManagerDashBoardActivity")
private fun getViVoComponentName(): ComponentName? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ComponentName.unflattenFromString("com.iqoo.secure/.safeguard.PurviewTabActivity")
} else {
ComponentName(
"com.iqoo.secure",
"com.iqoo.secure.ui.phoneoptimize.SoftwareManagerActivity"
)
}
}
private fun getOppoComponentName(): ComponentName? {
return ComponentName(
"com.coloros.safecenter",
"com.coloros.safecenter.startupapp.StartupAppListActivity"
)
}
private fun getOnePlusComponentName(): ComponentName = ComponentName(
"com.oneplus.security",
"com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity"
)
private fun get360ComponentName(): ComponentName = ComponentName(
"com.yulong.android.coolsafe",
"com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity"
)
private fun getFlyMeComponentName(): ComponentName? =
ComponentName.unflattenFromString("com.meizu.safe/.permission.PermissionMainActivity")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment