方案1
===
声明在清单文件中的ContentProvider 会在应用启动后就创建。具体是在 ActivityThread的handleBindApplication方法中。(以下截图为Android 30的ActivityThread)
具体就在这一句
installContentProviders实现如下
最终是通过AppComponentFactory的instantiateProvider方法创建。
而AppComponentFactory是Android 28以后系统提供给我们的一个hook的工厂类。可以通过清单文件指定,在这里面可以hook 所有组件的初始化。
这么指定
但是在Android 28以下,比如这个截图是Android 25.没有这类,ContentProvider直接通过反射获得。无法通过该类来修改。
最终方案
====
为了兼容性,考虑如下方案。在调用installContentProviders前,如果这个data里面的providers为空岂不是不会走installContentProviders方法了吗。
这个data 是一个AppBindData类型,通过handleBi
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
ndApplication方法的参数传入。会保存到ActivityThread的 mBoundApplication 字段中。
于是就可以通过获取这个mBoundApplication 字段中的providers 来保存要初始化的provider。再讲providers置为空即可。到了用户同意以后,再去通过反射调用ActivityThread的installContentProviders方法即可。
hook时机
======
这个时机只有Application的attachBaseContext方法中。该方法会比installContentProviders提前执行。
最后的代码App中
public class MyApp extends Application {
static MyApp app;
/**
*用户同意
*/
public static void agree(Action action) {
HookUtil.initProvider(app);
action.doAction();
}
public interface Action {
void doAction();
}
@Override
protected void attachBaseContext(Context base) {
app = this;
try {
HookUtil.attachContext();
} catch (Exception e) {
e.printStackTrace();
}
super.attachBaseContext(base);
}
}
HookUtil
package com.zgh.testcontentprovider;
import android.content.Context;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
/**
-
Created by zhuguohui
-
Date: 2021/9/13
-
Time: 11:23
-
Desc:
*/
public class HookUtil {
private static Object providers;