How to setup Android projects
Tags: android, kotlin, gradle, check
Published: 2019-05-23 11:55:54

---
title: How to setup Android projects
published: true
description: 
tags: android,kotlin,gradle,check
---

This post details installing check tools for Java and Kotlin, as well as obfuscation and gradle grgit script.

## checkstyle (Java)

- http://checkstyle.sourceforge.net/
- https://github.com/checkstyle/checkstyle

> Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard. It automates the process of checking Java code to spare humans of this boring (but important) task. This makes it ideal for projects that want to enforce a coding standard.

app/build.gradle

```groovy
apply plugin: 'checkstyle'

task checkstyle(type: Checkstyle) {
    description 'Check code standard'
    group 'verification'

    configFile file('$project.rootDir/tools/checkstyle.xml')
    source 'src'
    include '**/*.kt'
    exclude '**/gen/**'

    classpath = files()
    ignoreFailures = false
}
```

tools/chekcstyle

```xml
<?xml version="1.0"?><!DOCTYPE module PUBLIC
        "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
        "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<module name="Checker">
    <module name="FileTabCharacter"/>
    <module name="TreeWalker">

        <!-- Checks for Naming Conventions                            -->
        <!-- See http://checkstyle.sourceforge.net/config_naming.html -->
        <module name="MethodName"/>
        <module name="ConstantName"/>

        <!-- Checks for Imports                                 -->
        <!-- See http://checkstyle.sourceforge.net/config_imports.html-->
        <module name="AvoidStarImport"/>
        <module name="UnusedImports"/>

        <!-- Checks for Size                                          -->
        <!-- See http://checkstyle.sourceforge.net/config_sizes       -->
        <module name="ParameterNumber">
            <property name="max" value="6"/>
        </module>

        <!-- other rules ignored for brevity -->
    </module>
</module>
```

## findbugs (Java)

- http://findbugs.sourceforge.net/

> A program which uses static analysis to look for bugs in Java code

app/build.gradle

```groovy
apply plugin: 'findbugs'

task findbugs(type: FindBugs) {
    ignoreFailures = false
    effort = "max"
    reportLevel = "low"
    classes = files("$project.buildDir/intermediates/javac")

    excludeFilter = file("$rootProject.rootDir/tools/findbugs-exclude.xml")

    source = fileTree('src/main/java/')
    classpath = files()

    reports {
        xml.enabled = false
        html.enabled = true
        html.destination file("$project.buildDir/outputs/findbugs/findbugs-output.html")
    }
}
```

tools/findbugs-exclude.xml

```xml
<FindBugsFilter>
    <!-- Do not check auto-generated resources classes -->
    <Match>
        <Class name="~.*R\$.*"/>
    </Match>
 
    <!-- Do not check auto-generated manifest classes -->
    <Match>
        <Class name="~.*Manifest\$.*"/>
    </Match>
 
    <!-- Do not check auto-generated classes (Dagger puts $ into class names) -->
    <Match>
        <Class name="~.*Dagger*.*"/>
    </Match>
     
    <!-- http://findbugs.sourceforge.net/bugDescriptions.html#ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD-->
     <Match>
        <Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" />
    </Match>
</FindBugsFilter>
```

## pmd (Java)

- https://github.com/pmd/pmd

> PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth

app/build.gradle

```groovy
apply plugin: 'pmd'

task pmd(type: Pmd) {
    ruleSetFiles = files("${project.rootDir}/tools/pmd-rules.xml")
    ignoreFailures = false
    ruleSets = []

    source 'src'
    include '**/*.kt'
    exclude '**/gen/**'

    reports {
        xml.enabled = false
        html.enabled = true
        html.destination = file("$project.buildDir/outputs/pmd/pmd.html")
    }
}
```

tools/pmd-rules.xml

```xml
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
	<exclude-pattern>.*/R.java</exclude-pattern>
    <exclude-pattern>.*/gen/.*</exclude-pattern>

    <rule ref="rulesets/java/basic.xml" />

    <rule ref="rulesets/java/braces.xml" />

    <rule ref="rulesets/java/strings.xml" />

    <rule ref="rulesets/java/design.xml" >
        <exclude name="AvoidDeeplyNestedIfStmts"/>
    </rule>

    <rule ref="rulesets/java/unusedcode.xml" />

</ruleset>
```

## lint

app/build.gradle

```groovy
android {
  lintOptions {
        lintConfig file("$project.rootDir/tools/lint-rules.xml")
        htmlOutput file("$project.buildDir/outputs/lint/lint.html")
        warningsAsErrors true
        xmlReport false
        htmlReport true
        abortOnError false
    }
}
```

tools/lint-rules.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>

<lint>
    <issue id="GoogleAppIndexWarning" severity="ignore" />

    <issue id="InvalidPackage" severity="error">
        <ignore regexp="okio.*jar" />
        <ignore regexp="retrofit.*jar" />
    </issue>

    <!-- Disable the given check in this project -->
    <issue id="IconMissingDensityFolder" severity="ignore" />
 
    <!-- Change the severity of hardcoded strings to "error" -->
    <issue id="HardcodedText" severity="error" />
</lint>
```

## Strict mode

- https://developer.android.com/reference/android/os/StrictMode

```kotlin
import android.app.Application
import android.os.StrictMode

class App: Application() {
    override fun onCreate() {
        super.onCreate()

        enableStrictMode()
    }

    private fun enableStrictMode() {
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectAll()
                    .penaltyLog()
                    .build()
            )

            StrictMode.setVmPolicy(
                StrictMode.VmPolicy.Builder()
                    .detectAll()
                    .penaltyLog()
                    .build()
            )
        }
    }
}
```

## Version code

tools/grgit.gradle

```groovy
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.ajoberstar:grgit:1.5.0'
    }
}

import org.ajoberstar.grgit.Grgit

ext {
    git = Grgit.open(currentDir: projectDir)
    gitCommitCount = git.log().size()
}

task printVersion() {
    println("Commit count: $gitCommitCount")
}
```

app/build.gradle

```groovy
android {
    defaultConfig {
        versionCode gitCommitCount
    }
}
```

## Obfuscation

- https://developer.android.com/studio/build/shrink-code

> To make your app as small as possible, you should enable shrinking in your release build to remove unused code and resources. When enabling shrinking, you also benefit from obfuscation, which shortens the names of your app’s classes and members, and optimization, which applies more aggressive strategies to further reduce the size of your app

> When you use Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher, R8 is the default compiler that converts your project’s Java bytecode into the DEX format that runs on the Android platform

app/build.gradle

```groovy
android {
  buildTypes {
        debug {
            signingConfig signingConfigs.debug
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), '$project.rootDir/tools/proguard-rules-debug.pro'
        }

        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), '$project.rootDir/tools/proguard-rules.pro'
        }
    }
}
```

tools/proguard-rules.pro

```
-ignorewarnings

# Remove logs
-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(java.lang.String, int);
    public static int v(...);
    public static int i(...);
    public static int w(...);
    public static int d(...);
    public static int e(...);
}
```

tools/proguard-rules-debug.pro

```
-ignorewarnings
-dontobfuscate
-dontoptimize
-ignorewarnings
```

More proguard snippets https://github.com/krschultz/android-proguard-snippets

## quality

tools/quality.gradle

```groovy
task findbugs
task pmd
task checkstyle
```

app/build.gradle

```groovy
apply from: "$project.rootDir/tools/quality.gradle"
```

## File format

- https://twitter.com/kotlin/status/1067825173196414976?lang=en

> You don't need to use ktlint or detekt to ensure that your code is formatted consistently. Simply enable "File is not formatted according to project settings" in the inspection settings.

## ktlint (Kotlin)

- https://github.com/pinterest/ktlint

> An anti-bikeshedding Kotlin linter with built-in formatter

app/build.gradle

```groovy
apply from: "$project.rootDir/tools/ktlint.gradle"
```

tools/ktlint.gradle

```groovy
repositories {
    jcenter()
}

configurations {
    ktlint
}

dependencies {
    ktlint "com.pinterest:ktlint:0.32.0"
    // additional 3rd party ruleset(s) can be specified here
    // just add them to the classpath (e.g. ktlint 'groupId:artifactId:version') and
    // ktlint will pick them up
}

task ktlint(type: JavaExec, group: "verification") {
    description = "Check Kotlin code style."
    classpath = configurations.ktlint
    main = "com.pinterest.ktlint.Main"
    args "src/**/*.kt", "--reporter=checkstyle, output=${buildDir}/outputs/ktlint.xml"
}


task ktlintFormat(type: JavaExec, group: "formatting") {
    description = "Fix Kotlin code style deviations."
    classpath = configurations.ktlint
    main = "com.pinterest.ktlint.Main"
    args "-F", "src/**/*.kt"
}
```

.editorconfig

```
[*.{kt,kts}]
indent_size=4
```

## detekt (Kotlin)

- https://github.com/arturbosch/detekt

> Static code analysis for Kotlin

build.gradle

```groovy
buildscript {}

plugins {
    id "io.gitlab.arturbosch.detekt" version "1.0.0-RC14"
}

allprojects {}
```

tools/detekt.gradle

```groovy
detekt {
    toolVersion = "1.0.0-RC14"
    input = files("src/main")
    filters = ".*/resources/.*,.*/build/.*"
    baseline = file("${project.rootDir}/tools/detekt-baseline.xml")
    config = files(file("$project.rootDir/tools/detekt.yml"))
}
```

tools/detekt.xml 

- https://github.com/arturbosch/detekt/blob/master/docs/pages/baseline.md

> The intention of a whitelist is that only new code smells are printed on further analysis. The blacklist can be used to write down false positive detections (instead of suppressing them and polute your code base).

```xml
<SmellBaseline>
    <Blacklist>
        <ID>CatchRuntimeException:Junk.kt$e: RuntimeException</ID>
    </Blacklist>
    <Whitelist>
        <ID>NestedBlockDepth:Indentation.kt$Indentation$override fun procedure(node: ASTNode)</ID>
        <ID>TooManyFunctions:LargeClass.kt$io.gitlab.arturbosch.detekt.rules.complexity.LargeClass.kt</ID>
        <ID>ComplexMethod:DetektExtension.kt$DetektExtension$fun convertToArguments(): MutableList&lt;String&gt;</ID>
    </Whitelist>
</SmellBaseline>
```

tools/detekt.yml 

- https://github.com/arturbosch/detekt/blob/master/detekt-cli/src/main/resources/default-detekt-config.yml
- https://arturbosch.github.io/detekt/configurations.html

> detekt uses a yaml style configuration file for various things:

```yaml
autoCorrect: true

build:
  maxIssues: 10
  weights:
    # complexity: 2
    # LongParameterList: 1
    # style: 1
    # comments: 1
```

Run

```
./gradlew detekt
```

## check

app/build.gradle

```groovy
check.dependsOn 'checkstyle', 'findbugs', 'pmd', 'lint', 'ktlint', 'detekt'
```

Run

```
./gradlew check
```

## Reference

- [Configuring Android Project — Little Things That Matter](https://proandroiddev.com/configuring-android-project-little-things-that-matter-d6a9d34c1ce0)
- [Ensure High-Quality Android Code With Static Analysis Tools](https://code.tutsplus.com/tutorials/ensure-high-quality-android-code-with-static-analysis-tools--cms-28787)
- [Kotlin Static Analysis — why and how?](https://proandroiddev.com/kotlin-static-analysis-why-and-how-a12042e34a98)

Original post https://github.com/onmyway133/blog/issues/257