Motivação

Quando desenvolvemos aplicativos mobile, uma prática muito comum é testar e depurar parte das funcionalidades do software dentro do próprio Windows. Isso ocorre devido ao fato de que os emuladores dos dispositivos físicos são, em geral, bastante lentos dentro do IDE do RAD Studio (geralmente por limitação dos próprios emuladores). Dependendo das configurações do computador e do aparelho, em alguns casos pode ser mais rápido realizar os testes no próprio device, fazendo o deploy do aplicativo. Porém, esse processo também pode consumir vários minutos de processamento e de cópia dos arquivos para o dispositivo físico. Por esse motivo, é bastante comum que testemos as funcionalidades dentro do próprio Windows, já que com o FireMonkey o mesmo código-fonte é utilizado para distribuir o software para todas as plataformas suportadas. Contudo, nem todas as funcionalidades podem ser executadas pelo Windows, como a câmera, o GPS, o acelerômetro, os sensores, a luz do flash, dentre outras. Nessas situações é necessário fazer o deploy do aplicativo para executar esses recursos.

Dentro desse contexto, quando trabalhamos com bases de dados nativas, precisamos sempre definir o caminho do arquivo do banco, o qual é diferente no Windows, Android e iOS. Nesse caso, toda vez que é preciso fazer o deploy do aplicativo, é também preciso mudar o caminho da base de dados para se adaptar a cada tipo de compilação. Uma forma muito utilizada para gerenciar essa questão é definir esses caminhos dentro do próprio código-fonte, comentando e descomentando as linhas de código de acordo com a necessidade de compilação. Porém, essa não é uma maneira muito adequada, pois além do desenvolvedor ter de comentar/descomentar o código, pode acabar esquecendo alguma configuração e perder tempo com recompilações. Para resolver esse problema, podemos utilizar os recursos de variáveis de ambiente do RAD Studio e as diretivas de compilação, para que consigamos programar somente um código-fonte que consiga compilar para qualquer plataforma alvo suportada pelo IDE.

Passo 1: Configurar a conexão

Como o objetivo deste artigo é somente mostrar como realizar a conexão com a base de dados via código, não será construída nenhuma interface gráfica para visualização dos dados. A Figura 1 apresenta um DataModule (File>New>Other>Data Module) com um componente TFDConnection (cnnConexao) e um TFDPhysisSQLiteDriverLink (driver), ambos da paleta FireDAC. O primeiro efetivamente realizará a conexão com a base de dados, enquanto o segundo representa o driver de acesso ao SQLite. Normalmente, para atribuir os valores da conexão deve-se dar um duplo clique no TFDConnection para abrir a janela para a configuração visual das propriedades, porém, esse processo serárealizado posteriormente, via código.

Data Module com os componentes de conexão
Figura 1. Data Module com os componentes de conexão

O próximo passo é configurar a conexão tanto para o dispositivo Android quanto para o iOS, e para isso deve-se acessar o menu Project>Deployment, para que as configurações de deploy do projeto sejam abertas. Observe no combobox da Figura 2 que são exibidas as opções para todos os dispositivos suportados pelo IDE, divididos nas categorias All configurations, Debug configuration e Release configuration.

Caso seja escolhida a opção Release, a base de dados será instalada na versão final a ser copiada para o dispositivo físico, ou seja, quando o aplicativo já se encontra em sua versão final. Por outro lado, a opção Debug deve ser utilizada quando há a necessidade de depurar o código diretamente no dispositivo. Esse modo é comumente utilizado quando se deseja testar algum recurso da câmera ou acelerômetro, os quais não podem ser acessados diretamente pelo Windows. Por fim, a opção All configurations copia a base de dados tanto para debug quanto para release. Nesse exemplo, utilizaremos as opções Release configuration para Android platform e iOS Device – 32 bit platform, no entanto, em uma aplicação comercial deve-se avaliar em quais plataformas o aplicativo será instalado.

Dispositivos para deploy
Figura 2. Dispositivos para deploy

A seguir, devemos adicionar nossa base de dados de exemplo para cada uma dessas duas plataformas, clicando no botão Add file, destacado em vermelho na Figura 3. Para isso, a plataforma correspondente deve ser selecionada no combobox e o arquivo contatos.sdb precisa ser adicionado duas vezes, uma para cada configuração. Além disso, a propriedade Remote Path (destacada em vermelho na figura) deve ter o caminho .\assets\internal para o Android e StartUp\Documents\ para o iOS. Esses valores indicam o caminho no qual a base de dados será armazenada no dispositivo físico.

Adição da base de dados no Android e iOS
Figura 3. Adição da base de dados no Android e iOS

Precisamos agora configurar o local da base de dados no Windows. Normalmente, os desenvolvedores armazenam o caminho da base em constantes do tipo string dentro do próprio código-fonte, porém, o Delphi disponibiliza uma maneira alternativa para esse tipo de armazenamento, que são as variáveis de ambiente. Acessando o menu Tools>Options e clicando em Environment Variables, é possível observar as configurações chamadas de User Overrides (Figura 4). Neste local podem ser definidas variáveis personalizadas e seus valores podem ser acessados via código posteriormente. Dessa forma, algumas das constantes do sistema podem ficar centralizadas e não há necessidade de alterações no código. Para adicionar uma nova, basta clicar no botão New e definir a variável CAMINHO_DB com o valor C:\contatos.sdb, que indica o caminho físico do arquivo da base de dados no computador Windows.

Definição da variável de ambiente
Figura 4. Definição da variável de ambiente

Passo 2: Codificar a conexão com a base de dados

A Listagem 1 apresenta o código que fará a conexão com a base de dados, o qual deve ser programado no evento OnCreate do DataModule. Esse código tem a função de verificar para qual dispositivo está sendo feita a compilação e configurar os parâmetros dinamicamente de acordo com o dispositivo.

Listagem 1. Conexão dinâmica com a base de dados

procedure TdtmConexao.DataModuleCreate(Sender: TObject);
begin
  cnnConexao.Params.Values['DriverID'] := 'SQLite';
  cnnConexao.LoginPrompt := False;
  {$IF DEFINED (ANDROID) || (IOS)}
    cnnConexao.Params.Values['Database'] := TPath.Combine(TPath.GetDocumentsPath, 'contatos.sdb');
  {$ENDIF}
  {$IF DEFINED (MSWINDOWS)}
    cnnConexao.Params.Values['DataBase'] := '${CAMINHO_DB}';
 {$ENDIF}
 cnnConexao.Connected := True;
end;
  • Linha 3: Definimos o DriverID do FDConnection para o SQLite;
  • Linha 4: A propriedade LoginPrompt é desabilitada para que a senha do banco de dados não seja solicitada a cada tentativa de conexão. Nesse exemplo nenhuma senha foi definida, porém, se essa propriedade estiver com o valor True, a janela de usuário e senha aparecerá mesmo assim;
  • Linha 5: Diretiva de compilação que consulta o destino do deploy, definido pelo usuário na seção Target Platforms da janela Project Manager. Nesse caso estamos verificando se o programa está sendo compilado para iOS ou Android;
  • Linha 6: Configuração do parâmetro Database do FDConnection. Aqui fazemos a combinação do caminho do dispositivo apresentado na Figura 3 com o nome do arquivo da base de dados SQLite;
  • Linha 7: Final da primeira diretiva de compilação;
  • Linha 8: Início da diretiva de compilação que verifica se o usuário está compilando para o Windows;
  • Linha 9: Configuração do parâmetro Database do FDConnection, atribuindo o valor da variável de ambiente definida na Figura 4.
  • Linha 11: Efetivamente faz a conexão com a base de dados. Caso nenhum erro seja retornado quando rodar o aplicativo, isso indica que a conexão foi estabelecida com sucesso.

Com isso, finalizamos uma codificação para que não seja mais preciso fazer ajustes no código-fonte quando for necessário portar o aplicativo para outras plataformas. Para rodar o exemplo, sugere-se acessar o menu Project>Options>Forms e nas configurações relativas à criação dos formulários (Auto-create forms), mover o DataModule para a primeira posição. Dessa maneira, quando a aplicação for executada, ele será a primeira classe a ser criada, juntamente com o código definido na Listagem 1.