News & Events
Atualizador Automático vs Google Play
Publicar aplicativos na loja Google Play, tem inúmeras vantagens, tais como: globalização do app, oportunidade de vendas no mundo todo, download automático de versões novas para o usuário final, relatórios de download para o desenvolvedor, ranking de apps, feedback do usuário para o desenvolvedor etc. Mas, e se nosso app não precisa necessariamente estar no Google Play por ser de uso interno, corporativo ou algo do gênero? Sabemos que é possível disponibilizar nosso APK (Extensão de aplicativos Android) em um servidor próprio disponibilizando apenas um link para nosso usuário final baixar. Entretanto, nesse caso, como faremos para atualizar automaticamente o app desses usuários? Obtivemos resposta a esses questionamentos, confira nesse post.
Em conversa com o desenvolvedor Robert Cuervo Campos do site Programador Mobile, descobrimos é possível criar um algorítimo para “enganar” o Android e fazer a atualização de qualquer app, mesmo fora da loja Google Play, bastante importante para quem possui o cenário mencionado acima. Robert publicou seu algorítimo no site fórum do Programador Mobile, mas nos deu permissão para incluir a codificação também aqui. O código é simples de entender e não requer nenhuma grande mágica. Utilizaremos o que já conhecemos de Delphi, Indy. Isso mesmo! Componentes da paleta Indy para fazer o download do APK e em seguida usamos apenas classes do Java para ativar a instalação da versão nova de nosso app.
Atualizador Automático vs Google Play
Como mencionado anteriormente, utilizaremos o componente idHTTP da paleta Indy, já bastante conhecida da comunidade Delphi. Para iniciarmos nosso projeto, crie um novo aplicativo mobile utilizando o menu File > New > Multi-Device Application Delphi (Figura 1), escolha o template Blank Application e siga com o assistente até finalizar a criação do app.
#Dica: Caso seja novato na criação de aplicativos Mobile, sugerimos acompanhar nosso Tutorial: Criando meu app step-by-step. Acesse o menu Tutoriais desse blog e localize o link para o tutorial completo.
Com o app já criado, adicione 2 (Dois) Buttons ou SpeedButtons, 1 (Um) Label e 1 (Um) ProgressBar. Alinhe os componentes conforme desejar, se preferir desenhe uma janela semelhante a Figura 2.
O processo de download e instalação, evidentemente, pode ser efetuado em uma única ação, mas Robert preferiu separar as ações para melhor entendimento do leitor, e concordamos com isso.
No código-fonte do primeiro botão, Download APP, digite o algorítimo da Listagem 1.
procedure TForm1.Button2Click(Sender: TObject); var Caminho_D : String; MyFile : TFileStream; begin {Verifica se o arquivo já existe na pasta de downloads. Apaga caso exista e cria novamente} if FileExists(GetSharedDownloadsDir + '/MeuAplicativo.apk') then DeleteFile(GetSharedDownloadsDir+'/MeuAplicativo.apk'); {Difinição do link de download} {Nesse momento, você deverá informar o link completo para o download do arquivo} Caminho_D:= 'http://www.MEU_SITE/MeuAplicativo.apk'; {Criação a instância do tipo TFileStream} {Aqui informamos o local (diretório no mobile) onde o aplicativo será baixado} MyFile := TFileStream.Create(GetSharedDownloadsDir + '/MeuAplicativo.apk', fmCreate); try {Download do arquivo} IdHTTP1.Get(Caminho_D, MyFile); finally MyFile.Free; end; end;
Listagem 1. Download do app
Robert comentou todo o código-fonte, então fica fácil de entendermos. De qualquer forma, vamos lá. No primeiro momento nós testamos se o arquivo APK já encontra-se em nosso diretório de downloads no Android. Usamos algo extremamente simples, um FileExists bem conhecido em apps Desktop. Passamos como parâmetro o result do método GetSharedDownloadsDir presente na Unit Androidapi.IOUtils, portanto precisará adicionar essa Unit ao Uses do projeto para ter acesso a ela. O método retorna o diretório de downloads do Android. Acrescido ao resultado do método, informamos o nome do arquivo, MeuAplicativo.apk. Se o arquivo já existir, excluímos.
Em seguida, informamos o link completo para download do arquivo na variável Caminho_D. Instanciamos então uma variável do tipo TFileStream, MyFile, para receber o arquivo em si. E por fim fazemos o download usando o método Get do idHTTP. Isso fará o arquivo ser baixado e gravado no diretório de downloads.
Depois faremos os refinamentos para mostrar a barra de progresso enquanto o arquivo é baixado, isso acontecerá programando os eventos OnWork, OnWorkBegin e OnWorkEnd do idHTTP, mas antes vamos digitar o código da instalação do app.
Nós vamos usar métodos Intent do Java dentro do Delphi, para invocarmos o aplicativo. Na verdade o que faremos é executar o arquivo baixado, o que forcará a instalação do mesmo. Clique duas vezes no botão 2 e digite o código da Listagem 2.
procedure TForm1.Button1Click(Sender: TObject); var aFile : Jfile; Intent : JIntent; begin aFile := TJfile.JavaClass.Init(stringtojstring(GetSharedDownloadsDir), StringToJString('APP.apk')); Intent := TJIntent.Create; Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK); Intent.setDataAndType(TJnet_Uri.JavaClass.fromFile(aFile),StringToJString('application/vnd.android.package-archive')); SharedActivityContext.startActivity(Intent); end;
Listagem 2. Instalação do app
Basicamente temos duas variáveis aqui responsáveis pelo arquivo. São elas aFile (JFile) e Intent (JIntent). Em aFile nós inicializamos chamando o método Init da classe JavaClass em TJFile. Note que informamos o nome do arquivo baixado, MeuAplicativo.apk. Em seguida criamos uma instância de Intent para que possamos manipular o arquivo. O restante diz respeito a configuração de abertura desse arquivo, ações e flags necessárias. Não entraremos em detalhes. Por fim, chamamos o método startActivity para invocar a abertura do arquivo. A partir daqui, o sistema operacional fará seu trabalho, ou seja, preparar o arquivo para instalação, perguntar ao usuário se deseja instalar, etc.
Refinamentos
Para que o usuário não fique sem informações sobre o que está acontecendo, vamos informar a ele o progresso de download. Isso é relativamente simples, nesse caso, e basta codificarmos os eventos mencionados anteriomente, OnWork, OnWorkBegin e OnWorkEnd do componente idHTTP. Incluímos na Listagem 3 todo o código dos 3 (três) eventos, então tenha atenção ao copiar/digitar o código.
procedure TForm1.IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64); begin ProgressBar1.value := AWorkCount; Application.ProcessMessages; end; procedure TForm1.IdHTTP1WorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64); begin ProgressBar1.value := 0; ProgressBar1.Max := AWorkCountMax; Label1.Text := 'Download em andamente, Aguarde!'; end; procedure TForm1.IdHTTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode); begin ProgressBar1.Value := ProgressBar1.Max; Label1.text := 'Download Concluído!'; end;
Listagem 3. Código dos eventos de progresso no idHTTP
O evento OnWork é bem simples, assim como os demais. Nós apenas atualizamos a propriedade Value com o valor do parâmetro AWorkCount do evento. Por fim chamamos Application.ProcessMessages para atualizar a tela. Já o evento OnWorkBegin, zeramos a propriedade Value do ProgressBar e atualizar o Max com o valor recebido em AWorkCountMax e incluímos um texto padrão. Para finalizarmos, no evento OnWorkEnd nós atualizamos novamente o Value da ProgressBar com o valor da propriedade Max do mesmo ProgressBar.
Em tempo de execução o que teremos será uma informação básica do progresso de download. Os parâmetros mencionados na explicação anterior, usados para atualizar o Value e o Max da ProgressBar, possuem a quantidade de bytes já carregados do servidor durante o download. Você pode obter facilmente algorítimos mais precisos na internet, fica a seu critério.
Caso tenha dúvidas quanto as Units que devem ser adicionadas ao Uses do projeto, observe a Listagem 4.
uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText, FMX.Platform.Android, Androidapi.Jni.JavaTypes, Androidapi.JNIBridge, FMX.StdCtrls,FMX.Helpers.Android, IdURI,Androidapi.Jni.Net, FMX.Controls.Presentation, FMX.Edit,Androidapi.IOUtils, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP;
Listagem 4. Units a serem adicionadas
Entrevista com Robert
Robert, gentilmente, nos concedeu uma entrevista para entendermos melhor toda sua ideia e como ele chegou ao algorítimo descrito nas seções acima.
1. TDevRocks: Robert uma da maiores vantagens em se manter um aplicativo no Google Play é o de ter o controle e mensurar os downloads e atualizações do app, além é claro de comentários, classificação e divulgação. Qual foi a sua intenção ao criar o algorítimo para efetuar o download e atualização do app sem uso do Google Play?
Robert: Hoje meu foco é força de vendas, então só desenvolvo aplicativos para empresas. A maioria delas não querem colocar o APP no Google Play por quererem privacidade e que ninguém baixe o seu aplicativo também, diferentemente de aplicativos que você quer que os demais baixem, façam testes e até deem sua nota e opinião no Google Play.
E como praticamente toda empresa tem sua área de TI, é própria TI a responsável por atualizar o aplicativo nos celulares dos vendedores. Os primeiros aplicativos necessitavam que a TI entrasse em contato com o representante para atualizar o aplicativo. Em muitos de meus clientes não encontrei outra solução, senão dar poderes e responsabilidade para que a própria área técnica fizesse suas devidas atualizações. Mas, para uma das empresas que estou desenvolvendo, eles exigiram que tivesse uma atualização automática, portanto precisei pensar em uma solução mais profissional.
No Google se encontra quase tudo hoje em dia, pegando pedaços de códigos em alguns sites consegui chegar ao resultado final esperado.
2. TDevRocks: No mecanismo mostrado por você, a atualização exige uma interação do usuário do app. Você pretende criar algum processo ou API do Android para fazer o processo automático sem também o uso do Google Play?
Robert: Ainda estou trabalhando nisso para que seja 100% automático, espero que em pouco tempo já consiga atualizar 100% automático sem que o usuário precise clicar em instalar.
3. TDevRocks: Assim como você menciona no artigo em seu portal, o algorítimo atualiza somente o apk do aplicativo. Qualquer outro arquivo, como um banco de dados por exemplo, não é atualizado. Você pretende criar um novo tutorial mostrando como fazer a atualização também de arquivos off-line no dispositivo?
Robert: Para a atualização de arquivos, atualmente já é possível fazer isso no Delphi adicionando os arquivos no deployment (Project > Deployment). Ao atualizar o APK, ele já instala juntos os arquivos que você quiser. Para o banco de dados é um pouco mais complicado, pois é preciso verificar se o arquivo já existe antes da alteração. Isso precisa ser feito no próprio aplicativo, criando um algorítimo na inicialização para verificar a existência de tabelas, registros, etc. Essa etapa é necessária, pois o Android não fará a verificação automática do DB, ele simplesmente substituirá o arquivo.
Farei um tutorial explicando isso e com exemplos para o pessoal entender melhor.
#Dica: Uma forma de atualização de banco de dados é com o uso de um servidor DataSnap, ou seja, criando um app multi-camadas e alguns algorítimos para resgatar informações atualizadas do servidor. Veja um exemplo em nosso Tutorial: Criando meu app step-by-step.
4. TDevRocks: Em seu tutorial, você faz uso de APIs do Android. O que você recomenda de links para estudo de outras APIs do sistema operacional?
Robert: Há algumas semanas atrás (Partindo da data de publicação desse post) comecei a entender essas APIs que podem ser usadas em conjunto com o Delphi. Você pode usar um arquivo .JAR para utilizar funções diversas, tais como chamadas a hardwares externos, criação de classes, etc. De fato um excelente recurso do Delphi para evitarmos ficarmos presos ao Pascal. Temos um mundo de funções, ainda tenho muito a aprender sobre as APIs, mas agora podemos dizer que o Delphi não fica tão limitado como parecia a principio.
Links que me ajudaram a entender melhor:
Delphi.org
DocWiki da Embarcadero
Blog do Fernando Rizzato
Uma última informação, extremamente importante no exemplo, é não esquecer de dar permissão para leitura de arquivos externos no Android. Acesse o menu Project > Options e em seguida o item Uses Permissions. Marque a opção READ EXTERNAL STORAGE. Veja na figura abaixo.