Skip to content

Commit e5ae372

Browse files
authored
Merge pull request #7 from frogermcs/feature/consumerProguardFiles
Feature/consumer proguard files
2 parents b34ded3 + 8ab2174 commit e5ae372

File tree

7 files changed

+84
-7
lines changed

7 files changed

+84
-7
lines changed

README.md

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The project is a straightforward Github API client containing 3 screens (user se
2020
* repository - repository detail
2121
* base - module containing a code shared between all modules
2222

23-
![Project structure](https://raw.githubusercontent.com/frogermcs/MultiModuleGithubClient/master/docs/img/app_diagram.png "Project structure")
23+
![Project structure](docs/img/app_diagram.png "Project structure")
2424

2525
### Dependencies management
2626
It is easy to get lost with dependencies management across different project modules (especially with libs versions). To make it easier, take a look at `buildsystem/dependencies.gradle` where everything is configured. Each module has separate configuration, with additional two for testing and annotation processing. Like some other patterns, this was originally introduced in [Azimo](https://azimo.com) Android application by [@dbarwacz](https://github.com/dbarwacz).
@@ -38,7 +38,7 @@ Here are some highlights from it:
3838

3939
For the rest take a look at the code - should be self-explaining. As this is just self-invented setup (that works on production!), all kind of feedback is warmly welcomed.
4040

41-
![Dagger structue](https://raw.githubusercontent.com/frogermcs/MultiModuleGithubClient/master/docs/img/dagger_diagram.png "Dagger structure")
41+
![Dagger structue](docs/img/dagger_diagram.png "Dagger structure")
4242

4343
## Unit Testing
4444

@@ -108,7 +108,7 @@ or
108108

109109
The repository contains shared configurations for running Unit Tests directly from Android Studio.
110110

111-
![Android Studio configs](https://raw.githubusercontent.com/frogermcs/MultiModuleGithubClient/master/docs/img/as_run_configurations.png "Android Studio configs")
111+
![Android Studio configs](docs/img/as_run_configurations.png "Android Studio configs")
112112

113113
#### All tests at once
114114

@@ -118,14 +118,14 @@ Recently it is not always possible to run all tests at once (see troubleshooting
118118

119119
Run `App and modules tests`. This configuration will run unit tests from all modules in separate tabs, one after another. To modify list of tests, click on `Edit Configurations` -> `App and modules tests` -> `Before Launch`.
120120

121-
![All tests sequential](https://raw.githubusercontent.com/frogermcs/MultiModuleGithubClient/master/docs/img/all_tests_sequential.png "All tests sequential")
121+
![All tests sequential](docs/img/all_tests_sequential.png "All tests sequential")
122122

123123
#### Troubleshooting
124124

125125
* **Class not found: ... Empty test suite.**
126126
There is a bug in Android Studio which prevents from launching all unit tests at once, before their code is generated (what happens after the first run of unit tests for every single module independently). For more take a look at Android Studio bug tracker: https://issuetracker.google.com/issues/111154138.
127127

128-
![Android Studio issues](https://raw.githubusercontent.com/frogermcs/MultiModuleGithubClient/master/docs/img/failing_all_tests.png "Android Studio issues")
128+
![Android Studio issues](docs/img/failing_all_tests.png "Android Studio issues")
129129

130130
## Test coverage for unit tests
131131

@@ -157,7 +157,7 @@ buildTypes {
157157

158158
* Task `testDebugUnitTestCoverage` depends on `testDebugUnitTest` tasks (each module separately). Thanks to it all sources required for coverage report are available before gradle starts generating it (in `<module_dir>/build/...`.
159159

160-
![Coverage report](https://raw.githubusercontent.com/frogermcs/MultiModuleGithubClient/master/docs/img/coverage_report.png "Coverage report")
160+
![Coverage report](docs/img/coverage_report.png "Coverage report")
161161

162162

163163
## Instrumentation Testing
@@ -173,7 +173,7 @@ To run all Instrumentation tests from all modules at once launch emulator or plu
173173
```
174174

175175
When all goes fine, you should see testing report in `app/build/reports/androidTests/connected/` directory.
176-
![Instrumentation test report](https://raw.githubusercontent.com/frogermcs/MultiModuleGithubClient/master/docs/img/instrumentation_report_example.png "Instrumentation test report")
176+
![Instrumentation test report](docs/img/instrumentation_report_example.png "Instrumentation test report")
177177

178178
### Functional vs End-to-end testing
179179
From the high level, Android Instrumentation tests can be split into two types: functional and end-to-end. You can check my [article](https://medium.com/azimolabs/automated-testing-will-set-your-engineering-team-free-a89467c40731) about how we do QA at Azimo to see what is the difference between both of them.
@@ -195,3 +195,56 @@ It is, because `app` module doesn't have access to `RepositoryDetailsActivity` c
195195
What about end-to-end tests? They shouldn't be problematic, simply because tests shouldn't have knowledge about specific implementation, but rather how user interface is composed (so again, not: `withText("R.string.show_repos")` but `withText("Show repositories")`).
196196

197197
More cases: TBD
198+
199+
200+
## Proguard
201+
202+
Proguard configuration isn't very different in standard and multi-feature project configuration. Minification process is enabled in `app/build.gradle` [file](app/build.gradle):
203+
204+
```groovy
205+
buildTypes {
206+
debug {
207+
minifyEnabled true
208+
proguardFiles getDefaultProguardFile('proguard-android.txt'),
209+
'proguard-rules.pro'
210+
testProguardFile 'proguard-test-rules.pro'
211+
}
212+
//...
213+
}
214+
```
215+
216+
For proguard configuration and know-how we could create completely separate demo project and a bunch of articles. Instead, just take a look at screenshots that compare apk files built from this project, with and without minification enabled.
217+
218+
#### Project without proguard
219+
220+
![No proguard config](docs/img/no-proguard.png "No proguard config")
221+
222+
#### Project with proguard
223+
224+
![With proguard config](docs/img/with-proguard.png "With proguard config")
225+
226+
### Proguard config for project modules
227+
228+
It is also possible to Provide proguard configuration for each module separately. Why would you like to do this? Usually Proguard configuration is set in app's module gradle file. Also all global flags `-dontoptimize` also should be set there.
229+
But sometimes there are module-specific configurations. So for example you would like to keep methods or classes, even if they aren't used in app's module. Also when you share .aar library file, you can provide it with Proguard configuration built in.
230+
In this situation you should use `consumerProguardFiles`. For example, see `features/base/build.gradle` (file)[features/base/feature-base-proguard-rules.pro]:
231+
232+
```groovy
233+
buildTypes {
234+
all {
235+
consumerProguardFiles 'feature-base-proguard-rules.pro'
236+
}
237+
}
238+
```
239+
240+
Configuration tells:
241+
242+
```
243+
-keep class com.frogermcs.multimodulegithubclient.base.BaseActivity {
244+
public void notUsedMethod();
245+
}
246+
```
247+
248+
It means that method `notUsedMethod()` from class (BaseActivity)[features/base/src/main/java/com/frogermcs/multimodulegithubclient/base/BaseActivity.java] will be kept, no matter what.
249+
250+
For more details, take a look at [this blog post](https://proandroiddev.com/handling-proguard-as-library-developer-or-in-a-multi-module-android-application-2d738c37890) that describes how to setup Proguard for multi-module android app.

app/proguard-rules.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117

118118

119119
# === App UI ===
120+
120121
-keep class androidx.recyclerview.widget.RecyclerView {
121122
public <methods>;
122123
}

docs/img/no-proguard.png

174 KB
Loading

docs/img/with-proguard.png

114 KB
Loading

features/base/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ apply from: '../../buildsystem/android_commons.gradle'
55

66
android {
77
baseFeature true
8+
9+
buildTypes {
10+
all {
11+
consumerProguardFiles 'feature-base-proguard-rules.pro'
12+
}
13+
}
814
}
915

1016
dependencies {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# === Base module proguard configuration ===
2+
3+
-keep class com.frogermcs.multimodulegithubclient.base.BaseActivity {
4+
public void notUsedMethod();
5+
}
6+

features/base/src/main/java/com/frogermcs/multimodulegithubclient/base/BaseActivity.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,15 @@ public void setContentView(int layoutResID) {
2222
protected abstract void setupActivityComponent();
2323

2424
public abstract String getScreenName();
25+
26+
/*
27+
This method isn't used anywhere. But it won't disappear during minification process. It's
28+
because we use added proguard configuration for module telling that this method should be
29+
kept. See features/base/build.gradle -> consumerProguardFiles for more details.
30+
*/
31+
public void notUsedMethod() {
32+
int a = 1;
33+
int b = 3;
34+
int ab = a + b;
35+
}
2536
}

0 commit comments

Comments
 (0)