一键接入Tinker
来源:互联网 发布:php文章管理系统 初学 编辑:程序博客网 时间:2024/05/18 16:16
背景
InstantRun
实现
打包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@TaskAction
def updateManifest() {
def ns = new Namespace("http://schemas.android.com/apk/res/android", "android")
def xml = new XmlParser().parse(new InputStreamReader(new FileInputStream(manifestPath), "utf-8"))
def application = xml.application[0]
if (application) {
def metaDataTags = application['meta-data']
String rawApplicationName = application.attributes()[ns.name]
metaDataTags.findAll {
it.attributes()[ns.name].equals(TINKER_APPLICATION)
}.each {
it.parent().remove(it)
}
application.appendNode('meta-data', [(ns.name): TINKER_APPLICATION, (ns.value): rawApplicationName])
application.attributes()[ns.name] = TINKER_APPLICATION_VALUE
def printer = new XmlNodePrinter(new PrintWriter(manifestPath, "utf-8"))
printer.preserveWhitespace = true
printer.print(xml)
}
}
1
2
3
4
<application android:name="com.w4lle.onekeytinker.BootstrapApplication">
...
<meta-data android:name="ONEKEY_TINKER_APPLICATION" android:value="com.w4lle.onekeytinker.App"/>
</application>
运行时替换Application
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public static void monkeyPatchApplication(@Nullable Context context,
@Nullable Application bootstrap,
@Nullable Application realApplication) {
try {
// Find the ActivityThread instance for the current thread
Class<?> activityThread = Class.forName("android.app.ActivityThread");
Object currentActivityThread = getActivityThread(context, activityThread);
// Find the mInitialApplication field of the ActivityThread to the real application
Field mInitialApplication = activityThread.getDeclaredField("mInitialApplication");
mInitialApplication.setAccessible(true);
Application initialApplication = (Application) mInitialApplication.get(currentActivityThread);
if (realApplication != null && initialApplication == bootstrap) {
//**2.替换掉ActivityThread.mInitialApplication**
mInitialApplication.set(currentActivityThread, realApplication);
}
// Replace all instance of the stub application in ActivityThread#mAllApplications with the
// real one
if (realApplication != null) {
Field mAllApplications = activityThread.getDeclaredField("mAllApplications");
mAllApplications.setAccessible(true);
List<Application> allApplications = (List<Application>) mAllApplications
.get(currentActivityThread);
for (int i = 0; i < allApplications.size(); i++) {
if (allApplications.get(i) == bootstrap) {
//**1.替换掉ActivityThread.mAllApplications**
allApplications.set(i, realApplication);
}
}
}
// Figure out how loaded APKs are stored.
// API version 8 has PackageInfo, 10 has LoadedApk. 9, I don't know.
Class<?> loadedApkClass;
try {
loadedApkClass = Class.forName("android.app.LoadedApk");
} catch (ClassNotFoundException e) {
loadedApkClass = Class.forName("android.app.ActivityThread$PackageInfo");
}
Field mApplication = loadedApkClass.getDeclaredField("mApplication");
mApplication.setAccessible(true);
// 10 doesn't have this field, 14 does. Fortunately, there are not many Honeycomb devices
// floating around.
Field mLoadedApk = null;
try {
mLoadedApk = Application.class.getDeclaredField("mLoadedApk");
} catch (NoSuchFieldException e) {
// According to testing, it's okay to ignore this.
}
// Enumerate all LoadedApk (or PackageInfo) fields in ActivityThread#mPackages and
// ActivityThread#mResourcePackages and do two things:
// - Replace the Application instance in its mApplication field with the real one
// - Set Application#mLoadedApk to the found LoadedApk instance
for (String fieldName : new String[]{"mPackages", "mResourcePackages"}) {
Field field = activityThread.getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(currentActivityThread);
for (Map.Entry<String, WeakReference<?>> entry :
((Map<String, WeakReference<?>>) value).entrySet()) {
Object loadedApk = entry.getValue().get();
if (loadedApk == null) {
continue;
}
if (mApplication.get(loadedApk) == bootstrap) {
if (realApplication != null) {
//**3.替换掉mApplication**
mApplication.set(loadedApk, realApplication);
}
if (realApplication != null && mLoadedApk != null) {
//**4.替换掉mLoadedApk**
mLoadedApk.set(realApplication, loadedApk);
}
}
}
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
兼容性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
try {
...
} catch {
e = true;
realApplication.onCreate();
}
public void onConfigurationChanged(Configuration paramConfiguration)
{
if (e && realApplication != null) {
realApplication.onConfigurationChanged(paramConfiguration);
return;
}
super.onConfigurationChanged(paramConfiguration);
}
public void onLowMemory()
{
if (e && realApplication != null) {
realApplication.onLowMemory();
return;
}
super.onLowMemory();
}
@TargetApi(14)
public void onTrimMemory(int paramInt)
{
if (e && realApplication != null) {
realApplication.onTrimMemory(paramInt);
return;
}
super.onTrimMemory(paramInt);
}
public void onTerminate()
{
if (e && realApplication != null) {
realApplication.onTerminate();
return;
}
super.onTerminate();
}
总结
参考
0 0
- 一键接入Tinker
- Tinker接入及源码分析(一)
- Tinker接入及源码分析(一)
- Tinker接入
- tinker接入
- Tinker 接入指南
- Tinker接入步骤
- Tinker接入快速上手
- Tinker接入详解
- Tinker接入简单实践
- Tinker 的接入
- Tinker的简单接入
- Android热修复(一):Tinker的使用(一)命令行接入
- 接入热修复框架TinKer
- Tinker热修复简单接入
- 热修复,Tinker的接入
- Tinker接入及原理分析
- Tinker接入小白教程
- 阿里云部署Java web项目初体验(转)/linux 上配置jdk和安装tomcat
- Jackson Annotation 格式化日期时区问题
- linux命令-sed语法详解
- 把图片文件存入oracle数据库 然后读取并显示在jsp页面
- 识别和匹配idc配置文件
- 一键接入Tinker
- 结合 category 工作原理分析 OC2.0 中的 runtime
- ES 父子关系(持续更新)
- 转载一个关于python web fraemwork 的理解
- swiper3.4 IE8兼容性问题
- S2 1本2章 课后题
- HTML5 学习笔记6-改良的input元素
- Eclipse不自动编译java文件的终极解决方法
- Unity3D for VR 学习(4): 自绘摄像机的视口区域锥体