一、前言
由于用户在开发者选项中关闭了动画的效果,导致App的动画不生效。但是有的App动画效果被关闭了,还依旧能有动画效果产生,这就让我们的用户觉得这是个BUG😀。于是,就有这个问题的解决方案。
开发者选项关闭动画如下:
(关于为什么用户要关闭动画效果?baidu一下,原因竟然是因为能提升手机的流畅度😭😭😭 )
二、如何解决?
工具类
public class ValueAnimatorUtil {
private static String TAG = "ValueAnimatorUtil";
/**
* 如果动画被禁用,则重置动画缩放时长
*/
public static void resetDurationScaleIfDisable() {
if (getDurationScale() == 0)
resetDurationScale();
}
/**
* 重置动画缩放时长
*/
public static void resetDurationScale() {
try {
getField().setFloat(null, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
private static float getDurationScale() {
try {
return getField().getFloat(null);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
@NonNull
private static Field getField() throws NoSuchFieldException {
Field field = ValueAnimator.class.getDeclaredField("sDurationScale");
field.setAccessible(true);
return field;
}
}
怎么使用?
在Activity的onCreate方法中调用如下代码:
ValueAnimatorUtil.resetDurationScaleIfDisable()
注意:以上代码只能在 targetSdkVersion为28或者以下生效,原因如下:
可以看到,在我们需要反射的字段sDurationScale,多了UnsupportedAppUsage注解。
这是因为Google官方在Android P(Android9.0版本)开始针对非 SDK 接口的限制。也就是说,以前你系统的接口通过反射就能调用,现在都不能通过反射获取。
具体被限制的接口名单可以查看这里
所谓道高一尺魔高一丈,既然Google限制了我们,那就肯定会有大佬去解决问题,一起往下看如何突破Android P 接口限制。
三、如何突破Android P接口限制?
如何突破的原理可以看最后提供的参考链接,这篇文章主要讲如何使用。
第一步:将下面仓库地址代码添加到你的根 build.gradle 中:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
第二步:将下面代码添加到你的主模块build.gradle中:
implementation 'com.github.tiann:FreeReflection:3.1.0'
第三步:在你的Application中加入如下代码:
public class MyApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Reflection.unseal(base);
}
}
最后,重新编译运行,在targetSdkVersion为28以上的版本都能修改sDurationScale成功。
四、分析源码
突破Andriod P限制仓库地址
可以把上面第三方SDK源码下载到本地,可以发现,核心代码量就十几行。主要文件就两个
BootstrapClass 和 Reflection,其中关于CPP的代码应该是旧的突破Android P限制的方法。
源码截图如下:
源码分析
源码核心目的:
- 通过反射调用 VMRuntime.setHiddenApiExemptions,把我们需要解除限制的方法传入,就能将我们自己要使用的隐藏 API 全部都豁免掉了。
- 我们所有Java方法类的签名都是以 L开头,只要直接传个
L
进去,所有隐藏API就会被全部解除限制。
开始从源码分析他是如何使用的
第一步:先从 Reflection.unseal(base)调用开始
public static int unseal(Context context) {
if (SDK_INT < 28) {
// Below Android P, ignore
return 0;
}
// try exempt API first.
if (exemptAll()) {
return 0;
}
if (unsealByDexFile(context)) {
return 0;
}
return -1;
}
可以看到,主要方法其实就两个,exemptAll和unsealByDexFile,先看下exemptAll方法。
第二步:exemptAll方法
public static boolean exemptAll() {
return exempt(new String[]{"L"});
}
可以看到,传入了一个字符串“L“,而这个L就是代表了所有的Java方法。继续往下看:
public static boolean exempt(String... methods) {
if (sVmRuntime == null || setHiddenApiExemptions == null) {
return false;
}
try {
setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});
return true;
} catch (Throwable e) {
return false;
}
}
其实就是一个反射的调用setHiddenApiExemptions方法,我们看下setHiddenApiExemptions和sVnRuntime是如何获取的
public final class BootstrapClass {
private static final String TAG = "BootstrapClass";
private static Object sVmRuntime;
private static Method setHiddenApiExemptions;
static {
if (SDK_INT >= Build.VERSION_CODES.P) {
try {
Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
sVmRuntime = getRuntime.invoke(null);
} catch (Throwable e) {
Log.w(TAG, "reflect bootstrap failed:", e);
}
}
}
上面代码的目的是为了获取到 setHiddenApiExemptions,由于setHiddenApiExemptions是属于系统的方法,普通的用户是无法获取到的。dalvik.system.VMRuntime源码截图如下:
/**
* Sets the list of exemptions from hidden API access enforcement.
*
* @param signaturePrefixes
* A list of signature prefixes. Each item in the list is a prefix match on the type
* signature of a blacklisted API. All matching APIs are treated as if they were on
* the whitelist: access permitted, and no logging..
*
* @hide
*/
@SystemApi(client = MODULE_LIBRARIES)
public native void setHiddenApiExemptions(String[] signaturePrefixes);
注释里也说明了Sets the list of exemptions from hidden API access enforcement(设置隐藏 API 访问强制执行的豁免列表。)
需要我们把自己变成系统类,变成系统类的的核心代码主要就是这两句:
Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
- 第一行,通过Class获取到自己的forName,用来反射获取类
- 第二行,通过Class获取到自己的getDeclaredMethod方法,用来反射调用方法
看到这里你可能会有疑惑,通过反射去反射获取类的方法获取到getDeclaredMethod,然后再去反射调用其他方法,那为什么不直接通过getDeclaredMethod反射调用,还要多此一步呢?
这是因为我们之所以在Android P以上不能调用被系统隐藏的类,是因为我们不是系统类。也就是说,我们把自己变成系统类,那么我们就不会存在有接口的限制。
上面可能说的有点绕。简单的说,通过上面两行代码,你就能变成系统类,那么你就能获取。
提示:上面这个方法在Android 11及以上已经失效(在小米8和一加8的安卓版本10上测试通过),🤭实际调用的是下面的unsealByDexFile方法。
第三步:unsealByDexFile方法
代码如下:
private static boolean unsealByDexFile(Context context) {
//1.解码DEX字段,获取字节流
byte[] bytes = Base64.decode(DEX, Base64.NO_WRAP);
//2.将获取的字节流,写入到本地文件
File codeCacheDir = getCodeCacheDir(context);
if (codeCacheDir == null) {
return false;
}
File code = new File(codeCacheDir, System.currentTimeMillis() + ".dex");
try {
try (FileOutputStream fos = new FileOutputStream(code)) {
fos.write(bytes);
}
//3.执行自己生成的dex文件
DexFile dexFile = new DexFile(code);
//4.加载BootstrapClass类
Class<?> bootstrapClass = dexFile.loadClass("me.weishu.reflection.BootstrapClass", null);
//5.调用exemptAll方法
Method exemptAll = bootstrapClass.getDeclaredMethod("exemptAll");
return (boolean) exemptAll.invoke(null);
}
可以看到,这个方法的最终还是调用exemptAll。这个方法的作用主要是通过系统类去加载我们自己的Dex文件,而这个Dex文件其实就是我们FreeRelfection的源码。生成的Dex文件截图如下:
说到这里,那我们能不能也自己生成一个?继续往下看
五、生成Dex文件
1.拷贝源码到自己项目下,如图(包名com.example.viewdemo):
2.将com.example.viewdemo下的代码打包成dex文件
这里可以看我另外一篇文章安卓中将Java文件转换成Dex文件_I'm a Android Dev的博客-CSDN博客
最终生成Hello.dex文件,也可以放到Android Studio打开查看。如下:
3.将Hello.dex文件编码成字符串
由于转换需要在Java工程里,需要创建一个Java工程。 可以将Hello.dex文件放在一起,截图如下:
注意:由于需要用到Android的Base64文件,所以需要拷贝Android的Base64文件到此。
代码如下:
public class FileUtil {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
String path = "D:\\20210426\\code\\otherCode\\ViewDemo\\lib\\src\\main\\java\\com\\example\\lib\\Hello.dex";
byte[] bytesByFile = getBytesByFile(path);
String DEX = Base64.encodeToString(bytesByFile, Base64.NO_WRAP);
System.out.println("DEX: " + DEX);
}
}.start();
}
public static byte[] getBytesByFile(String pathStr) {
File file = new File(pathStr);
System.out.println("文件大小为: " + file.length());
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
byte[] data = bos.toByteArray();
bos.close();
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
运行后如下:
将自己生成的DEX字符串拷贝到Reflection替换DEX字段,并且修改包名。如下:
private static final String DEX = "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SUxEX1RZUEUADkJvb3RzdHJhcENsYXNzABNCb290c3RyYXBDbGFzcy5qYXZhABBCdWlsZENvbmZpZy5qYXZhAAVERUJVRwADREVYAAFJAAJJSQACSUwABElMTEwAAUoAAUwAAkxKAAJMTAADTExJAANMTEwAGUxhbmRyb2lkL2NvbnRlbnQvQ29udGV4dDsAGkxhbmRyb2lkL29zL0J1aWxkJFZFUlNJT047ABhMYW5kcm9pZC90ZXh0L1RleHRVdGlsczsAFUxhbmRyb2lkL3V0aWwvQmFzZTY0OwASTGFuZHJvaWQvdXRpbC9Mb2c7ACVMY29tL2V4YW1wbGUvdmlld2RlbW8vQm9vdHN0cmFwQ2xhc3M7ACJMY29tL2V4YW1wbGUvdmlld2RlbW8vQnVpbGRDb25maWc7ACFMY29tL2V4YW1wbGUvdmlld2RlbW8vUmVmbGVjdGlvbjsAF0xkYWx2aWsvc3lzdGVtL0RleEZpbGU7AA5MamF2YS9pby9GaWxlOwAaTGphdmEvaW8vRmlsZU91dHB1dFN0cmVhbTsAE0xqYXZhL2xhbmcvQm9vbGVhbjsAGExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOwARTGphdmEvbGFuZy9DbGFzczsAFExqYXZhL2xhbmcvQ2xhc3M8Kj47ABdMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAEkxqYXZhL2xhbmcvU3lzdGVtOwAVTGphdmEvbGFuZy9UaHJvd2FibGU7ABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwAlTG1lL3dlaXNodS9yZWZsZWN0aW9uL0Jvb3RzdHJhcENsYXNzOwAKUmVmbGVjdGlvbgAPUmVmbGVjdGlvbi5qYXZhAAdTREtfSU5UAANUQUcAAVYADFZFUlNJT05fQ09ERQAMVkVSU0lPTl9OQU1FAAJWTAADVkxMAAFaAMgeWkdWNENqQXpOUUNsNEVwckdTMnBYSS92M093bEJybGZSblg1cm1rS1ZkTjBDd0FBY0FBQUFIaFdOQklBQUFBQUFBQUFBTWdLQUFCRUFBQUFjQUFBQUJNQUFBQ0FBUUFBQ3dBQUFNd0JBQUFNQUFBQVVBSUFBQThBQUFDd0FnQUFBd0FBQUNnREFBRHNCd0FBaUFNQUFCWUdBQUFZQmdBQUhRWUFBQ2NHQUFBdkJnQUFQd1lBQUVzR0FBQmJCZ0FBY0FZQUFJSUdBQUNKQmdBQWtRWUFBSlFHQUFDWUJnQUFuQVlBQUtJR0FBQ2xCZ0FBcWdZQUFNVUdBQURyQmdBQUJ3Y0FBQnNIQUFBdUJ3QUFSQWNBQUZnSEFBQnNCd0FBZ0FjQUFKY0hBQUN6QndBQTJ3Y0FBQUlJQUFBbENBQUFNUWdBQUVJSUFBQkxDQUFBVUFnQUFGTUlBQUJoQ0FBQWJ3Z0FBSE1JQUFCMkNBQUFlZ2dBQUk0SUFBQ2pDQUFBdUFnQUFNRUlBQURhQ0FBQTNRZ0FBT1VJQUFEd0NBQUErUWdBQUFvSkFBQWVDUUFBTVFrQUFEMEpBQUJGQ1FBQVVna0FBR3dKQUFCMENRQUFmUWtBQUpnSkFBQ2hDUUFBclFrQUFNVUpBQURYQ1FBQTNRa0FBT1VKQUFEekNRQUFDd0FBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZ3QUFBQmdBQUFBWkFBQUFHZ0FBQUJzQUFBQWNBQUFBSFFBQUFCNEFBQUFqQUFBQUp3QUFBQ2tBQUFBcUFBQUFLd0FBQUF3QUFBQUFBQUFBM0FVQUFBMEFBQUFBQUFBQTVBVUFBQTRBQUFBQUFBQUE3QVVBQUE4QUFBQUNBQUFBQUFBQUFCQUFBQUFHQUFBQStBVUFBQkFBQUFBS0FBQUFBQVlBQUNNQUFBQU9BQUFBQUFBQUFDWUFBQUFPQUFBQUNBWUFBQ2NBQUFBUEFBQUFBQUFBQUNnQUFBQVBBQUFBQ0FZQUFDZ0FBQUFQQUFBQUVBWUFBQUlBQUFBL0FBQUFBd0FBQUNFQUFBQUxBQWNBQkFBQUFBc0FCd0FGQUFBQUN3QVBBQWtBQUFBTEFBY0FDZ0FBQUFzQUFBQWtBQUFBQ3dBSEFDVUFBQUFNQUFjQUlnQUFBQXdBQmdBOUFBQUFEQUFLQUQ0QUFBQU5BQWNBSWdBQUFBRUFBd0F6QUFBQUJBQUNBQzRBQUFBRkFBVUFOQUFBQUFZQUJnQURBQUFBQ0FBSEFEY0FBQUFLQUFRQU5nQUFBQXNBQmdBREFBQUFEQUFHQUFJQUFBQU1BQVlBQXdBQUFBd0FDUUF2QUFBQURBQUtBQzhBQUFBTUFBZ0FNQUFBQUEwQUJnQURBQUFBRFFBQkFFRUFBQUFOQUFBQVFnQUFBQXNBQUFBUkFBQUFCZ0FBQUFBQUFBQUlBQUFBQUFBQUFIZ0tBQUJtQ2dBQURBQUFBQkVBQUFBR0FBQUFBQUFBQUFjQUFBQUFBQUFBamdvQUFISUtBQUFOQUFBQUFRQUFBQVlBQUFBQUFBQUFJQUFBQUFBQUFBQ3hDZ0FBZFFvQUFBRUFBUUFCQUFBQUF3b0FBQVFBQUFCd0VBTUFBQUFPQUFvQUFBQURBQUVBQ0FvQUFIc0FBQUJnQlFFQUV3WWNBRFJsYlFBY0JRVUFHZ1l4QUJJWEkzY1FBQklJSEFrSEFFMEpCd2h1TUFJQVpRY01BUndGQlFBYUJqUUFFaWNqZHhBQUVnZ2NDUWNBVFFrSENCSVlIQWtRQUUwSkJ3aHVNQUlBWlFjTUFoSUZFaFlqWmhFQUVnY2FDQzBBVFFnR0IyNHdCUUJSQmd3RUh3UUZBQklsSTFVUkFCSUdHZ2MxQUUwSEJRWVNGaElIVFFjRkJtNHdCUUJDQlF3REh3TUtBQklsSTFVUkFCSUdHZ2MrQUUwSEJRWVNGaElYSTNjUUFCSUlIQWtTQUUwSkJ3aE5Cd1VHYmpBRkFFSUZEQVVmQlFvQWFRVUtBQklGRWdZalpoRUFiakFGQUZNR0RBVnBCUWtBRGdBTkFCb0ZCZ0FhQmpzQWNUQUJBR1VBS1BjQUFBWUFBQUJyQUFFQUFRRUpjZ0VBQVFBQkFBQUFOd29BQUFRQUFBQndFQU1BQUFBT0FBTUFBUUFCQUFBQVBBb0FBQXNBQUFBU0VDTUFFZ0FTQVUwQ0FBRnhFQW9BQUFBS0FBOEFBQUFJQUFFQUF3QUJBRUlLQUFBZEFBQUFFaEVTQW1JRENRQTRBd1lBWWdNS0FEa0RCQUFCSVE4QllnTUtBR0lFQ1FBU0ZTTlZFUUFTQmswSEJRWnVNQVVBUXdVbzhnMEFBU0VvN3dBQURBQUFBQTBBQVFBQkFRa2FBd0FBQUFFQUFBQlNDZ0FBRFFBQUFCSVFJd0FTQUJJQkdnSVBBRTBDQUFGeEVBb0FBQUFLQUE4QUFBQUJBQUVBQVFBQUFGY0tBQUFFQUFBQWNCQURBQUFBRGdBRUFBRUFBUUFBQUZ3S0FBQWVBQUFBRWdCZ0FRRUFFd0ljQURVaEF3QVBBSEVBQ3dBQUFBb0JPUUg3L3hvQU1nQnhFQVFBQUFCdUVBQUFBd0FNQUZJQUFBQnhFQTRBQUFBS0FDanFBUUFBQUFBQUFBQUJBQUFBQVFBQUFBTUFBQUFIQUFjQUNRQUFBQUlBQUFBR0FCRUFBZ0FBQUFjQUVBQUJBQUFBQndBQUFBRUFBQUFTQUFBQUF6RXVNQUFJUEdOc2FXNXBkRDRBQmp4cGJtbDBQZ0FPUVZCUVRFbERRVlJKVDA1ZlNVUUFDa0pWU1V4RVgxUlpVRVVBRGtKdmIzUnpkSEpoY0VOc1lYTnpBQk5DYjI5MGMzUnlZWEJEYkdGemN5NXFZWFpoQUJCQ2RXbHNaRU52Ym1acFp5NXFZWFpoQUFWRVJVSlZSd0FHUmt4QlZrOVNBQUZKQUFKSlNRQUNTVXdBQkVsTVRFd0FBVXdBQTB4TVRBQVpUR0Z1WkhKdmFXUXZZMjl1ZEdWdWRDOURiMjUwWlhoME93QWtUR0Z1WkhKdmFXUXZZMjl1ZEdWdWRDOXdiUzlCY0hCc2FXTmhkR2x2YmtsdVptODdBQnBNWVc1a2NtOXBaQzl2Y3k5Q2RXbHNaQ1JXUlZKVFNVOU9Pd0FTVEdGdVpISnZhV1F2ZFhScGJDOU1iMmM3QUJGTWFtRjJZUzlzWVc1bkwwTnNZWE56T3dBVVRHcGhkbUV2YkdGdVp5OURiR0Z6Y3p3cVBqc0FFa3hxWVhaaEwyeGhibWN2VDJKcVpXTjBPd0FTVEdwaGRtRXZiR0Z1Wnk5VGRISnBibWM3QUJKTWFtRjJZUzlzWVc1bkwxTjVjM1JsYlRzQUZVeHFZWFpoTDJ4aGJtY3ZWR2h5YjNkaFlteGxPd0FhVEdwaGRtRXZiR0Z1Wnk5eVpXWnNaV04wTDAxbGRHaHZaRHNBSmt4dFpTOTNaV2x6YUhVdlpuSmxaWEpsWm14bFkzUnBiMjR2UW5WcGJHUkRiMjVtYVdjN0FDVk1iV1V2ZDJWcGMyaDFMM0psWm14bFkzUnBiMjR2UW05dmRITjBjbUZ3UTJ4aGMzTTdBQ0ZNYldVdmQyVnBjMmgxTDNKbFpteGxZM1JwYjI0dlVtVm1iR1ZqZEdsdmJqc0FDbEpsWm14bFkzUnBiMjRBRDFKbFpteGxZM1JwYjI0dWFtRjJZUUFIVTBSTFgwbE9WQUFEVkVGSEFBRldBQXhXUlZKVFNVOU9YME5QUkVVQURGWkZVbE5KVDA1ZlRrRk5SUUFDVmt3QUFWb0FBbHBNQUJKYlRHcGhkbUV2YkdGdVp5OURiR0Z6Y3pzQUUxdE1hbUYyWVM5c1lXNW5MMDlpYW1WamREc0FFMXRNYW1GMllTOXNZVzVuTDFOMGNtbHVaenNBQjJOdmJuUmxlSFFBRjJSaGJIWnBheTV6ZVhOMFpXMHVWazFTZFc1MGFXMWxBQUZsQUFabGVHVnRjSFFBQ1dWNFpXMXdkRUZzYkFBSFptOXlUbUZ0WlFBUFpuSmxaUzF5Wldac1pXTjBhVzl1QUJKblpYUkJjSEJzYVdOaGRHbHZia2x1Wm04QUVXZGxkRVJsWTJ4aGNtVmtUV1YwYUc5a0FBcG5aWFJTZFc1MGFXMWxBQVpwYm5admEyVUFDMnh2WVdSTWFXSnlZWEo1QUJodFpTNTNaV2x6YUhVdVpuSmxaWEpsWm14bFkzUnBiMjRBQm0xbGRHaHZaQUFIYldWMGFHOWtjd0FaY21WbWJHVmpkQ0JpYjI5MGMzUnlZWEFnWm1GcGJHVmtPZ0FIY21Wc1pXRnpaUUFLYzFadFVuVnVkR2x0WlFBV2MyVjBTR2xrWkdWdVFYQnBSWGhsYlhCMGFXOXVjd0FRZEdGeVoyVjBVMlJyVm1WeWMybHZiZ0FFZEdocGN3QUdkVzV6WldGc0FBeDFibk5sWVd4T1lYUnBkbVVBRG5adFVuVnVkR2x0WlVOc1lYTnpBQVlBQnc0QUZnQUhEbXIvQXdFeUN3RVZFQU1DTlF2d0JBUkVCaGNCRWc4REF6WUxBUnNQcVFVQ0JRTUZCQmtlQXdBdkNnQU9BQWNPQUN3Qk9nY09BRFlCT3djc25ScmlBUUVEQUM4S0hnQklBQWNPQUEwQUJ3NEFFd0V0QngxeUdXdGFBQVlYT0JjOEh4Y0FCQUVYQVFFWEJnRVhId1lBQVFBQ0dRRVpBUmtCR1FFWkFSa0dnWUFFaUFjREFBVUFDQm9CQ2dFS0I0aUFCS0FIQVlHQUJMUUpBUW5NQ1FHSkFmUUpBUW5NQ2dFQUF3QUxHZ3lCZ0FUNENnRUprQXNCaWdJQUFBQUFEZ0FBQUFBQUFBQUJBQUFBQUFBQUFBRUFBQUJFQUFBQWNBQUFBQUlBQUFBVEFBQUFnQUVBQUFNQUFBQUxBQUFBekFFQUFBUUFBQUFNQUFBQVVBSUFBQVVBQUFBUEFBQUFzQUlBQUFZQUFBQURBQUFBS0FNQUFBRWdBQUFJQUFBQWlBTUFBQUVRQUFBSEFBQUEzQVVBQUFJZ0FBQkVBQUFBRmdZQUFBTWdBQUFJQUFBQUF3b0FBQVVnQUFBREFBQUFaZ29BQUFBZ0FBQURBQUFBZUFvQUFBQVFBQUFCQUFBQXlBb0FBQT09AAJaTAACW0IAEltMamF2YS9sYW5nL0NsYXNzOwATW0xqYXZhL2xhbmcvT2JqZWN0OwATW0xqYXZhL2xhbmcvU3RyaW5nOwANYWRkU3VwcHJlc3NlZAAGYXBwZW5kAAxib29sZWFuVmFsdWUADmJvb3RzdHJhcENsYXNzAAVieXRlcwAFY2xvc2UABGNvZGUADGNvZGVDYWNoZURpcgAUY29tLmV4YW1wbGUudmlld2RlbW8AB2NvbnRleHQAEWN1cnJlbnRUaW1lTWlsbGlzABdkYWx2aWsuc3lzdGVtLlZNUnVudGltZQAFZGVidWcABmRlY29kZQAGZGVsZXRlAAdkZXhGaWxlAAFlAAZleGVtcHQACWV4ZW1wdEFsbAAGZXhpc3RzAAdmb3JOYW1lAANmb3MAD2dldENvZGVDYWNoZURpcgARZ2V0RGVjbGFyZWRNZXRob2QAC2dldFByb3BlcnR5AApnZXRSdW50aW1lAAZpbnZva2UAB2lzRW1wdHkADmphdmEuaW8udG1wZGlyAAlsb2FkQ2xhc3MAI21lLndlaXNodS5yZWZsZWN0aW9uLkJvb3RzdHJhcENsYXNzAAZtZXRob2QAB21ldGhvZHMADHBhcnNlQm9vbGVhbgAPcHJpbnRTdGFja1RyYWNlABlyZWZsZWN0IGJvb3RzdHJhcCBmYWlsZWQ6AApzVm1SdW50aW1lABZzZXRIaWRkZW5BcGlFeGVtcHRpb25zAAR0aGlzAAN0bXAABnRtcERpcgAIdG9TdHJpbmcABHRydWUABnVuc2VhbAAPdW5zZWFsQnlEZXhGaWxlAAx1bnNlYWxOYXRpdmUADnZtUnVudGltZUNsYXNzAAF3AAV3cml0ZQAWAAcOav8DAVEXARUQAwJUF/AEBGsQJAESDwMDVhcBGw+pBQIFAwUEGR4DAE0WAA4ABw4ALAFcBw4ANgFdByydGuIBAQMATRYeAEgABw4ABwAHDgAGAAcOABUABw4ATAFGBx0tVAJ4HWkDAWUTeB9aAwBkDHgAHQFGBx0CDWgCeR1rbAAuAUYHHXgDAUEbSwMDRAwCEjsCcR0BHBEDAkMMWgMHUg08PVwDBEwLeAQAQBAklgMGTxflagJwSgUABQQFBmMFBx4DBU0WPmpGAnQdBQUGBwIOWQUHeT0AARcGBRdEF0gfBAEXAQIXNhcsAwAFAAEaAQoBCgSIgAS4CwGBgATMDQEJ5A0BiQGMDgEJ5A4FAAIABBkBGQEZARkBGQmIgASQDwGBgAS0DwIABQAJGgEaC4GABMwPAQrkDwEJvBABCvgQAYoCAAAAAA4AAAAAAAAAAQAAAAAAAAABAAAAbQAAAHAAAAACAAAAHgAAACQCAAADAAAAGQAAAJwCAAAEAAAACwAAAMgDAAAFAAAAJwAAACAEAAAGAAAAAwAAAFgFAAABIAAACwAAALgFAAABEAAADwAAAOAJAAACIAAAbQAAAFwKAAADIAAACwAAAIgfAAAFIAAAAwAAAGQgAAAAIAAAAwAAAHYgAAAAEAAAAQAAANQgAAA=";
Class<?> bootstrapClass = dexFile.loadClass("com.example.viewdemo.BootstrapClass", null);
最后运行App,设置依然生效。
本篇分享到此结束,说个题外话,文章中的获取元反射方法和DEX文件的生成,这些都是跟安卓的插件化息息相关的。学习需要互相联系。
参考链接:
Android ValueAnimator时长错乱或者不起作用的解决方法以及问题分析_陈小缘的博客-CSDN博客_valueanimator回调不正常
下面两篇是维术大佬关于Android P的限制的原理和解决方案,YYDS。
另一种绕过 Android P以上非公开API限制的办法 | Weishu's Notes
一种绕过Android P对非SDK接口限制的简单方法 | Weishu's Notes