Android系统开发 AppOpsManager 应用权限管理

Android系统开发 AppOpsManager 应用权限管理

本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17374096.html

本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。

前言

AppOpsManager是应用权限管理器,负责控制应用权限设置。appops是在现有权限机制上新增的一套权限管理机制,主要针对一些高危的非必须系统应用的权限。

请注意!调用AppOpsManager需要系统级权限。所以此API通常不适用于第三方应用程序开发人员; 大多数功能仅适用于系统应用程序。 通过Context.getSystemService与Context.APP_OPS_SERVICE获取它的一个实例。

常量

mode参数

/**

* 允许权限

*/

public static final int MODE_ALLOWED = 0;

/**

* 忽略权限

*/

public static final int MODE_IGNORED = 1;

/**

* 拒绝权限,并且会引起报错

*/

public static final int MODE_ERRORED = 2;

/**

* 默认,通常不使用这种模式;它应该只在appop权限下使用,调用者必须显式地检查它并处理它。

*/

public static final int MODE_DEFAULT = 3;

/**

* 特殊模式只允许应用处于前台时,当设置此模式时,当被检查的应用程序当前处于前台时返回{@link MODE_ALLOWED},否则返回{@link MODE_IGNORED}。

* @hide

*/

public static final int MODE_FOREGROUND = 4;

可申请的权限列表

/** 访问粗略的位置信息。*/

public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";

/** 访问精细的位置信息。*/

public static final String OPSTR_FINE_LOCATION ="android:fine_location";

/** 持续监控位置数据。*/

public static final String OPSTR_MONITOR_LOCATION = "android:monitor_location";

/** 在相对较高的功率要求下持续监控位置数据。*/

public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";

/** 访问统计数据权限 */

public static final String OPSTR_GET_USAGE_STATS = "android:get_usage_stats";

/** 激活VPN连接,无需用户干预 */

public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";

/** 允许应用程序读取用户的联系人数据. */

public static final String OPSTR_READ_CONTACTS = "android:read_contacts";

/** 允许应用程序写入用户的联系人数据. */

public static final String OPSTR_WRITE_CONTACTS = "android:write_contacts";

/** 允许程序读取用户的通话记录. */

public static final String OPSTR_READ_CALL_LOG = "android:read_call_log";

/** 允许应用程序写入用户的呼叫记录. */

public static final String OPSTR_WRITE_CALL_LOG = "android:write_call_log";

/** 允许应用程序读取用户的日历数据. */

public static final String OPSTR_READ_CALENDAR = "android:read_calendar";

/** 允许应用程序写入用户的日历数据. */

public static final String OPSTR_WRITE_CALENDAR = "android:write_calendar";

/** 允许应用程序发起一个电话呼叫. */

public static final String OPSTR_CALL_PHONE = "android:call_phone";

/** 允许程序读取短信. */

public static final String OPSTR_READ_SMS = "android:read_sms";

/** 允许应用程序接收短信. */

public static final String OPSTR_RECEIVE_SMS = "android:receive_sms";

/** 允许应用程序接收彩信. */

public static final String OPSTR_RECEIVE_MMS = "android:receive_mms";

/** 允许应用程序接收WAP推送消息. */

public static final String OPSTR_RECEIVE_WAP_PUSH = "android:receive_wap_push";

/** 允许应用程序发送短信. */

public static final String OPSTR_SEND_SMS = "android:send_sms";

/** 需要能够访问摄像设备. */

public static final String OPSTR_CAMERA = "android:camera";

/** 需要能够访问麦克风设备. */

public static final String OPSTR_RECORD_AUDIO = "android:record_audio";

/** 需要访问电话状态相关信息. */

public static final String OPSTR_READ_PHONE_STATE = "android:read_phone_state";

/** 需要访问电话状态相关信息. */

public static final String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";

/** 通过VOIP或WiFi访问SIP呼叫的api */

public static final String OPSTR_USE_SIP = "android:use_sip";

/** 访问用于转移呼出的api */

public static final String OPSTR_PROCESS_OUTGOING_CALLS = "android:process_outgoing_calls";

/** 使用指纹API. */

public static final String OPSTR_USE_FINGERPRINT = "android:use_fingerprint";

/** 接入身体传感器,如心率等. */

public static final String OPSTR_BODY_SENSORS = "android:body_sensors";

/** 读取先前收到的蜂窝广播消息. */

public static final String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";

/** 将模拟位置注入系统. */

public static final String OPSTR_MOCK_LOCATION = "android:mock_location";

/** 读取外部存储器. */

public static final String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";

/** 写入外部存储器. */

public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage";

/** 需要悬浮窗. */

public static final String OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window";

/** 需要写入、修改、更新系统设置. */

public static final String OPSTR_WRITE_SETTINGS = "android:write_settings";

检查权限

checkOp

/**

* 检查权限

* [op]这个参数请参考 AppOpsManager.OPSTR_CAMERA 这些常量

* 返回值请参考 AppOpsManager.MODE_ALLOWED 这些常量

*/

fun checkPermissions(context: Context, packageName: String, op: String): Int {

try {

val uid: Int = context.getPackageManager().getPackageUid(packageName, 0)

val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager

val result = appOpsManager.checkOp(op, uid, packageName)

return result

} catch (e: SecurityException) {

e.printStackTrace()

return -1

}

}

checkOpNoThrow

此方法不会抛出异常,所以不需要做异常捕获,其他部分与上面的差不多

/**

* 检查权限

* [op]这个参数请参考 AppOpsManager.OPSTR_CAMERA 这些常量

* 返回值请参考 AppOpsManager.MODE_ALLOWED 这些常量

*/

fun checkPermissions(context: Context, packageName: String, op: String): Int {

val uid: Int = context.getPackageManager().getPackageUid(packageName, 0)

val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager

val result = appOpsManager.checkOpNoThrow(op, uid, packageName)

return result

}

设置权限

验证相关代码的时候有一些疑惑。在设置-应用-权限管理,如果这个应用一次都没有授权过(安装授权),那么权限还是能设置的,但是在设置-应用-权限管理不会发生变化(实际上还是有授权的)。但是,如果你执行过安装授权,那么这个地方就会有权限变化了。

setMode

这里的setMode可能会爆红,在Android studio中,kotlin上可以直接编译过去,但是java可能不行,需要反射

/**

* 设置权限

* [op]这个参数请参考 AppOpsManager.OPSTR_CAMERA 这些常量

* [mode]这个参数请参考 AppOpsManager.MODE_ALLOWED 这些常量

*/

fun setPermissions(context: Context, packageName: String, op: String, mode: Int) {

try {

val uid: Int = context.getPackageManager().getPackageUid(packageName, 0)

val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager

appOpsManager.setMode(op, uid, packageName, mode)

} catch (e: PackageManager.NameNotFoundException) {

e.printStackTrace()

}

}

上面的代码使用例子

//检查权限

val permissionsState = PermissionsHelp.checkPermissions(this, "xxx.xxx.xxx", AppOpsManager.OPSTR_CAMERA)

//设置权限

PermissionsHelp.setPermissions(this, "xxx.xxx.xxx", AppOpsManager.OPSTR_CAMERA, AppOpsManager.MODE_ALLOWED)

监听权限的变化

代码

/**

* [op] 请参考AppOpsManager.OPSTR_CAMERA 这些常量

*/

fun startWatchingMode(context: Context, packageName: String, op: String) {

val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager

appOpsManager.startWatchingMode(op, packageName, object : AppOpsManager.OnOpChangedListener {

override fun onOpChanged(op2: String?, packageName2: String?) {

val uid: Int = context.getPackageManager().getPackageUid(packageName2, 0)

val result = appOpsManager.checkOpNoThrow(op2, uid, packageName2)

Log.e("zh", "权限发生变更 op = ${op2} packageName = ${packageName2} ${result}")

}

})

}

请注意,如果不需要监听了,请调用stopWatchingMode方法取消监听

一次性权限

一次性权限是在Android 10才有的概念(这个请自行百度了解)。 AppOpsManager 通过2个方法,startOp与finishOp实现了一次性权限功能。

此功能暂时无法给出,有一些问题,我不太明白需要什么样的条件才能调用startOp与finishOp并且发挥作用。我看了源码也不太明白,待后续有时间研究。

验证包名是否属于UID

代码

fun checkPackage(context: Context, packageName: String, uid:Int):Boolean {

try {

val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager

appOpsManager.checkPackage(uid, packageName)

Log.e("tag", "uid 与 packageName 匹配", )

return true

} catch (e: SecurityException) {

e.printStackTrace()

Log.e("tag", "uid 与 packageName 不匹配", )

return false

}

}

使用

val uid: Int = this.getPackageManager().getPackageUid("你的包名", 0)

AppOpsManagerUtil.checkPackage(this, "你的包名", uid)

检索所有应用程序的当前操作状态

请注意!getPackagesForOps() 方法并不是返回全部应用的权限信息,而是你使用AppOpsManager 操作过的应用它才会返回。如果你是在Android原生设置-应用-权限中的操作,它是不会有记录的。

这里的很多方法与类可能都会爆红,在Android studio中,kotlin上可以不用管爆红直接编译过去,但是java可能不行,需要反射。

/**

* 检索所有应用程序的当前操作状态。

*/

fun getPackagesForOps(context: Context) {

try {

val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager

val list : List = appOpsManager.getPackagesForOps(intArrayOf(AppOpsManager.OP_CAMERA))

list.forEach {

Log.e("zh", "PackageName = ${it.getPackageName()} Uid = ${it.getUid()}")

//保存有关这个应用程序的全部权限类型的信息

(it.getOps() as List).forEach{

Log.e("zh", "Op = ${it.getOp()}")

Log.e("zh", "Mode = ${it.getMode()}")

Log.e("zh", "Time = ${it.getTime()}")

Log.e("zh", "isRunning = ${it.isRunning()}")

}

}

} catch (e: SecurityException) {

e.printStackTrace()

}

}

结果

2023-11-04 16:50:25.017 20730-20730 zh E PackageName = com.zh.demo Uid = 10118

2023-11-04 16:50:25.017 20730-20730 zh E Op = 26

2023-11-04 16:50:25.017 20730-20730 zh E Mode = 0

2023-11-04 16:50:25.017 20730-20730 zh E Time = 1699080166754

2023-11-04 16:50:25.017 20730-20730 zh E isRunning = false

end

相关文章