本文来自博客园,作者:观心静 ,转载请注明原文链接: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.PackageOps> = appOpsManager.getPackagesForOps(intArrayOf(AppOpsManager.OP_CAMERA))
list.forEach {
Log.e("zh", "PackageName = ${it.getPackageName()} Uid = ${it.getUid()}")
//保存有关这个应用程序的全部权限类型的信息
(it.getOps() as List<AppOpsManager.OpEntry>).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
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17374096.html