Criação de uma biblioteca no-op Android para ferramentas de depuração
Conteudo
O que é um ambiente autônomo?
“No op” é a abreviatura de “no operation”.
É uma instrução comum em linguagem assembly e significa uma operação de computação que não tem efeito significativo. Por exemplo, uma função que não contém código:
// Performs an operation fun setTimestamp(timestamp: String) { this.timestamp = timestamp } // Does nothing fun setTimestamp(timestamp: String) { // no-op }
Nesse caso, uma “biblioteca não operacional” é uma biblioteca da qual um aplicativo depende, mas na realidade não tem efeito.
Por que queremos uma biblioteca sem operação?
Durante o desenvolvimento do aplicativo, você pode usar ferramentas de depuração que aumentam a eficiência ao fazer alterações. No entanto, muitas vezes você não quer colocar ferramentas de depuração nas mãos dos usuários finais. Isto é porque:
- Isso exporia um nível de controle sobre o aplicativo, em produção, que não é seguro ou sensato
- Isso aumentaria desnecessariamente o tamanho do arquivo APK
Um bom exemplo de uma biblioteca como esta é Stetho. É uma ferramenta de depuração poderosa que não possui uma versão autônoma prontamente disponível.
Então, se quiséssemos, poderíamos incluir a biblioteca acima em compilações ao vivo e simplesmente desativá-la (via BuildConfig.FLAVOUR) ou criar uma classe “DebugApplication”.
No entanto, nenhuma dessas soluções é preferível. O primeiro adiciona lógica e não remove a implementação da biblioteca original. O último remove a implementação da biblioteca original, mas adiciona uma nova classe que estende sua classe de aplicativo normal.
Então, como podemos criar um?
- Em primeiro lugar, adicionamos um novo módulo no Android Studio (versão 3.6.2 para mim) por meio de Arquivo -> Novo -> Novo Módulo
- Em seguida, adicionamos uma nova biblioteca Android que conterá nossa versão no-op:
“Nome do aplicativo/biblioteca” e “Nome do módulo” podem ser o que você quiser (dentro do razoável, é claro), mas é importante que o campo “Nome do pacote” seja exatamente o mesmo que a biblioteca original que você está usando. Também definimos o idioma e os valores mínimos do SDK para corresponder ao que a biblioteca original usa. Neste caso, é Java e API 18.
É importante que o campo “Nome do pacote” seja exatamente igual à biblioteca original que você está usando.
Depois de terminar a caixa de diálogo acima, será exibida uma opção para gerar alguns arquivos. Você pode fazer o que quiser aqui, mas garantimos que a estrutura do arquivo do projeto foi configurada da seguinte maneira:
Aqui, o arquivo Android Manifest é apenas uma única linha:
<manifest package="com.facebook.stetho.stetho" />
E podemos reduzir o arquivo de compilação gerado automaticamente:
apply plugin: 'com.android.library' android { compileSdkVersion <my compile SDK version> defaultConfig { minSdkVersion <my min SDK version> targetSdkVersion <my target SDK version> versionCode 1 versionName '1.5.1' <this can be whatever you want, here it matches the version code from the genuine library> } }
Em seguida, criamos nossa própria versão do arquivo Stetho.java, com nossa implementação no-op de todos os métodos publicamente acessíveis da superfície da API da biblioteca genuína (neste caso, apenas um!):
package com.facebook.stetho; import android.content.Context; public class Stetho { public static void initializeWithDefaults(Context context) { // no op } }
Portanto, criamos um arquivo Java em nossa biblioteca personalizada com a mesma estrutura do original, com uma classe com o mesmo nome e o método estático que desejamos, com a mesma assinatura. Agora, se mudássemos para um tipo ao vivo, o IDE nos mostraria que há um erro – não podemos resolver o Stetho.
Portanto, precisamos informar ao Gradle (o Android Studio pode sugerir automaticamente essa alteração) qual versão da biblioteca “Stetho” usar, dependendo do tipo de compilação:
repositories { ... } android { ... } dependencies { ... debugImplementation "com.facebook.stetho.stetho:<version>" liveImplementation project(':stetho-no-op') ... }
Aqui, debugImplementation informa ao Gradle qual dependência usar nos tipos de depuração. liveImplementation informa ao Gradle qual usar em versões ao vivo, e usando o projeto (‘caminho’) localiza nossa biblioteca autônoma em nosso projeto, por seu caminho. Isso significa que, quando estamos em um tipo de depuração, estamos usando a versão original do Stetho. Em uma versão ao vivo, estamos usando nossa versão no-op.
Depois que o Gradle for sincronizado, você deverá notar uma diferença ao encontrar os usos de initializeWithDefaults – o tipo de depuração apontará para a biblioteca genuína e o sabor ao vivo para o no-op que criamos.
E é isso!