├── .gitignore
├── README.MD
├── app
├── .gitignore
├── build.gradle
├── libs
│ └── merge-release.aar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── onzhou
│ │ └── module
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── onzhou
│ │ │ └── module
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── onzhou
│ └── module
│ └── ExampleUnitTest.java
├── build.gradle
├── common
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── onzhou
│ │ │ └── module
│ │ │ └── common
│ │ │ └── CommonActivity.java
│ └── res
│ │ ├── layout
│ │ └── activity_common.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── onzhou
│ └── module
│ └── common
│ └── ExampleUnitTest.java
├── config.gradle
├── download
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── onzhou
│ │ │ └── module
│ │ │ └── download
│ │ │ └── DownloadActivity.java
│ └── res
│ │ ├── layout
│ │ └── activity_download.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── onzhou
│ └── module
│ └── download
│ └── ExampleUnitTest.java
├── fat-aar.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── liveroom
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── onzhou
│ │ │ └── module
│ │ │ └── liveroom
│ │ │ └── LiveRoomActivity.java
│ └── res
│ │ ├── layout
│ │ └── activity_live_room.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── onzhou
│ └── module
│ └── liveroom
│ └── ExampleUnitTest.java
├── merge
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── onzhou
│ └── module
│ └── merge
│ └── ExampleUnitTest.java
├── module.gradle
├── publish.gradle
├── settings.gradle
├── upload
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── onzhou
│ │ │ └── module
│ │ │ └── upload
│ │ │ └── UploadActivity.java
│ └── res
│ │ ├── layout
│ │ └── activity_upload.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── onzhou
│ └── module
│ └── upload
│ └── ExampleUnitTest.java
└── video
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
├── main
├── AndroidManifest.xml
├── java
│ └── com
│ │ └── onzhou
│ │ └── module
│ │ └── video
│ │ └── VideoPlayActivity.java
└── res
│ ├── layout
│ └── activity_video_play.xml
│ └── values
│ └── strings.xml
└── test
└── java
└── com
└── onzhou
└── module
└── video
└── ExampleUnitTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 | project.properties
22 | *.resources.prefs
23 | .settings*
24 | lint.xml
25 |
26 | # Log files
27 | *.log
28 |
29 | #ButterKnife
30 | .apt_generated/
31 | .factorypath
32 |
33 | # for android-studio
34 | # Gradle files
35 | out/
36 | outputs/
37 | build/
38 | .gradle/
39 | */build/
40 | gradlew
41 | gradlew.bat
42 |
43 | # IDEA
44 | *.iml
45 | .idea/
46 | .idea/.name
47 | .idea/encodings.xml
48 | .idea/inspectionProfiles/Project_Default.xml
49 | .idea/inspectionProfiles/profiles_settings.xml
50 | .idea/misc.xml
51 | .idea/modules.xml
52 | .idea/scopes/scope_settings.xml
53 | .idea/vcs.xml
54 | .idea/workspace.xml
55 | .idea/libraries
56 | captures/
57 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | 逛掘金很久了,之前注册过邮箱账号,但是现在每次登录,都要求重置密码,改了也没用,很绝望,重新注册了一个账号。
2 | 今天第一次在掘金上分享,废话不多说,直接开始正题。
3 |
4 | - [概述]()
5 | - [合并的坑]()
6 | - [思考与扩展]()
7 | - [混淆配置]()
8 | - [小结]()
9 |
10 | ### 概述
11 |
12 | 简单介绍一下项目情况,笔者做这个项目快两年了,之所以有这篇文章,源于项目的需求,因为项目除了公司内部使用,`还需要抽取sdk给第三方合作公司使用,并且不同的合作方可能会对sdk作改动,A公司可能不要录屏功能,B公司可能只要视频播放功能,不要视频发布`,如何在不侵入我们主版本业务的情况下解决这个问题呢?
13 |
14 | 聪明的你肯定想到了,切分支呗!
15 |
16 | 
17 |
18 | 这种方式只能解决一时之需,但是后续的主版本迭代,差异会越来越大,主版本同步到SDK的效率越来越低。
19 | 所以一旦是你采用了此种方案,我个人建议你做好跑路的准备!
20 |
21 | 所以去年底的时候,将组件化落地到了项目中,将各个模块独立,按照第三方的需要,实现灵活的搭配,这样一来,可以解耦我们的各个模块,便于维护,也可以适应第三方的定制需求,但是今天笔者讨论的并非组件化相关的内容,与该主题相关的内容很多,笔者今天想讨论的是组件化之后踩到的一些坑,,可能这些坑你永远也不会碰到,但是既然来了,看完又何妨呢?
22 |
23 | 目前项目架构如图所示:
24 |
25 | 
26 |
27 | 组件化已基本完成,这才迈开了第一步,如何实现差异化呢?
28 |
29 | >1.分别打包
30 |
31 | 将各个独立的组件分别打包成对应的aar,提供给第三方,但是又涉及到一个问题,那就是混淆的问题,如果直接分别提供原始的aar包,那么源代码几乎等于完全暴露,如果分别混淆,又会存在一个问题,公共组件中常用的工具类被混淆,上层的短视频这些组件就会找不到对应的类。
32 | > 2.合并打包
33 |
34 | 这种方案具备良好的可行性,因为最终合并的文件只有一个,便于混淆,遗憾的是Android官方并没有提供这种合并的操作,但是发现github上有作者开源了一个合并脚本[fat-aar.gradle](https://github.com/adwiv/android-fat-aar),这个脚本的作用实际就是合并我们的多个组件为一个aar
35 |
36 | ### 合并的坑
37 |
38 | 下面笔者将用一个示例工程来演示合并的一些相关问题。
39 | [合并组件工程示例](https://github.com/byhook/merge-module)
40 |
41 | 用一张简单的图来描述其中的依赖关系
42 | 
43 |
44 | 最上层的是我们要生成的最终的merge.aar
45 | 他会合并直播间liveroom模块,合并video视频模块,而对应的模块也会依赖下层的组件,如何依赖合并呢?
46 |
47 | ```
48 | apply from: "../fat-aar.gradle"
49 | ```
50 |
51 | ```
52 | embedded project(':common')
53 | embedded project(':upload')
54 | embedded project(':download')
55 | embedded project(':video')
56 | embedded project(':liveroom')
57 | ```
58 |
59 | >注意: 需要合并的组件,只需要在最上层的组件中使用`embedded`关键字标记即可,并且下层所依赖的所有组件,都需要标记一次
60 |
61 | 接下来直接使用命令打包合并
62 | ```
63 | cd merge
64 | gradle clean asR
65 | ```
66 | 合并完成之后你以为就结束了吗?你太年轻了!!!
67 | 当你给别人使用的时候,马上就会发现第一个坑:
68 | 
69 |
70 | 出现这个错误的原因,经过笔者肉眼的分析(各种google,各种stackoverflow),发现是由gradle 的插件版本引起的
71 |
72 | 笔者工作的环境
73 | ```
74 | 系统: ubuntu 16.04
75 | gradle插件版本是2.3.3
76 | gradle的版本是3.5
77 | ```
78 | 降级到gradle插件版本
79 | ```
80 | classpath 'com.android.tools.build:gradle:2.2.3'
81 | ```
82 | 此时编译直接报错:
83 |
84 | 
85 |
86 | 笔者用了一个比较笨的方法:
87 | 强行指定fat-aar.gradle脚本中的版本
88 |
89 | 
90 |
91 | 终于合并完成!!!
92 | 但是不明白这两者合并出来的aar包差异在哪里,所以我将两个插件版本分别合并的aar包截图观察了一下
93 |
94 | `gradle2.3.3版本`合并的aar包
95 | 
96 | `gradle2.2.3版本`合并的aar包
97 | 
98 |
99 | 可以看到后者打包出来的aar文件,在libs目录中有一个jar包,这个jar包里存放的就是相关的R文件
100 |
101 | 所以解决上述问题的方案:
102 | >1.降级gradle插件版本到2.2.3版本,并修改对应脚本里的版本号
103 |
104 | >2.使用gradle插件版本2.2.3以上,但是需要手动修改fat-aar.gradle插件的内容,使之合并相关的R文件的jar包,这个问题大家也可以思考一下?
105 |
106 | >要知道,gradle的远程依赖功能实在是太方便了,我们可以很轻易的指定相关的依赖包,但是由于aar文件的特殊性,我们在组件中包含的一下远程依赖并不会被实际的合并到aar中去,例如你远程依赖了okhttp或者glide等相关的库,合并aar之后,就会出现如下的错误:
107 |
108 | 
109 |
110 | 如何解决这个问题呢?聪明的你一定想到,`maven`
111 |
112 | 我们完全可以把这些依赖合并发布到maven中去,于是笔者尝试着搭建了[nexus私服](https://www.sonatype.com/download-oss-sonatype),具体的搭建不是本文讨论的重点。
113 |
114 | 幸运的是,fat-aar的作者给我们提供了相关的publish.gradle的脚本,真的不得不说,想什么来什么啊,既然有了现成的轮子,我们就直接跑呗!
115 |
116 | 在最上层的`merge`模块中添加依赖
117 | ```
118 | apply from: '../publish.gradle'
119 | ```
120 | 并添加如下配置
121 | ```
122 | android {
123 |
124 | ...
125 |
126 | libraryVariants.all { variant ->
127 | variant.outputs.each { output ->
128 | def outputFile = output.outputFile
129 | if (outputFile != null && outputFile.name.endsWith('.aar')) {
130 | def fileName = getArtifactFileName()
131 | output.outputFile = new File(outputFile.parent, fileName)
132 | }
133 | }
134 | }
135 |
136 | }
137 |
138 | def getArtifactFileName() {
139 | return "${POM_ARTIFACT_ID}-${VERSION_NAME}.aar"
140 | }
141 | ```
142 |
143 | 接下来配置自己的nexus私服即可
144 | ```
145 | maven {
146 | //替换自己搭建的私服
147 | url "http://127.0.0.1:8081/nexus/content/repositories/releases"
148 | }
149 | ```
150 |
151 | 通刚才的合并打包方式,最后发布到自己的nexus私服上
152 | 
153 |
154 | 你以为这样就结束了吗?并没有!!!
155 |
156 | 实际操作过程中,笔者发现,我们本地实际是有依赖`本地第三方的aar包`的,换句话说,并非所有的库都是远程依赖,你会发现,原来脚本居然会将本地依赖的aar文件,也合并到pom.xml文件中,继而发布到nexus私服上去了,这个时候给别人远程依赖,就会一直找不到相关的本地库
157 |
158 | 
159 |
160 | `如何解决呢?`
161 |
162 | 看来偷懒是不行的了,还是得改脚本,经过笔者的观察,发现在生成的pom.xml中可以过滤掉
163 | ```
164 | pom.withXml {
165 | def dependenciesNode = asNode().appendNode('dependencies')
166 |
167 | depList.values().each {
168 | ResolvedDependency dep ->
169 | def hasGroup = dep.moduleGroup != null
170 | def hasName = (dep.moduleName != null && !"unspecified".equals(dep.moduleName) && !"".equals(dep.moduleVersion))
171 | def hasVersion = (dep.moduleVersion != null && !"".equals(dep.moduleVersion) && !"unspecified".equals(dep.moduleVersion))
172 |
173 | if (hasGroup && hasName && hasVersion) {
174 | def dependencyNode = dependenciesNode.appendNode('dependency')
175 | dependencyNode.appendNode('groupId', dep.moduleGroup)
176 | dependencyNode.appendNode('artifactId', dep.moduleName)
177 | dependencyNode.appendNode('version', dep.moduleVersion)
178 | }
179 | }
180 | }
181 | ```
182 | 即把版本号为空的过滤掉即可。
183 |
184 | ### 思考与扩展
185 | 经过一番折腾,好歹也是合并出来我们想要的东西,但是笔者刚刚也说到了,公司主项目除了自己使用,还是组合成sdk给第三方使用,第三方可能会改下首页的布局,颜色,等等。如何在不侵入主业务的情况下,作变更呢?其实很简单,借鉴Android中多渠道包的生成,同名的资源放在不同的目录
186 | 遗憾的是原生的脚本并不支持这种姿势,我在最上层的`merge`模块中使用同名的资源试图覆盖下层的资源,达到替换的目的,并未得逞!!!
187 | 没办法,还是得改脚本,改动的思想实际就是在脚本合并的过程中,优先记录最上层的资源名称,当合并下层模块的资源文件时,直接跳过即可,改过的脚本在文章的末尾。
188 |
189 | ### 混淆配置
190 | 关于混淆的配置,只需要在最上层的merge模块中配置即可
191 |
192 | ### 注意事项
193 | >1.尽量不要使用原本的脚本文件,因为原作者已经几年未更新过,文章末尾有笔者的改动过的脚本文件
194 |
195 | >2.各个组件的清单会合并,不需要在最上层的组件中统一注册
196 |
197 | >3.本地依赖的jar包不用担心,因为脚本会合并到最终aar库的lib目录下
198 |
199 | >4.本地依赖的aar包,要记得随着远程依赖,给第三方一起依赖,即第三方除了依赖我们的远程依赖,还需要本地依赖我们所使用的aar文件,这也算是一个缺陷吧
200 |
201 | >5.第三方依赖的插件版本最好跟我们合并使用的gradle版本一致
202 |
203 | ### 小结
204 |
205 |
206 | 到目前为止,合并多组件的几个坑基本已经走了一遍了,其实在去年底,笔者在公司的直播项目中已经将组件化落地了,而后在实现多组件的道路上也踩了不少坑,本来这篇文章并没有打算发布出来,因为并不是所有人都会碰到这类需求,但是前段时间有个朋友公司问了我相关的问题,看他踩坑了很久,所以还是觉得发布出来,至少对于看到的人而言,以后碰到类似问题,可以少走些弯路,提高效率。
207 |
208 | `纸上得来终觉浅,绝知此事要躬行!`
209 |
210 |
211 | [示例项目](https://github.com/byhook/merge-module)
212 |
213 | [脚本地址](https://github.com/byhook/merge-gradle)
214 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | //构建版本
5 | compileSdkVersion rootProject.ext.android.compileSdkVersion
6 | buildToolsVersion rootProject.ext.android.buildToolsVersion
7 | //默认的配置
8 | defaultConfig {
9 | minSdkVersion rootProject.ext.android.minSdkVersion
10 | targetSdkVersion rootProject.ext.android.targetSdkVersion
11 | versionCode rootProject.ext.android.versionCode
12 | versionName rootProject.ext.android.versionName
13 | applicationId rootProject.ext.android.applicationId
14 |
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | repositories {
26 | jcenter()
27 | maven {
28 | //替换自己搭建的私服
29 | url uri("/home/byhook/android/maven")
30 | }
31 | }
32 |
33 | configurations.all {
34 | resolutionStrategy {
35 | force 'com.android.support:appcompat-v7:25.3.1'
36 | force 'com.android.support:support-annotations:25.3.1'
37 | }
38 | }
39 |
40 | dependencies {
41 | compile fileTree(dir: 'libs', include: ['*.jar'])
42 | compile 'com.android.support:appcompat-v7:25.3.1'
43 | testCompile 'junit:junit:4.12'
44 | androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
45 |
46 | //先在merge目录下执行合并gradle clean asR,右侧栏目gradle选择发布到maven,再进行依赖
47 | compile 'com.onzhou.module:merge:1.0.1'
48 | }
49 |
--------------------------------------------------------------------------------
/app/libs/merge-release.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/libs/merge-release.aar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/onzhou/module/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.onzhou.module", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/onzhou/module/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.view.View;
6 |
7 | import com.onzhou.module.download.DownloadActivity;
8 | import com.onzhou.module.liveroom.LiveRoomActivity;
9 | import com.onzhou.module.upload.UploadActivity;
10 | import com.onzhou.module.video.VideoPlayActivity;
11 |
12 | public class MainActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_main);
18 | }
19 |
20 | public void onDownloadClick(View view) {
21 | DownloadActivity.intentStart(this);
22 | }
23 |
24 | public void onUploadClick(View view) {
25 | UploadActivity.intentStart(this);
26 | }
27 |
28 |
29 | public void onLiveClick(View view) {
30 |
31 | LiveRoomActivity.intentStart(this);
32 | }
33 |
34 | public void onVideoClick(View view) {
35 | VideoPlayActivity.intentStart(this);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
25 |
26 |
33 |
34 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 合并组件
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/onzhou/module/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: "config.gradle"
2 |
3 | buildscript {
4 |
5 | repositories {
6 | maven {
7 | //替换自己搭建的私服 如: http://127.0.0.1:8081/nexus/content/repositories/releases
8 | url uri("/home/byhook/android/maven")
9 | }
10 | mavenCentral()
11 | jcenter()
12 | }
13 | dependencies {
14 | classpath 'com.android.tools.build:gradle:2.2.3'
15 |
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | maven {
22 | //替换自己搭建的私服
23 | url uri("/home/byhook/android/maven")
24 | }
25 | mavenCentral()
26 | jcenter()
27 | }
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/common/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/common/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: '../module.gradle'
2 |
3 | dependencies {
4 | compile fileTree(dir: 'libs', include: ['*.jar'])
5 | }
6 |
--------------------------------------------------------------------------------
/common/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/common/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/common/src/main/java/com/onzhou/module/common/CommonActivity.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.common;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 |
9 | /**
10 | * @author: andy
11 | * @date: 2018-06-19
12 | **/
13 | public class CommonActivity extends AppCompatActivity {
14 |
15 | public static void intentStart(Context ctx) {
16 | Intent intent = new Intent(ctx, CommonActivity.class);
17 | ctx.startActivity(intent);
18 | }
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_common);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/res/layout/activity_common.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/common/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | common
3 |
4 |
--------------------------------------------------------------------------------
/common/src/test/java/com/onzhou/module/common/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.common;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | android = [
3 | compileSdkVersion: 25,
4 | buildToolsVersion: "25.0.3",
5 | applicationId : "com.onzhou.module",
6 | minSdkVersion : 16,
7 | targetSdkVersion : 25,
8 | versionCode : 1,
9 | versionName : "1.0.0",
10 |
11 | //是否开启测试环境
12 | MODE_DEBUG : false
13 | ]
14 |
15 | dependencies = [
16 | "design" : 'com.android.support:design:25.3.1',
17 | "appcompat-v7": 'com.android.support:appcompat-v7:25.3.1',
18 | "multidex" : "com.android.support:multidex:1.0.1",
19 | "junit" : 'junit:junit:4.12'
20 | ]
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/download/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/download/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: '../module.gradle'
2 |
3 | dependencies {
4 | compile fileTree(dir: 'libs', include: ['*.jar'])
5 | compile project(':common')
6 | }
7 |
--------------------------------------------------------------------------------
/download/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/download/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/download/src/main/java/com/onzhou/module/download/DownloadActivity.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.download;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 |
9 | /**
10 | * @author: andy
11 | * @date: 2018-06-19
12 | **/
13 | public class DownloadActivity extends AppCompatActivity {
14 |
15 | public static void intentStart(Context ctx) {
16 | Intent intent = new Intent(ctx, DownloadActivity.class);
17 | ctx.startActivity(intent);
18 | }
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_download);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/download/src/main/res/layout/activity_download.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/download/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | download
3 |
4 |
--------------------------------------------------------------------------------
/download/src/test/java/com/onzhou/module/download/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.download;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/fat-aar.gradle:
--------------------------------------------------------------------------------
1 | /**
2 | * This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 |
29 | import com.android.annotations.NonNull
30 | import com.android.manifmerger.ManifestMerger2
31 | import com.android.manifmerger.ManifestMerger2.Invoker
32 | import com.android.manifmerger.ManifestMerger2.MergeType
33 | import com.android.manifmerger.MergingReport
34 | import com.android.manifmerger.PlaceholderEncoder
35 | import com.android.manifmerger.XmlDocument
36 | import com.android.utils.ILogger
37 | import com.google.common.base.Charsets
38 | import com.google.common.io.Files
39 |
40 | /**
41 | * Fat AAR Lib generator v 0.2.1
42 | * Target Gradle Version :: 2.2.0
43 | *
44 | * Latest version available at https://github.com/adwiv/android-fat-aar
45 | * Please report issues at https://github.com/adwiv/android-fat-aar/issues
46 | *
47 | * This code is in public domain.
48 | *
49 | * Use at your own risk and only if you understand what it does. You have been warned ! :-)
50 | */
51 |
52 | buildscript {
53 | repositories {
54 | jcenter()
55 | }
56 | dependencies {
57 | classpath 'com.android.tools.build:manifest-merger:25.3.2'
58 | }
59 | }
60 |
61 | configurations {
62 | embedded
63 | }
64 |
65 | dependencies {
66 | compile configurations.embedded
67 | }
68 |
69 | // Paths to embedded jar files
70 | ext.embeddedJars = new ArrayList()
71 | // Paths to embedded aar projects
72 | ext.embeddedAarDirs = new ArrayList()
73 | // Embedded aar files dependencies
74 | ext.embeddedAarFiles = new ArrayList()
75 | // List of embedded R classes
76 | ext.embeddedRClasses = new ArrayList()
77 |
78 | // Change backslash to forward slash on windows
79 | ext.build_dir = buildDir.path.replace(File.separator, '/');
80 | ext.root_dir = project.rootDir.absolutePath.replace(File.separator, '/');
81 | ext.exploded_aar_dir = "$build_dir/intermediates/exploded-aar";
82 | ext.classs_release_dir = "$build_dir/intermediates/classes/release";
83 | ext.bundle_release_dir = "$build_dir/intermediates/bundles/release";
84 | ext.manifest_aaapt_dir = "$build_dir/intermediates/manifests/aapt/release";
85 | ext.generated_rsrc_dir = "$build_dir/generated/source/r/release";
86 |
87 | ext.base_r2x_dir = "$build_dir/fat-aar/release/";
88 |
89 | def gradleVersionStr = GradleVersion.current().getVersion();
90 |
91 | //2.2以上api有变动,报错
92 | ext.gradleApiVersion = "2.2".toFloat();//gradleVersionStr.substring(0, gradleVersionStr.lastIndexOf(".")).toFloat();
93 |
94 | println "Gradle version: " + gradleVersionStr;
95 |
96 | afterEvaluate {
97 | // the list of dependency must be reversed to use the right overlay order.
98 | def dependencies = new ArrayList(configurations.embedded.resolvedConfiguration.firstLevelModuleDependencies)
99 | dependencies.reverseEach {
100 |
101 | def aarPath;
102 | if (gradleApiVersion >= 2.3f)
103 | aarPath = "${root_dir}/${it.moduleName}/build/intermediates/bundles/default"
104 | else
105 | aarPath = "${exploded_aar_dir}/${it.moduleGroup}/${it.moduleName}/${it.moduleVersion}"
106 | it.moduleArtifacts.each {
107 | artifact ->
108 |
109 | println "ARTIFACT 3 : "
110 | println artifact
111 | if (artifact.type == 'aar') {
112 | if (!embeddedAarFiles.contains(artifact)) {
113 | embeddedAarFiles.add(artifact)
114 | }
115 | if (!embeddedAarDirs.contains(aarPath)) {
116 | if (artifact.file.isFile()) {
117 | println artifact.file
118 | println aarPath
119 |
120 | copy {
121 | from zipTree(artifact.file)
122 | into aarPath
123 | }
124 | }
125 | embeddedAarDirs.add(aarPath)
126 | }
127 | } else if (artifact.type == 'jar') {
128 | def artifactPath = artifact.file
129 | if (!embeddedJars.contains(artifactPath))
130 | embeddedJars.add(artifactPath)
131 | } else {
132 | throw new Exception("Unhandled Artifact of type ${artifact.type}")
133 | }
134 | }
135 | }
136 |
137 | if (dependencies.size() > 0) {
138 | // Merge Assets
139 | generateReleaseAssets.dependsOn embedAssets
140 | embedAssets.dependsOn prepareReleaseDependencies
141 |
142 | // Embed Resources by overwriting the inputResourceSets
143 | packageReleaseResources.dependsOn embedLibraryResources
144 | embedLibraryResources.dependsOn prepareReleaseDependencies
145 |
146 | // Embed JNI Libraries
147 | bundleRelease.dependsOn embedJniLibs
148 |
149 | println("==============================" + gradleApiVersion + "==========================")
150 |
151 | if (gradleApiVersion >= 2.3f) {
152 | embedJniLibs.dependsOn transformNativelibsWithSyncJniLibsForRelease
153 | ext.bundle_release_dir = "$build_dir/intermediates/bundles/default"
154 | } else {
155 | embedJniLibs.dependsOn transformNative_libsWithSyncJniLibsForRelease
156 | ext.bundle_release_dir = "$build_dir/intermediates/bundles/release";
157 | }
158 |
159 | // Merge Embedded Manifests
160 | bundleRelease.dependsOn embedManifests
161 | embedManifests.dependsOn processReleaseManifest
162 |
163 | // Merge proguard files
164 | embedLibraryResources.dependsOn embedProguard
165 | embedProguard.dependsOn prepareReleaseDependencies
166 |
167 | // Generate R.java files
168 | compileReleaseJavaWithJavac.dependsOn generateRJava
169 | generateRJava.dependsOn processReleaseResources
170 |
171 | // Bundle the java classes
172 | bundleRelease.dependsOn embedJavaJars
173 | embedJavaJars.dependsOn compileReleaseJavaWithJavac
174 |
175 | //合并R文件
176 | collectRClass.dependsOn compileReleaseJavaWithJavac
177 |
178 | // If proguard is enabled, run the tasks that bundleRelease should depend on before proguard
179 | if (tasks.findByPath('proguardRelease') != null) {
180 | proguardRelease.dependsOn embedJavaJars
181 | } else if (tasks.findByPath('transformClassesAndResourcesWithProguardForRelease') != null) {
182 | transformClassesAndResourcesWithProguardForRelease.dependsOn embedJavaJars
183 | }
184 | }
185 | }
186 |
187 | task embedLibraryResources << {
188 | println "Running FAT-AAR Task :embedLibraryResources"
189 |
190 | def oldInputResourceSet = packageReleaseResources.inputResourceSets
191 | packageReleaseResources.conventionMapping.map("inputResourceSets") {
192 | getMergedInputResourceSets(oldInputResourceSet)
193 | }
194 | }
195 |
196 | /**
197 | * 本地资源
198 | * 由于合并module的时候
199 | * 资源文件无法替换
200 | */
201 |
202 | private List getMergedInputResourceSets(List inputResourceSet) {
203 | //We need to do this trickery here since the class declared here and that used by the runtime
204 | //are different and results in class cast error
205 | def ResourceSetClass = inputResourceSet.get(0).class
206 |
207 | List newInputResourceSet = new ArrayList(inputResourceSet)
208 |
209 | HashMap localRes = new HashMap()
210 | String path = buildDir.path.replace("/build", "") + "/src/main/res"
211 | FileTree moduleRes = fileTree(dir: path, include: '**/*.xml')
212 | moduleRes.each { File file ->
213 | println("路径=" + file.getAbsolutePath() + "/" + file.getName())
214 | localRes.put(file.getName(), file.getAbsolutePath())
215 | }
216 |
217 | println "getMergedInputResourceSets"
218 |
219 | println embeddedAarDirs
220 | embeddedAarDirs.each { aarPath ->
221 | try {
222 | println aarPath
223 | def resname
224 | if (gradleApiVersion >= 2.3f) {
225 | def parentProject = project.rootProject.name.toString()
226 | println "parent: "
227 | println parentProject
228 |
229 | def startIndex = aarPath.indexOf('/' + parentProject)
230 | def endIndex = aarPath.indexOf('/build/')
231 |
232 | println "start"
233 | println startIndex
234 | println "end"
235 | println endIndex
236 | if (startIndex < 1 || endIndex < 1)
237 | return;
238 | resname = aarPath.substring(startIndex, endIndex).replace('/', ':')
239 | } else
240 | resname = (aarPath.split(exploded_aar_dir)[1]).replace('/', ':');
241 |
242 | FileTree libRes = fileTree(dir: "$aarPath/res", include: '**/*.xml')
243 | libRes.each { File file ->
244 | if (localRes.containsKey(file.getName())) {
245 | println("资源重复" + file.getAbsolutePath())
246 | file.delete()
247 | }
248 | }
249 | def rs = ResourceSetClass.newInstance([resname, true] as Object[])
250 | rs.addSource(file("$aarPath/res"))
251 | println "ResourceSet is " + rs
252 | println resname
253 | println "$aarPath/res"
254 | newInputResourceSet += rs
255 | } catch (Exception e) {
256 | e.printStackTrace();
257 | throw e;
258 | }
259 | }
260 |
261 | return newInputResourceSet
262 | }
263 |
264 | /**
265 | * Assets are simple files, so just adding them to source set seems to work.
266 | */
267 | task embedAssets << {
268 | println "Running FAT-AAR Task :embedAssets"
269 | embeddedAarDirs.each { aarPath ->
270 | // Merge Assets
271 | android.sourceSets.main.assets.srcDirs += file("$aarPath/assets")
272 | }
273 | }
274 |
275 | /**
276 | * Merge proguard.txt files from all library modules
277 | * @author Marian Klühspies
278 | */
279 | task embedProguard << {
280 | println "Running FAT-AAR Task :embedProguard"
281 |
282 | def proguardRelease = file("$bundle_release_dir/proguard.txt")
283 | embeddedAarDirs.each { aarPath ->
284 | try {
285 | def proguardLibFile = file("$aarPath/proguard.txt")
286 | if (proguardLibFile.exists())
287 | proguardRelease.append("\n" + proguardLibFile.text)
288 | } catch (Exception e) {
289 | e.printStackTrace();
290 | throw e;
291 | }
292 | }
293 | }
294 |
295 |
296 | task generateRJava << {
297 | println "Running FAT-AAR Task :generateRJava"
298 |
299 | // Now generate the R.java file for each embedded dependency
300 | def mainManifestFile = android.sourceSets.main.manifest.srcFile;
301 | def libPackageName = "";
302 |
303 | if (mainManifestFile.exists()) {
304 |
305 | libPackageName = new XmlParser().parse(mainManifestFile).@package
306 | }
307 |
308 | embeddedAarDirs.each { aarPath ->
309 |
310 | def manifestFile = file("$aarPath/AndroidManifest.xml");
311 | if (!manifestFile.exists()) {
312 | manifestFile = file("./src/main/AndroidManifest.xml");
313 | }
314 |
315 | if (manifestFile.exists()) {
316 | def aarManifest = new XmlParser().parse(manifestFile);
317 | def aarPackageName = aarManifest.@package
318 |
319 | String packagePath = aarPackageName.replace('.', '/')
320 |
321 | // Generate the R.java file and map to current project's R.java
322 | // This will recreate the class file
323 | def rTxt = file("$aarPath/R.txt")
324 | def rMap = new ConfigObject()
325 |
326 | if (rTxt.exists()) {
327 | rTxt.eachLine {
328 | line ->
329 | //noinspection GroovyUnusedAssignment
330 | def (type, subclass, name, value) = line.tokenize(' ')
331 | rMap[subclass].putAt(name, type)
332 | }
333 | }
334 |
335 | def sb = "package $aarPackageName;" << '\n' << '\n'
336 | sb << 'public final class R {' << '\n'
337 |
338 | rMap.each {
339 | subclass, values ->
340 | sb << " public static final class $subclass {" << '\n'
341 | values.each {
342 | name, type ->
343 | sb << " public static $type $name = ${libPackageName}.R.${subclass}.${name};" << '\n'
344 | }
345 | sb << " }" << '\n'
346 | }
347 |
348 | sb << '}' << '\n'
349 |
350 | mkdir("$generated_rsrc_dir/$packagePath")
351 | file("$generated_rsrc_dir/$packagePath/R.java").write(sb.toString())
352 |
353 | embeddedRClasses += "$packagePath/R.class"
354 | embeddedRClasses += "$packagePath/R\$*.class"
355 | }
356 |
357 | }
358 | }
359 |
360 | task collectRClass << {
361 | println "COLLECTRCLASS"
362 | delete base_r2x_dir
363 | mkdir base_r2x_dir
364 |
365 | copy {
366 | from classs_release_dir
367 | include embeddedRClasses
368 | into base_r2x_dir
369 | }
370 | }
371 |
372 | task embedRClass(type: org.gradle.jvm.tasks.Jar, dependsOn: collectRClass) {
373 | println "EMBED R CLASS"
374 |
375 | destinationDir file("$bundle_release_dir/libs/")
376 | println destinationDir
377 | from base_r2x_dir
378 | println base_r2x_dir
379 | }
380 |
381 | /**
382 | * To embed the class files, we need to change the R.class to X.class, so we explode it in another
383 | * location, proguard it to modify R to X, and then finally copy it to build location
384 | */
385 | task embedJavaJars(dependsOn: embedRClass) << {
386 | println "Running FAT-AAR Task :embedJavaJars"
387 |
388 | embeddedAarDirs.each { aarPath ->
389 |
390 | // Explode all classes.jar files to classes so that they can be proguarded
391 | def jar_dir
392 | if (gradleApiVersion >= 2.3f)
393 | jar_dir = "$aarPath"
394 | else
395 | jar_dir = "$aarPath/jars"
396 |
397 | if (embeddedAarFiles.size() > 0) {
398 |
399 | embeddedAarFiles.each {
400 | artifact ->
401 | FileTree aarFileTree = zipTree(artifact.file.getAbsolutePath());
402 |
403 | def aarFile = aarFileTree.files.find { it.name.contains("classes.jar") }
404 |
405 | copy {
406 | from zipTree(aarFile)
407 | into classs_release_dir
408 | }
409 | }
410 |
411 | } else {
412 |
413 | println jar_dir
414 | println classs_release_dir
415 | println bundle_release_dir
416 | println embeddedJars
417 |
418 | copy {
419 | from zipTree(jar_dir + "/classes.jar")
420 | into classs_release_dir
421 | }
422 | }
423 |
424 | // Copy all additional jar files to bundle lib
425 | FileTree jars = fileTree(dir: jar_dir, include: '*.jar', exclude: 'classes.jar')
426 | jars += fileTree(dir: jar_dir + "/libs", include: '*.jar')
427 | jars += fileTree(dir: "$aarPath/libs", include: '*.jar')
428 |
429 | copy {
430 | from jars
431 | into file("$bundle_release_dir/libs")
432 | }
433 |
434 | // Copy all embedded jar files to bundle lib
435 | copy {
436 | from embeddedJars
437 | into file("$bundle_release_dir/libs")
438 | }
439 | }
440 | }
441 |
442 | /**
443 | * For some reason, adding to the jniLibs source set does not work. So we simply copy all files.
444 | */
445 | task embedJniLibs << {
446 | println "Running FAT-AAR Task :embedJniLibs"
447 |
448 | embeddedAarDirs.each { aarPath ->
449 | println "======= Copying JNI from $aarPath/jni"
450 | // Copy JNI Folders
451 | copy {
452 | from fileTree(dir: "$aarPath/jni")
453 | into file("$bundle_release_dir/jni")
454 | }
455 | }
456 | }
457 |
458 | task embedManifests << {
459 | println "Running FAT-AAR Task :embedManifests"
460 |
461 | ILogger mLogger = new MiLogger()
462 | List libraryManifests = new ArrayList<>()
463 |
464 | embeddedAarDirs.each { aarPath ->
465 | File dependencyManifest = file("$aarPath/AndroidManifest.xml")
466 |
467 | if (!libraryManifests.contains(aarPath) && dependencyManifest.exists()) {
468 | libraryManifests.add(dependencyManifest)
469 | }
470 | }
471 |
472 | File reportFile = file("${build_dir}/embedManifestReport.txt")
473 |
474 | File origManifest = file("$bundle_release_dir/AndroidManifest.xml")
475 | File copyManifest = file("$bundle_release_dir/AndroidManifest.orig.xml")
476 | File aaptManifest = file("$manifest_aaapt_dir/AndroidManifest.xml")
477 |
478 | if (!origManifest.exists()) {
479 | origManifest = file("./src/main/AndroidManifest.xml")
480 | }
481 |
482 | if (!origManifest.exists()) {
483 | return;
484 | }
485 |
486 | copy {
487 | from origManifest.parentFile
488 | into copyManifest.parentFile
489 | include origManifest.name
490 | rename(origManifest.name, copyManifest.name)
491 | }
492 |
493 | try {
494 | Invoker manifestMergerInvoker = ManifestMerger2.newMerger(copyManifest, mLogger, MergeType.APPLICATION)
495 |
496 | manifestMergerInvoker.addLibraryManifests(libraryManifests.toArray(new File[libraryManifests.size()]))
497 |
498 | // manifestMergerInvoker.setPlaceHolderValues(placeHolders)
499 | manifestMergerInvoker.setMergeReportFile(reportFile);
500 |
501 | MergingReport mergingReport = manifestMergerInvoker.merge();
502 |
503 | mLogger.info("Merging result:" + mergingReport.getResult());
504 | MergingReport.Result result = mergingReport.getResult();
505 | switch (result) {
506 | case MergingReport.Result.WARNING:
507 | mergingReport.log(mLogger);
508 | // fall through since these are just warnings.
509 | case MergingReport.Result.SUCCESS:
510 | XmlDocument xmlDocument = mergingReport.getMergedXmlDocument(MergingReport.MergedManifestKind.MERGED);
511 | try {
512 | String annotatedDocument = mergingReport.getActions().blame(xmlDocument);
513 | mLogger.verbose(annotatedDocument);
514 | } catch (Exception e) {
515 | mLogger.error(e, "cannot print resulting xml");
516 | }
517 | save(xmlDocument, origManifest);
518 | mLogger.info("Merged manifest saved to " + origManifest);
519 | if (aaptManifest.exists()) {
520 | new PlaceholderEncoder().visit(xmlDocument);
521 | save(xmlDocument, aaptManifest);
522 | mLogger.info("Merged aapt safe manifest saved to " + aaptManifest);
523 | }
524 | break;
525 | case MergingReport.Result.ERROR:
526 | mergingReport.log(mLogger);
527 | throw new RuntimeException(mergingReport.getReportString());
528 | default:
529 | throw new RuntimeException("Unhandled result type : " + mergingReport.getResult());
530 | }
531 | } catch (RuntimeException e) {
532 | // Unacceptable error
533 | e.printStackTrace()
534 | throw new RuntimeException(e);
535 | }
536 | }
537 |
538 | private void save(XmlDocument xmlDocument, File out) {
539 | try {
540 | Files.write(xmlDocument.prettyPrint(), out, Charsets.UTF_8);
541 | } catch (IOException e) {
542 | throw new RuntimeException(e);
543 | }
544 | }
545 |
546 | class MiLogger implements ILogger {
547 |
548 | @Override
549 | void error(
550 | @com.android.annotations.Nullable Throwable t,
551 | @com.android.annotations.Nullable String msgFormat, Object... args) {
552 | System.err.println(String.format("========== ERROR : " + msgFormat, args))
553 | if (t) t.printStackTrace(System.err)
554 | }
555 |
556 | @Override
557 | void warning(@NonNull String msgFormat, Object... args) {
558 | System.err.println(String.format("========== WARNING : " + msgFormat, args))
559 | }
560 |
561 | @Override
562 | void info(@NonNull String msgFormat, Object... args) {
563 | System.out.println(String.format("========== INFO : " + msgFormat, args))
564 | }
565 |
566 | @Override
567 | void verbose(@NonNull String msgFormat, Object... args) {
568 | // System.out.println(String.format("========== DEBUG : " + msgFormat, args))
569 | }
570 | }
571 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Tue Mar 26 15:43:26 CST 2019
16 | org.gradle.jvmargs=-Xmx1536m
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byhook/merge-module/3f045c1e75ee63b397638654940226f5d859d728/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jun 19 11:09:20 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip
7 |
--------------------------------------------------------------------------------
/liveroom/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/liveroom/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: '../module.gradle'
2 |
3 |
4 | repositories {
5 | jcenter()
6 | flatDir {
7 | dirs "$rootDir/liveroom/libs"
8 | }
9 | }
10 |
11 |
12 | dependencies {
13 | compile fileTree(dir: 'libs', include: ['*.jar'])
14 |
15 | compile 'com.github.bumptech.glide:glide:3.8.0'
16 |
17 | compile project(':common')
18 | compile project(':download')
19 | }
20 |
--------------------------------------------------------------------------------
/liveroom/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/liveroom/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/liveroom/src/main/java/com/onzhou/module/liveroom/LiveRoomActivity.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.liveroom;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.widget.ImageView;
9 |
10 | import com.bumptech.glide.Glide;
11 |
12 | /**
13 | * @author: andy
14 | * @date: 2018-06-19
15 | **/
16 | public class LiveRoomActivity extends AppCompatActivity {
17 |
18 | public static void intentStart(Context ctx) {
19 | Intent intent = new Intent(ctx, LiveRoomActivity.class);
20 | ctx.startActivity(intent);
21 | }
22 |
23 | @Override
24 | protected void onCreate(@Nullable Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_live_room);
27 | }
28 |
29 | @Override
30 | protected void onPostCreate(@Nullable Bundle savedInstanceState) {
31 | super.onPostCreate(savedInstanceState);
32 | ImageView imageView = (ImageView) findViewById(R.id.iv_main);
33 | Glide.with(this).load("http://cdn.byhook.cn/0fc87e6251577216b34ec31f1f76ffdd-320_320.jpg").into(imageView);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/liveroom/src/main/res/layout/activity_live_room.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
15 |
19 |
20 |
--------------------------------------------------------------------------------
/liveroom/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | liveroom
3 |
4 |
--------------------------------------------------------------------------------
/liveroom/src/test/java/com/onzhou/module/liveroom/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.liveroom;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/merge/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/merge/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: '../module.gradle'
2 |
3 | apply from: '../fat-aar.gradle'
4 |
5 | apply from: '../publish.gradle'
6 |
7 | android {
8 |
9 | libraryVariants.all { variant ->
10 | variant.outputs.each { output ->
11 | def outputFile = output.outputFile
12 | if (outputFile != null && outputFile.name.endsWith('.aar')) {
13 | def fileName = getArtifactFileName()
14 | output.outputFile = new File(outputFile.parent, fileName)
15 | }
16 | }
17 | }
18 |
19 | }
20 |
21 | def getArtifactFileName() {
22 | return "${POM_ARTIFACT_ID}-${VERSION_NAME}.aar"
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 |
28 | embedded project(':common')
29 | embedded project(':upload')
30 | embedded project(':download')
31 | embedded project(':video')
32 | embedded project(':liveroom')
33 | }
34 |
--------------------------------------------------------------------------------
/merge/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Fri Aug 18 12:04:47 CST 2017
16 | #maven配置
17 | GROUP=com.onzhou.module
18 | VERSION_NAME=1.0.1
19 | POM_ARTIFACT_ID=merge
20 |
--------------------------------------------------------------------------------
/merge/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/merge/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/merge/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | merge
3 |
4 |
--------------------------------------------------------------------------------
/merge/src/test/java/com/onzhou/module/merge/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.merge;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/module.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | //构建版本
5 | compileSdkVersion rootProject.ext.android.compileSdkVersion
6 | buildToolsVersion rootProject.ext.android.buildToolsVersion
7 | //默认的配置
8 | defaultConfig {
9 | minSdkVersion rootProject.ext.android.minSdkVersion
10 | targetSdkVersion rootProject.ext.android.targetSdkVersion
11 | versionCode rootProject.ext.android.versionCode
12 | versionName rootProject.ext.android.versionName
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | repositories {
25 | jcenter()
26 | flatDir {
27 | dirs 'libs', "$rootDir/liveroom/libs"
28 | }
29 | }
30 |
31 | dependencies {
32 | compile fileTree(include: ['*.jar'], dir: 'libs')
33 |
34 | testCompile rootProject.ext.dependencies["junit"]
35 |
36 | compile rootProject.ext.dependencies["appcompat-v7"]
37 | compile rootProject.ext.dependencies["design"]
38 | }
39 |
--------------------------------------------------------------------------------
/publish.gradle:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////
2 | //////////// MAVEN PUBLISHING //////////////
3 | ////////////////////////////////////////////
4 | apply plugin: 'maven-publish'
5 |
6 | publishing {
7 | publications {
8 | androidLibs(MavenPublication) {
9 | groupId = GROUP
10 | artifactId POM_ARTIFACT_ID
11 | version = VERSION_NAME
12 |
13 | artifact "${project.buildDir}/outputs/aar/${getArtifactFileName()}" //bundleRelease
14 |
15 | List embedList = new ArrayList<>();
16 | Map depList = new LinkedHashMap<>();
17 |
18 | //List all embedded dependencies
19 | configurations.embedded.allDependencies.each {
20 | def depName = String.format("%s:%s", it.group, it.name)
21 | embedList.add(depName);
22 | }
23 |
24 | //Collect all first level dependencies except embedded ones
25 | configurations.compile.resolvedConfiguration.firstLevelModuleDependencies.each {
26 | ResolvedDependency dep ->
27 | def depName = String.format("%s:%s", dep.moduleGroup, dep.moduleName)
28 | if (!embedList.contains(depName) && !depList.containsKey(depName)) {
29 | depList.put(depName, dep)
30 | }
31 | }
32 |
33 | //Collect all second level dependencies of embedded ones
34 | configurations.embedded.resolvedConfiguration.firstLevelModuleDependencies.each {
35 | //Second Level Depenencies
36 | it.children.each {
37 | ResolvedDependency dep ->
38 | def depName = String.format("%s:%s", dep.moduleGroup, dep.moduleName)
39 | if (!embedList.contains(depName) && !depList.containsKey(depName)) {
40 | depList.put(depName, dep)
41 | }
42 | }
43 | }
44 |
45 | //The publication doesn't know about our dependencies, so we have to manually add them to the pom
46 | pom.withXml {
47 | def dependenciesNode = asNode().appendNode('dependencies')
48 |
49 | depList.values().each {
50 | ResolvedDependency dep ->
51 | def hasGroup = dep.moduleGroup != null
52 | def hasName = (dep.moduleName != null && !"unspecified".equals(dep.moduleName) && !"".equals(dep.moduleVersion))
53 | def hasVersion = (dep.moduleVersion != null && !"".equals(dep.moduleVersion) && !"unspecified".equals(dep.moduleVersion))
54 |
55 | if (hasGroup && hasName && hasVersion) {
56 | def dependencyNode = dependenciesNode.appendNode('dependency')
57 | dependencyNode.appendNode('groupId', dep.moduleGroup)
58 | dependencyNode.appendNode('artifactId', dep.moduleName)
59 | dependencyNode.appendNode('version', dep.moduleVersion)
60 | }
61 | }
62 | }
63 | }
64 | }
65 | repositories {
66 | maven {
67 | //远程maven仓库的地址如: http://127.0.0.1:8081/nexus/content/repositories/releases
68 | url uri("/home/byhook/android/maven")
69 | //远程仓库需要配置密钥
70 | /*credentials {
71 | username "admin"
72 | password "haoadmin"
73 | }*/
74 | }
75 | }
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':common', ':video', ':liveroom', ':upload', ':download', ':merge'
2 |
--------------------------------------------------------------------------------
/upload/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/upload/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: '../module.gradle'
2 |
3 | dependencies {
4 | compile fileTree(dir: 'libs', include: ['*.jar'])
5 | compile project(':common')
6 | }
7 |
--------------------------------------------------------------------------------
/upload/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/upload/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/upload/src/main/java/com/onzhou/module/upload/UploadActivity.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.upload;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 |
9 | /**
10 | * @author: andy
11 | * @date: 2018-06-19
12 | **/
13 | public class UploadActivity extends AppCompatActivity {
14 |
15 | public static void intentStart(Context ctx) {
16 | Intent intent = new Intent(ctx, UploadActivity.class);
17 | ctx.startActivity(intent);
18 | }
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_upload);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/upload/src/main/res/layout/activity_upload.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/upload/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | upload
3 |
4 |
--------------------------------------------------------------------------------
/upload/src/test/java/com/onzhou/module/upload/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.upload;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/video/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/video/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: '../module.gradle'
2 |
3 | dependencies {
4 | compile fileTree(dir: 'libs', include: ['*.jar'])
5 | compile project(':common')
6 | compile project(':upload')
7 | }
8 |
--------------------------------------------------------------------------------
/video/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/video/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/video/src/main/java/com/onzhou/module/video/VideoPlayActivity.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.video;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.app.AppCompatActivity;
8 |
9 | /**
10 | * @author: andy
11 | * @date: 2018-06-19
12 | **/
13 | public class VideoPlayActivity extends AppCompatActivity {
14 |
15 | public static void intentStart(Context ctx) {
16 | Intent intent = new Intent(ctx, VideoPlayActivity.class);
17 | ctx.startActivity(intent);
18 | }
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_video_play);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/video/src/main/res/layout/activity_video_play.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/video/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | video
3 |
4 |
--------------------------------------------------------------------------------
/video/src/test/java/com/onzhou/module/video/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.onzhou.module.video;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------