Skip to content

Commit a4b4285

Browse files
author
tangxiaolv
committed
更新Readme
1 parent 22d08b9 commit a4b4285

File tree

7 files changed

+134
-18
lines changed

7 files changed

+134
-18
lines changed

DexKnifePlugin/app/dexknife.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
# 这条配置可以指定这个包下类在第二及其他dex中.
1414
#android.support.v?.**
15-
#将全部类移除主Dex
15+
#将全部类移出主Dex
1616
-split **.**
1717

1818
# 不包含Android gradle 插件自动生成的miandex列表.(不用系统自带分包策略)

DexKnifePlugin/app/maindexlist.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
rx/annotations/Beta.class
2+
rx/annotations/Experimental.class
13
rx/android/concurrency/AndroidSchedulers.class
24
rx/android/concurrency/HandlerThreadScheduler.class
35
android/support/annotation/StyleableRes.class
@@ -25,8 +27,6 @@ android/support/annotation/LayoutRes.class
2527
android/support/annotation/IdRes.class
2628
android/support/annotation/StringDef.class
2729
android/support/annotation/ColorRes.class
28-
rx/annotations/Beta.class
29-
rx/annotations/Experimental.class
3030
android/support/multidex/MultiDex$V14.class
3131
android/support/multidex/MultiDex$V19.class
3232
android/support/multidex/MultiDex$V4.class

DexKnifePlugin/gradle-dexknife-plugin/src/main/groovy/com/ceabie/dexknife/DexKnifePlugin.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public class DexKnifePlugin implements Plugin<Project> {
3636
componentName.endsWith("${it}")
3737
}
3838
def bool = result != null;
39-
if (!bool) {
40-
printf "main-dex-filter: skipping ${componentName}\n"
39+
if (bool) {
40+
printf "main-dex-filter: keep ${componentName}\n"
4141
}
4242
return bool
4343
}

README.md

Lines changed: 129 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#Android傻瓜式分包插件
2-
注1:不想看前半部分的话可以直接跳过到最下面配置部分。
2+
注1:不想看前半部分的话可以直接跳过到最下面配置部分。
33
注2:本插件是基于[DexKnifePlugin 1.5.2](https://github.com/ceabie/DexKnifePlugin)优化改造而来,感谢ceabie的无私奉献。
44

5-
##填坑之路
6-
`坑1:65536 ,So easy! `
7-
*原因:*Dalvik 的 invoke-kind 指令集中,method reference index 只留了 16 bits,最多能引用 65535 个方法。
8-
参考=>[由Android 65K方法数限制引发的思考](http://jayfeng.com/2016/03/10/%E7%94%B1Android-65K%E6%96%B9%E6%B3%95%E6%95%B0%E9%99%90%E5%88%B6%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83/).
9-
*解决:*
5+
##填坑之路
6+
`坑1:65536 ,So easy! `
7+
*原因:*Dalvik 的 invoke-kind 指令集中,method reference index 只留了 16 bits,最多能引用 65535 个方法。
8+
参考=>[由Android 65K方法数限制引发的思考](http://jayfeng.com/2016/03/10/%E7%94%B1Android-65K%E6%96%B9%E6%B3%95%E6%95%B0%E9%99%90%E5%88%B6%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83/).
9+
10+
*解决:*
1011
```
1112
dependencies {
1213
compile 'com.android.support:MultiDex:1.0.1'
@@ -21,8 +22,9 @@ protected void attachBaseContext(Context base) {
2122
}
2223
```
2324

24-
`坑2:Too many classes in –main-dex-list ,what?`
25-
*原因:*通过上面的官方分包,已经把原Dex分为1主Dex加多从Dex,主Dex保留4大组件,Application,Annotation,multidex等及其必要的直接依赖。由于我们方法数已达到16W之巨,上百个Activity,所以成功的把主Dex又撑爆了。
25+
`坑2:Too many classes in –main-dex-list ,what?`
26+
*原因:*通过上面的官方分包,已经把原Dex分为1主Dex加多从Dex,主Dex保留4大组件,Application,Annotation,multidex等及其必要的直接依赖。由于我们方法数已达到16W之巨,上百个Activity,所以成功的把主Dex又撑爆了。
27+
2628
*解决:*
2729
gradle
2830
```
@@ -39,19 +41,133 @@ afterEvaluate {
3941
```
4042
参考=>[Android Dex分包之旅](http://yydcdut.com/2016/03/20/split-dex/index.html)
4143

42-
`坑3:gradle 1.5.0之后不支持这种写法 ,what the fuck?`
44+
`坑3:gradle 1.5.0之后不支持这种写法 ,what the fuck?`
4345
*原因:*官方解释Gralde`1.5.0`以上已经将(jacoco, progard, multi-dex)统一移到[Transform API](http://tools.android.com/tech-docs/new-build-system/transform-api)里,然而Transform API并没有想象的那么简单好用,最后翻遍Google终于找到一个兼容Gradle `1.5.0`以上的分包插件[DexKnifePlugin](https://github.com/ceabie/DexKnifePlugin)
4446
参考=>这篇[Android 热修复使用Gradle Plugin1.5改造Nuwa插件](http://blog.csdn.net/sbsujjbcy/article/details/50839263)比较好的介绍了Transform API的使用。
4547

46-
`坑4:NoClassDefFoundError ,are you kiding me?`
47-
*原因:*通过插件手动指定main dex中要保留的类,虽然分包成功,但是main dex中的类及其直接引用类很难通过手动的方式指定。
48+
`坑4:NoClassDefFoundError ,are you kiding me?`
49+
*原因:*通过插件手动指定main dex中要保留的类,虽然分包成功,但是main dex中的类及其直接引用类很难通过手动的方式指定。
50+
4851
*解决方式:*
4952
看了[美团Android DEX自动拆包及动态加载简介](http://tech.meituan.com/mt-android-auto-split-dex.html),他们是通过编写了一个能够自动分析Class依赖的脚本去算出主Dex需要包含的所有必要依赖。看来依赖脚本是跑不掉了。
5053

5154
`坑5:自定义脚本 ,read the fuck source!`
52-
插件的工作流程:
55+
问题一:放进主Dex里应该有哪些类,规则是什么?
56+
查看sdk\build-tools\platform-version\mainDexClasses.rules发现应该放进主Dex类有Instrumentation,Application,Activity,Service,ContentProvider,BroadcastReceiver,BackupAgent的所有子类。
57+
58+
问题二:gradle是在哪里计算出主Dex依赖?
59+
查看Gradle编译任务发现有如下3个编译任务:
60+
<img src="png/2.png" width="800">
61+
62+
运行collect任务,发现会在build/multi-dex目录下单独生成manifest_keep.txt文件,该文件其实就是通过上述规则扫描AndroidManifest生成。manifest_keep.txt保留的是所有需要放入主Dex里的类。还没完,接下来transformClassesWithMultidexlist任务会根据manifest_keep.txt生成必要依赖列表maindexlist.txt,这里面所有类才是真正放入主Dex里的。bingo,思路已经非常清晰,我们只需要控制manifest_keep.txt的类,依赖关系由系统帮我们生成,即可控制主Dex大小和方法数,安全可靠!
5363

64+
<img src="png/3.png" width="800">
65+
<img src="png/4.png" width="800">
5466

67+
问题三:在哪里控制maindexlist.txt的大小?
68+
由问题一我们知道生成manifest_keep.txt的规则,对于绝大部分工程来说,manifest_keep.txt中80%是Activity,其实我们只需要在主Dex中保留首页 Activity、Laucher Activity 、欢迎页的 Activity 等启动时必要的Activity就OK了。
69+
70+
71+
下图是Gradle的工作流程:
72+
<img src="png/1.png" width="800">
73+
来源:[深入理解Android之Gradle](http://blog.csdn.net/innost/article/details/48228651)
74+
75+
我们只需要在完成任务向量图之后,执行任务之前Hook一下collect任务,做下activity过滤就OK了,添加Gradle:
76+
```
77+
//需要加入主dex的Activity列表
78+
def mainDexListActivity = ['WelcomeActivity', 'MainFunctionActivity']
79+
afterEvaluate {
80+
project.tasks.each { task ->
81+
if (task.name.startsWith('collect') && task.name.endsWith('MultiDexComponents')) {
82+
println "main-dex-filter: found task $task.name"
83+
task.filter { name, attrs ->
84+
String componentName = attrs.get('android:name')
85+
if ('activity'.equals(name)) {
86+
def result = mainDexListActivity.find {
87+
componentName.endsWith("${it}")
88+
}
89+
return result != null
90+
} else {
91+
return true
92+
}
93+
}
94+
}
95+
}
96+
}
97+
```
98+
99+
`坑6:主dex依然爆表,shit again!`
100+
其实上面那段脚本已经成功筛选出我们想要的主Dex的manifest_keep和maindexlist,只是不知道为什么还是把所有类打进主Dex。这个时候就需要跟[DexKnifePlugin](https://github.com/ceabie/DexKnifePlugin)插件配合使用,首先在gradle中加上上述脚本,然后使用插件时在配置文件里加上`-split **.**``#-donot-use-suggest`
101+
102+
###Congratulation
103+
恭喜,填坑终于结束,不过还有点不爽的是需要同时维护Gradle脚本和插件的配置。
104+
于是就将Gradle脚本整合进了插件,以后只要维护一个配置文件就行了。由于带有点业务特性,于是就单独开了个项目,读者可以根据自己需求自己选择。以下是整合插件的配置。
55105

56106
##配置部分
57-
`第一步:`
107+
`第一步:将repo目录复制到项目根目录`
108+
109+
`第二步:添加根目录Gradle`
110+
```
111+
buildscript {
112+
repositories {
113+
maven {
114+
url uri('repo')
115+
}
116+
}
117+
118+
dependencies {
119+
classpath 'com.ceabie.dextools:gradle-dexknife-plugin:2.0.0'
120+
}
121+
}
122+
123+
```
124+
`第三步:在你的App模块的build.gradle添加插件`
125+
```
126+
apply plugin: 'com.ceabie.dexnkife'
127+
```
128+
129+
`第四步:在你的App模块目录下新建dexknife.txt,并自定义配置`
130+
```
131+
#为注释符
132+
133+
#-----------主Dex中必要依赖的脚本配置-----------
134+
#默认保留四大组件中其他三大组件,Activity组件选择性保留(使用-just activity 选项),若为空默认保留所有Activity
135+
-just activity com.ceabie.demo.MainActivity
136+
137+
#-----------附加类-----------
138+
# 如果你想要某个包路径在maindex中,则使用 -keep 选项,即使他已经在分包的路径中.若为空,默认保留所有
139+
140+
# 保留单个类.
141+
#-keep android.support.v7.app.AppCompatDialogFragment.class
142+
143+
# 这条配置可以指定这个包下类在第二及其他dex中.
144+
#android.support.v?.**
145+
#将全部类移出主Dex
146+
-split **.**
147+
148+
# 不包含Android gradle 插件自动生成的miandex列表.(不用系统自带分包策略)
149+
#-donot-use-suggest
150+
151+
# 不进行dex分包, 直到 dex 的id数量超过 65536.(设置自动执行分包策略)
152+
#-auto-maindex
153+
154+
# 显示miandex的日志.
155+
#-log-mainlist
156+
157+
```
158+
159+
`第五步:在 defaultConfig 或者 buildTypes中打开 multiDexEnabled true,否则不起作用`
160+
161+
##报错
162+
163+
错误1:
164+
```
165+
Error:Execution failed for task ':Toon:transformClassesWithDexForDebug'.> java.lang.NullPointerException (no error message)
166+
```
167+
发生此错误只要切换一次Gradle版本就OK了,比如1.5.0
168+
169+
错误2:
170+
```
171+
Unsupported major.minor version 52.0
172+
```
173+
将JDK升级到1.8

png/2.png

12.8 KB
Loading

png/3.png

12.1 KB
Loading

png/4.png

43.4 KB
Loading

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy