重點(diǎn)關(guān)注AppOpsManager這個類。要想知道這個類是干嘛的,直接去谷歌官方開發(fā)者文檔中去了解攻锰。
在AppOpsManager這個類中,可以看到
懸浮窗和修改系統(tǒng)設(shè)置的權(quán)限碼是24和25础米。并且這個類的變量土居,方法都是隱藏的。
接下來,我們需要調(diào)用checkOp方法來返回真正的權(quán)限回調(diào)結(jié)果失球。
/**
* Do a quick check for whether an application might be able to perform an operation.
* This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
* or {@link #startOp(int, int, String)} for your actual security checks, which also
* ensure that the given uid and package name are consistent. This function can just be
* used for a quick check to see if an operation has been disabled for the application,
* as an early reject of some work. This does not modify the time stamp or other data
* about the operation.
* @param op The operation to check. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
* {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
* causing the app to crash).
* @throws SecurityException If the app has been configured to crash on this op.
* @hide
*/
public int checkOp(int op, int uid, String packageName) {
try {
int mode = mService.checkOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
return mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
由于這個方法是隱藏的,所以需要用反射的方法來調(diào)用。也可以用這個庫來進(jìn)行調(diào)用 https://github.com/anggrayudi/android-hidden-api
這個庫只要直接將原本的SDK替換成這個庫的SDK就能夠不用通過反射來調(diào)用隱藏方法实苞。
反射調(diào)用checkOp的步驟:
private static boolean isPermissionGranted(String permissionCode) {
try {
Object object = getSystemService(Context.APP_OPS_SERVICE);
if (object == null) {
return false;
}
Class localClass = object.getClass();
Class[] arrayOfClass = new Class[3];
arrayOfClass[0] = Integer.TYPE;
arrayOfClass[1] = Integer.TYPE;
arrayOfClass[2] = String.class;
Method method = localClass.getMethod("checkOp", arrayOfClass);
if (method == null) {
return false;
}
Object[] arrayOfObject = new Object[3];
arrayOfObject[0] = Integer.valueOf(permissionCode);
arrayOfObject[1] = Integer.valueOf(Binder.getCallingUid());
arrayOfObject[2] = getPackageName();
int m = ((Integer) method.invoke(object, arrayOfObject)).intValue();
return m == AppOpsManager.MODE_ALLOWED;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
然后將懸浮窗和修改系統(tǒng)設(shè)置的權(quán)限碼傳進(jìn)去就好豺撑。
最后返回的結(jié)果既是真正的權(quán)限回調(diào)的結(jié)果。