Integrando Ferramentas de Análise de Código no Android — Parte II: FindBugs

Padrão

Depois de um hiato um pouco maior que o esperado, estamos de volta com a nossa série sobre ferramentas de análise de código no Android. Conforme antecipado no post anterior, desta vez vamos falar sobre o FindBugs.

Atualmente em sua versão 3.0.1, o FindBugs é uma ferramenta de análise que se concentra em bugs comumente encontrados em códigos Java, além de buscar por potenciais problemas de segurança. A partir da análise, ele pode gerar relatórios em diversos formatos, inclusive HTML, que podem posteriormente ser publicados em um servidor de CI.

A integração da ferramenta ocorre de forma bastante semelhante ao CheckStyle, já que o Gradle também possui nativamente um plugin para o FindBugs.

O primeiro passo é aplicarmos o plugin ao nosso arquivo build.gradle:

apply plugin: 'findbugs'

Assim como fizemos com o CheckStyle, podemos adicionar a task do FindBugs a nossa task check.

check.dependsOn 'checkstyle', 'findbugs'

Feito isso, vamos então criar a nossa task. Como o FindBugs também verifica os arquivos .class, precisamos fazer com que essa task dependa de uma outra task de build. Neste exemplo, coloquei a task assembleDebug.

task findbugs(type: FindBugs, dependsOn: assembleDebug) {
    ignoreFailures = false
    effort = 'max'
    reportLevel = 'high'
    excludeFilter = new File("${project.rootDir}/config/findbugs-filter.xml")
    classes = files("${project.rootDir}/app/build/intermediates/classes")

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

    reports {
        xml.enabled = false
        html.enabled = true
        html {
            destination "$project.buildDir/reports/findbugs/findbugs.html"
        }
    }

    classpath = files()
}

No caso do FindBugs, primeiro configuramos para que o processo de build seja interrompido caso alguma ocorrência seja encontrada. Em seguida, configuramos os níveis de esforço e report, as classes que devem ser ignoradas (já veremos como é este arquivo) e o diretório onde estão as classes a serem analisadas. Configuramos o atributo source, adicionamos todos os arquivos java que forem encontrados e ignoramos quaisquer arquivos que estejam na pasta gen (o que geralmente não ocorre em projetos Gradle — essa propriedade faz mais sentido em builds Ant feitas pelo Eclipse).

O arquivo de filtro (findbugs-filter.xml) diz quais classes devem ser ignoradas no processo. Para este exemplo, utilizei um arquivo assim:

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
    <Match>
        <Class name="~.*\.R\$.*" />
    </Match>
    <Match>
        <Class name="~.*\.Manifest\$.*" />
    </Match>
    <!-- Todas as classes de teste, exceto bugs específicos do JUnit -->
    <Match>
        <Class name="~.*\.*Test" />
        <Not>
            <Bug code="IJU" />
        </Not>
    </Match>
</FindBugsFilter>

Nesse arquivo, ignoramos a classe R, classes de Manifest e ignoramos bugs referentes ao JUnit nas classes de teste.

Por fim, configuramos a geração do relatório HTML e o classpath.

E pronto! Ao executarmos a task findbugs ou mesmo a task check (já que criamos esta dependência), teremos a execução da ferramenta sobre a nossa base de código. Mas, o que pode dar errado no código? Imagine o seguinte:

public class Client implements Parcelable {
  
  public static TABLE_NAME = "clients";
  
  ...
}

Tenho uma classe de modelo na qual, para organizar melhor meu projeto, coloquei um atributo estático com o nome da tabela do SQLite que armazena objetos desse tipo. Tudo certo, não?

findbugs-report

AHN??? Como assim?

Vamos ver o que o FindBugs tem a dizer sobre isso:

net.rafaeltoledo.sample.Client.TABLE_NAME isn’t final but should be

E ele ainda nos dá mais alguns detalhes sobre o motivo disso ser ruim:

MS_SHOULD_BE_FINAL: Field isn’t final but should be

This static field public but not final, and could be changed by malicious code or by accident from another package. The field could be made final to avoid this vulnerability.

Ahhh, sim! Me esqueci do modificador final, já que esse cara é uma constante! Ufa! 😀

O FindBugs possui uma lista vasta de verificações, e pode ser um grande aliado para fazer com que nosso código seja mais eficiente e mais seguro!

Então é isso, pessoal! No próximo post vamos conhecer o atirador de elite do nosso grupo, o PMD!

Até lá!

Integrando Ferramentas de Análise de Código no Android — Parte I: Checkstyle

Padrão

Sempre que começamos a escrever código, por mais simples ou complexo que seja, sempre existe a preocupação com a qualidade. Quando trabalhamos em equipe, essa preocupação se torna ainda mais presente, pois são várias pessoas produzindo código, cada uma ao seu estilo.

Para melhorar um pouco esse cenário já conhecido, temos ferramentas que nos auxiliam a manter o código em um nível adequado de qualidade, em diversos aspectos. Nesta série que começamos hoje, vamos conhecer ferramentas que podem nos auxiliar a manter nosso código Android mais adequado.

Começando, vamos conhecer o Checkstyle. Conforme citado anteriormente, principalmente quando trabalhamos em um projeto com mais de uma pessoa, o código tende a adquirir traços da “personalidade” de cada um, seja através de indentação com tabs / espaços, posicionamento da chave, e até nomenclatura de classes e atributos. O Checkstyle tem por objetivo auxiliar a manter um padrão de código por todo o projeto, apontando trechos que estejam fugindo do padrão configurado.

O mais interessante, nesse caso, é que o Gradle, o nosso querido build system do Android, já possui o Checkstyle integrado ao projeto, necessitando apenas uma pequena configuração para que ele seja executado.

Bom, para começarmos, primeiramente precisamos aplicar o plugin doCheckstyle no nosso arquivo build.gradle.

apply plugin: 'checkstyle'

Uma prática que geralmente adoto nessa configuração, é adicionar o Checkstyle a task check do Gradle. Assim, além das demais verificações que já possuímos (como a execução do Lint), teremos também o Checkstylerodando.

check.dependsOn 'checkstyle'

Feito isso, vamos configurar a execução dessa task em nosso projeto.

task checkstyle(type: Checkstyle) {
    configFile file("$project.rootDir/config/checkstyle/checkstyle.xml")
    source 'src'
    include '**/*.java'
    classpath = files()
}

Nessa configuração, temos primeiramente a propriedade configFile que recebe o arquivo checkstyle.xml que é quem define o estilo do nosso projeto (já já veremos como esse arquivo é). Posteriormente, configuramos para que a execução seja feita sobre a nossa pasta source, incluindo todos os arquivos .java, e concluímos com a configuração do classpath, exigida pelo plugin. Vamos conhecer então o arquivo checkstyle.xml.

Esse arquivo é que conterá as regras a serem validadas pelo CheckStyle. Para esse primeiro exemplo, vamos adicionar apenas uma, que validará se não existem espaços entre os símbolos < e > na declaração de generics.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">

    <module name="TreeWalker">
        <module name="GenericWhitespace" />
    </module>

</module>

Existe uma infinidade de regras que podem ser adicionadas ao arquivo. Todas elas podem ser encontradas na documentação oficial, e podem ser aplicadas de acordo com o estilo a ser utilizado em seu projeto.

Para validar que a regra está funcionando, podemos criar uma classe simples, que viole a regra de estilo especificada:

package net.rafaeltoledo.codequality;

import android.support.v7.app.AppCompatActivity;
import java.util.List;

public class MyActivity extends AppCompatActivity {

    List< String > myList;
}

Executando a task checkstyle através do Gradle (pela linha de comando ou pelo menu Gradle, geralmente localizado na barra direita do Android Studio), teremos uma mensagem ao final da execução:

Executing external task ‘checkstyle’…
Parallel execution is an incubating feature.
[ant:checkstyle] [...]MyActivity.java:9:10: ‘<’ é seguido de espaço em branco. [ant:checkstyle] [...]MyActivity.java:9:17: ‘>’ é precedido por espaço em branco.

:app:checkstyle FAILED

FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ‘:app:checkstyle’.
> Checkstyle rule violations were found. See the report at: file:///[...]/app/build/reports/checkstyle/checkstyle.xml

* Try:
Run with — stacktrace option to get the stack trace. Run with — info or — debug option to get more log output.

BUILD FAILED

Total time: 1.803 secs

Além de reportar os problemas no console, ele ainda gera um relatório XML com todas as violações das regras!

Corrigindo o nosso código para:

List<String> myList;

Temos uma execução tranquila e sem erros 🙂

Executing external task ‘checkstyle’…
Parallel execution is an incubating feature.
:app:checkstyle

BUILD SUCCESSFUL

Total time: 2.622 secs

E é isso! No próximo post vamos conhecer a FindBugs, que pode nos salvar de bugs clássicos e problemas de segurança no nosso código 😀

Até lá!

Desenvolvendo para Android com Kotlin: Como Começar?

Padrão

Olá pessoal!

Acredito que alguns de vocês já tenham ouvido falar no Kotlin. Pra quem não conhece, o Kotlin é uma linguagem que vem sendo desenvolvida pela Jetbrains (a empresa responsável pelo Android Studio, IntelliJ IDEA e uma porção de IDEs muito boas), focada na JVM, Android e web. A princípio, ela pode ser vista como um Java menos (muito) verboso. Por alguns, ela é chamada o Swift do Android! 🙂

Apesar de ainda estar em desenvolvimento, já é possível criar aplicativos completos utilizando essa linguagem, e é exatamente esse o propósito desse post: mostrar como configurar a sua IDE e criar o primeiro projeto usando Kotlin.

Bom, o primeiro passo é instalar os plugins do Kotlin no seu Android Studio ou IntelliJ. Para isso, abra as configurações da IDE e localize a opção Plugins. Ali, clique em Install JetBrains plugin… e localize os plugins Kotlin e Kotlin Extensions for Android.

Kotlin PluginsFeito isso, basta reiniciar a sua IDE para que a instalação esteja completa.

Com isso, já podemos criar o nosso projeto Android. A criação em nada difere de um projeto comum. Como ainda não temos um template, no início, temos que converter as classes manualmente. O que difere aqui são os arquivos de configuração do Gradle, que terão os plugins do Kotlin adicionados:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.12.1230'
        classpath 'org.jetbrains.kotlin:kotlin-android-extensions:0.12.1230'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

Aqui, adicionamos ao classpah os plugins do Kotlin (kotlin-gradle-plugin e kotlin-android-extensions – que não será utilizado ainda nesse primeiro tutorial).

No build.gradle do projeto, aplicamos o plugin e adicionamos a biblioteca padrão do kotlin:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.1'

    defaultConfig {
        applicationId 'net.rafaeltoledo.hellokotlin'
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName '1.0'
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'org.jetbrains.kotlin:kotlin-stdlib:0.12.1230'
}

Caso tenha escolhido para que o Android Studio gere a primeira Activity, você pode convertê-la para Kotlin indo até o menu Code -> Convert Java File to Kotlin File. Aquela sua Activity marota em Java vai virar algo mais ou menos assim:

package net.rafaeltoledo.hellokotlin.activity

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import net.rafaeltoledo.hellokotlin.R

public class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main)
    }
}

Agora é só executar e é só alegria. Até a versão 0.11, era necessária uma pasta de sources específica para o Kotlin, mas com a 0.12+, já não é necessário (perceba que os arquivos .kt ficam na pasta java de sources).

É isso pessoal! Aguardem que logo logo eu trago mais novidades!

Gerenciando suas Chaves no Android de forma Eficiente

Padrão

Olá pessoal! Depois de um bom tempo sumido, estou de volta para falar de gerenciamento de chaves de assinatura no Android.

Beleza, você já desenvolveu seu aplicativo matador, que vai te gerar milhões em 2 dias, e agora vai gerar a sua build de release para publicar no Google Play. Nesse caso, precisamos criar a nossa assinatura de release no arquivo build.gradle do nosso projeto. Alguma coisa mais ou menos assim:

signingConfigs {
    release {
        storeFile file('/home/rafael/minha_key.jks')
        storePassword 'senha secreta'
        keyAlias 'app_android'
        keyPassword 'senha mais secreta ainda'
    }
}

Mas… tem alguma coisa errada aí. Principalmente se estamos utilizando algum controle de versão, como o Git ou SVN, não é uma boa prática enviarmos dados sensíveis para eles (como senhas, keystores e coisas do tipo). Durante algum tempo, a saída utilizada por mim foi adicionar esses dados ao arquivo gradle.properties na raiz do projeto, e não enviá-lo para o controle de versão.

STORE_FILE=/home/rafael/minha_key.jks
STORE_PASSWORD=senha secreta
KEY_ALIAS=app_android
KEY_PASSWORD=senha mais secreta ainda

Dessa forma, a nossa configuração de assinatura ficaria algo assim:

signingConfigs {
    release {
        storeFile file(STORE_FILE)
        storePassword STORE_PASSWORD
        keyAlias KEY_ALIAS
        keyPassword KEY_PASSWORD
    }
}

Funciona bem, não temos dados sensíveis no nosso controle de versão mas… temos basicamente dois problemas principais nessa abordagem:

  • No clone do projeto, você terá um erro de build. Ou seja, se entrou alguém na equipe e clonar o projeto, baterá com a cara na porta logo de cara. Isso já vai atrasar um pouco o join no projeto. Esse problema também se aplica quando o código está em um servidor de CI (Jenkins, Travis, CircleCI, etc.)
  • Tem o agravante humano, ou seja, sempre há o risco de, sem querer, você enviar o arquivo original por algum motivo. Obviamente que você pode adicionar este arquivo no .gitignore ou equivalente no SVN, mas nesse caso caímos no primeiro cenário problemático.

Então… qual a saída?

Depois de pensar um pouco, acabei encontrando, hoje, a melhor saída com o uso de variáveis de ambiente! Como assim?

Vamos lá: o primeiro passo é criarmos uma assinatura default para o projeto. No meu caso, eu simplesmente copio a debug.keystore (que fica dentro da pasta .android do  usuário) e coloco, por exemplo, dentro de um diretório chamado distribution na raiz do meu projeto. Essa chave vai garantir que a build não vai quebrar, por exemplo, quando alguém clonar o projeto ou em um servidor de CI, num primeiro momento.

Agora, na configuração da minha assinatura, podemos fazer algo do tipo:

signingConfigs {
    release {
        storeFile file(System.getenv('STORE_FILE') != null ? System.getenv('STORE_FILE') : '../distribution/debug.keystore')
        storePassword System.getenv('STORE_PASSWORD') != null ? System.getenv('STORE_PASSWORD') : 'android'
        keyAlias System.getenv('KEY_ALIAS') != null ? System.getenv('KEY_ALIAS') : 'androiddebug'
        keyPassword System.getenv('KEY_PASSWORD') != null ? System.getenv('KEY_PASSWORD') : 'android'
    }
}

Nota: caso seu servidor de CI esteja gerando builds de release, você pode setar as variáveis de ambiente nele também para gerar builds assinadas corretamente.

E pronto! Agora, para gerar a build corretamente, você pode exportar as variáveis de ambiente ou, como eu faço, colocar os dados da chave no comando apenas na hora de gerar a build de release:

$ STORE_FILE='/home/rafael/minha_key.jks' STORE_PASSWORD='senha secreta' KEY_ALIAS='app_android' KEY_PASSWORD='senha mais secreta ainda' ./gradlew clean assembleRelease

 E é isso! Espero que a dica seja útil para vocês e, caso tenham sugestões, podem postar aí nos comentários!

Até a próxima! 😀

Como aprender Android (ou qualquer coisa) de verdade

Padrão

Essa semana eu estava conversando com o João Gouveia e o Halyson Gonçalves, dois ótimos desenvolvedores Android que trabalham conosco aqui na Concrete Solutions, sobre um problema que já me incomodava há algum tempo, mas que estava hibernando, só esperando a faísca de uma boa conversa para acordar:

Será que os desenvolvedores não estão se apoiando demais em bibliotecas e frameworks? Será que estamos virando apenas bons usuários de bibliotecas?

Essa pergunta virou uma pulga que ficou ali atrás da orelha desde então.

Comecei a brincar com o Android no final de 2010. Até então, minha experiência tendia muito mais para C++ do que para Java propriamente dito. Essa diferença de conhecimento me fez estudar muito mais a fundo a própria linguagem Java que, naquela época, fazia Android brilhar aos olhos por não ter as limitações que o JavaME, por exemplo, impunha. Mas vamos deixar de lado essa história por enquanto.

O que tenho visto em muitos desenvolvedores, principalmente naqueles que começaram a programar para Android nos últimos dois anos, é que eles não sabem ao certo como as coisas funcionam no Android. Muitos deles se agarraram às facilidades de uma biblioteca X ou Y, e sequer sabem o que acontece por baixo dos panos (ou under the hood, que funciona muito melhor para essa analogia).

Como funciona o ciclo de vida de uma Activity? Como você controla o estado dos seus campos em uma mudança de configuração, por exemplo? “Ah, eu só anoto a variável com a biblioteca Z”. Como você faz uma requisição a um servidor? “Ah, o Retrofit resolve pra mim”. Mas e a mudança de contexto para publicar o resultado na thread de UI? “Ah, não sei, o Callback já faz isso pra mim”.

Uma dica que dou pra vocês que estão começando (ou nem tão começando assim) é: façam um projeto sem biblioteca alguma. Ok, a Support Library & cia. vale, mas entendam como o Android funciona. Como consumir um REST sem o Retrofit? Como fazer parse de um JSON sem o GSON ou Jackson? Você sabe o que é um Content Provider e como criar um? Testem, estudem, experimentem. Não tenho dúvidas de que aquela nuvem cinza que aparece na sua cabeça quando algum framework mágico surge vai começar a dissipar.

Android-LearningConheçam o terreno onde estão pisando! Não importa o que estejam aprendendo, evitem os atalhos. Não que eles sejam ruins, mas, principalmente no momento de aprendizado, precisamos de bases sólidas, de conhecimento sobre o básico. Conhecimento esse que será sua especialidade futuramente. “Por fora bela viola, por dentro pão bolorento”.

Concordam, discordam ou têm alguma opinião sobre o assunto? Aproveite os campos abaixo!

Originalmente publicado no Blog da Concrete Solutions.

Quer trabalhar com Mobile na Concrete Solutions?

Padrão

Olá pessoal da Internet!

Como alguns de vocês já devem saber (ou ter percebido), atualmente estou trabalhando na Concrete Solutions, em São Paulo. Ela é uma empresa de produtos digitais muito bacana, com grande expertise em mobile / web, com práticas ágeis e muitas outras coisas legais.

E se você, meu leitor de cada dia que frequenta o meu blog mesmo sem muito conteúdo novo (desculpem…), já pensou em trabalhar lá também? Atualmente a Concrete está com muitas vagas abertas, em diferentes áreas, e para diferentes níveis!

Nossa, Rafael!!!! Mas como eu faço pra me candidatar a uma vaga nessa empresa ultra-mega-boga-bacana?????

Calma meu amigo leitor!!! Parece difícil, mas não é! Primeiramente, você vai bolar um currículo (pode ser basicão mesmo), colocando sua formação e experiências. Nada muito complexo não. Depois disso, você pode entrar lá na seção de Vagas do site da Concrete (ou pode me enviar um e-mail maroto – tem lá na página Sobre). Após isso, você vai mostrar seus conhecimentos ultra-mega-boga-incríveis através do Desafio Concrete! Apesar do nome intimidador, é simplesmente um projeto bem tranquilo que exige alguns conhecimentos básicos. É mais pra gente saber do que você é capaz, para depois batermos um papo 🙂

Os desafios que temos atualmente para mobile são Android, iOS e Windows Phone. Temos também vagas para o time web, para Java, .NET, Frontend, além de outras! Só dar uma olhada lá no link de vagas do site da Concrete. Ah é, e tem vagas pra você que é do Rio de Janeiro também!

Então corre lá e manda ver! Quem sabe a gente ainda não trabalha juntos qualquer dia desses?