Como criar suas próprias bibliotecas
Bibliotecas estão presentes na vida do desenvolvedor de várias formas: organizar código, poupar escrita, testes, clients HTTP… e por ai vai! Uma prática muito comum é reutilizarmos o nosso código de projetos antigos em projetos novos.
E quem nunca deu aquele Ctrl + C e Ctrl +V? ¯\_(ツ)_/¯
O problema de copiar o código de projetos antigos é que, na maioria das vezes, acabamos criando algo novo, ou até mesmo corrigindo um bug, e esquecemos que precisamos realizar a manutenção dos nossos códigos antigos.
Uma boa prática é abstrairmos esse código da aplicação. Criando uma biblioteca!
Primeiros passos
Vamos criar uma lib (abreviação de ‘library’) bem simples que apenas exibe informações no LogCat — Sim, eu sei que essa lib é inútil, mas vamos nos focar no conceito e deixar a sua aplicação (ou utilidade) de lado por enquanto.
Todo o código fonte usado nesse tutorial está disponível aqui.
Antes de tudo, crie um módulo novo e selecione a opção Android Library.
Até esse ponto, a criação de uma lib não é muito diferente de um app, mas uma observação importante é com o Module name: ela estará no compile do gradle.
Agora que já criamos o nosso módulo, podemos trabalhar em cima dele para desenvolvermos nossa lib.
A estrutura é a mesma de uma aplicação android, com androidTest para UI, se existirem, main, onde escreveremos a nossa lib e test, onde podem ser feitos os testes unitários.
Quando eu digo que a estrutura é a mesma, não é brincadeira:
~/git/Logger/logger/build/outputs/aar/logger-release.aar
├── AndroidManifest.xml
├── R.txt
├── aidl
├── assets
├── classes.jar
├── jni
├── libs
└── res
└── values
└── values.xml
Vale lembrar que todas as permissões, activities, services etc declaradas no AndroidManifest serão colocadas junto às das aplicações que estarão usando sua lib, graças ao Manifest Merge. Como o foco do artigo não é falar sobre a estrutura seguida nos arquivos .aar, não vamos nos aprofundar no assunto. Mas podemos encontrar mais informações aqui.
Logger
Como exemplo, nossa classe de log será algo bem simples:
Por enquanto, vamos referenciar a lib direto no app/build.gradle
Agora podemos fazer a chamada dentro da nossa aplicação:
Distribuição
Sem dúvidas esse é um dos pontos mais importantes (de qualquer projeto) e muito pouco pensado no desenvolvimento. Talvez para nós, devs android, seja uma coisa bem óbvia, a Google Play. Mas se tratando de uma biblioteca, nós podemos fazer a distribuição de N formas: disponibilizar o .aar publicamente, apenas o .jar, maven etc
Para esse exemplo, vamos usar uma ferramenta de distribuição chamada JFrog. Nela nós podemos fazer upload de várias ferramentas, SDKs, bibliotecas e mais com npm, nuget, maven, docker e gradle!
Como esse projeto é open source, podemos fazer o upload com a conta free.
Por default, a ferramenta já nos disponibiliza um repositório maven (para onde enviaremos a biblioteca).
Todo compile do gradle possui uma regra na sua estrutura, como essa:
Precisamos adicionar os plugins para deploy:
Vamos no logger/build.gradle e adicionar os plugins também:
Mapeamos os repositórios git…
Estamos quase lá! Para finalizarmos, precisamos da nossa apikey do Bintray. Podemos obtê-la facilmente acessando as configurações da conta no próprio site da Bintray e copiar na aba 'API KEY'. Após obter a sua chave, coloque-a no arquivo local.properties…
Gradle sincronizado com sucesso? Então estamos prontos para publicar!
Agora só será necessário rodar o comando no terminal
./gradlew bintrayUpload// gradle compilando aquiBUILD SUCCESSFUL
BUILD SUCCESSFUL
Mas Jão, BUILD SUCCESSFUL? Só isso? Então tá no ar??
— Aham!
Para finalizar, vamos remover a referência local que temos da lib na aplicação e apontar para a que está no JFrog.
/build.gradle
E no app/build.gradle
Sync now e está feito!
Extra
Quando desenvolvemos uma biblioteca, temos que ter alguns pontos em mente:
- USE e ABUSE de annotations — Annotations ajudam o desenvolvedor em tempo de edição e criação de algo mais concreto, com @NonNull e @Deprecated, por exemplo.
- Não quebre as interfaces! — É de extrema importância respeitarmos as interfaces que o cliente está utilizando com nossa biblioteca, então evite coisas como: alterações de parâmetros, métodos que retornam objetos diferentes após updates etc.
- Utilize a menor quantidade de dependências possíveis! — Isso influencia e muito na aplicação do seu cliente e no DEX.
Conclusão
Vimos como uma simples prática pode melhorar e muito a qualidade da distribuição, escalabilidade e manutenção do nosso código.
Caso você tenha alguma dúvida sobre o assunto, sugestão ou queira falar sobre, sinta-se livre para falar comigo no twitter que eu to sempre por lá!
May the force be with you — Yoda