Persistência Com Firebase Android - Parte 1
(22520) (42)
CategoriasAndroid, Design, Protótipo
AutorVinÃcius Thiengo
VÃdeo aulas186
Tempo15 horas
ExercÃciosSim
CertificadoSim
CategoriaDesenvolvimento Web
Autor(es)Robert C. Martin
EditoraAlta Books
Edição1ª
Ano2023
Páginas416
Tudo bem?
Neste artigo vamos dar início a série: APIs Firebase para o desenvolvimento acelerado de aplicativos Android.
Mas antes de continuar...
... não deixe de se inscrever 📩 na lista de emails do Blog para ter acesso aos conteúdos exclusivos sobre desenvolvimento Android.
Continuando...
Firebase é uma plataforma Web que nos permite salvar os dados de nossas aplicações na base de dados NoSQL provida por eles.
O Firebase é de tecnologia proprietária e tem uma conta iniciante que é gratuita.
A grande vantagem de seu uso está na velocidade provida pela entidade NoSQL, mesmo quando com dados em massa.
E a facilidade de uso da biblioteca no código Android. Como poucas linhas de código já possível, por exemplo, realizar todo o processo de cadastro e autenticação de um novo usuário de nosso aplicativo.
O Firebase é sem sombra de dúvidas uma excelente opção para aqueles que utilizavam a base de dados no Parse.com (empresa que fechou as portas).
Como indicado no vídeo no final desse post, ler a documentação do Firebase é essencial ainda mais quando é pequena e como muitos exemplos.
Atenção principal na página de "Structuring Data", onde é apresentado como se deve estruturar uma base de dados NoSQL no Firebase, algo diferente quando operando base de dados no modelo relacional.
No decorrer do post vamos construindo o código dessa primeira parte da série, onde trabalharemos o cadastro e login de um novo usuário em nosso aplicativo de chat.
O primeiro passo é criar uma conta no Firebase entrando na área de sign up: https://www.firebase.com/signup/.
O segundo passo é criar um projeto no dashboard do Firebase, clique no retângulo cercado de borda tracejada, insira o nome do aplicativo e logo depois clique em "CREATE NEW APP":
O terceiro passo é escolher um tipo de provider de autenticação que será utilizado em nosso aplicativo.
Podemos escolher entre:
- Email & Password (esse é o que vamos utilizar nesse projeto);
- Facebook;
- Twitter;
- Google;
- GitHub;
- Anônimo;
- e Customizado (junto ao sistema de autenticação de nosso aplicativo, caso exista um algoritmo de login proprietário ao nosso app).
Para acessar essa área de providers clique em "Login & Auth" no menu lateral esquerdo.
Logo depois clique na aba "Email & Password" e em seguida clique no checkbox "Enable Email & Password Authentication":
O quarto passo é configurar o Gradle, mais especificamente o build.gradle (Module: app), em "dependencies" adicione o compile abaixo:
...
compile 'com.firebase:firebase-client-android:2.5.1+'
...
Feito isso o próximo passo é colocar a permissão de Internet no AndroidManifest.xml:
...
<uses-permission android:name="android.permission.INTERNET" />
...
Nosso próximo passo é criarmos uma CustomApplication que será responsável por iniciar o contexto no Firebase:
public class CustomApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext( this );
}
}
Volte no AndroidManifest.xml e coloque o atributo android:name=".CustomApplication" na tag <application> como abaixo:
...
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name=".CustomApplication">
...
Agora, no domínio do problema de nosso projeto temos um package /util que contém uma classe que implementa o padrão "Class Library", nessa classe temos os métodos não comuns a uma especifica classe de nosso.
Nela vamos acrescentar o método que permite acessarmos uma instancia do Firebase sempre que necessário.
Note que o código completo está nesse projeto no GitHub: https://github.com/viniciusthiengo/nosso-chate.
Segue código das inserções de método e variável na ClasseLibrary:
...
private static Firebase firebase;
public static Firebase getFirebase(){
if( firebase == null ){
firebase = new Firebase( "https://nosso-chat-fb.firebaseio.com" );
}
return( firebase );
}
...
Depois desses passo de configuração vamos para a classe SignUpActivity.
Devemos iniciar o Firebase e logo depois, assim que o usuário solicitar o envio dos dados pelo clique no botão de envio, enviar os dados ao server Firebase e então aguardar o retorno de:
- Sucesso, o usuário foi salvo na base Firebase;
- ou Fail, o usuário não pôde ser salvo.
Neste último caso vamos utilizar um Snackbar para printar o problema.
Segue código de inicialização no onCreate():
...
protected void onCreate( Bundle savedInstanceState ){
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_sign_up );
Toolbar toolbar = (Toolbar) findViewById( R.id.toolbar );
setSupportActionBar( toolbar );
firebase = LibraryClass.getFirebase();
initViews();
}
...
Logo depois o código do método saveUser().
Método esse que é invocado dentro do método sendSignUpData(), esse é último é chamado depois que houve o clique no botão "Cadastrar".
Segue saveUser() code:
...
private void saveUser(){
firebase.createUser(
user.getEmail(),
user.getPassword(),
new Firebase.ValueResultHandler<Map<String, Object>>(){
@Override
public void onSuccess( Map<String, Object> stringObjectMap ){
user.setId( stringObjectMap.get( "uid" ).toString() );
user.saveDB();
firebase.unauth();
showToast( "Conta criada com sucesso!" );
closeProgressBar();
finish();
}
@Override
public void onError( FirebaseError firebaseError ){
showSnackbar( firebaseError.getMessage() );
closeProgressBar();
}
}
);
}
...
Note que caso tudo tenha sido um sucesso, temos ainda que salvar o nome do usuário no Firebase, pois o processo de cadastro somente aceita o email e senha.
O id único é retornado no stringObjectMap.
Esse id único é na verdade único para cada usuário no provider que está sendo utilizado, na mudança de provider (Facebook login, por exemplo) o id será também alterado.
Segue implementação do método saveDB() de User:
...
public void saveDB(){
Firebase firebase = LibraryClass.getFirebase();
firebase = firebase.child( "users" ).child( getId() );
setPassword( null );
setId( null );
firebase.setValue( this );
}
...
Quando realizamos a chamada firebase.child("users").child( getId() ) estamos na verdade informando que queremos acessar a base Firebase atualmente conectada.
Logo depois acessar o nó "users" e em seguida acessar o nó representado pela String retornada da chamada getId().
Note que caso nenhum dos nós exista em nossa base de dados Firebase todos serão então criados.
Estamos falando em nós e não em tabelas e colunas, pois a base sendo utilizada é uma NoSQL, que tem o modelo de persistência diferente que o do mais convencional modelo relacional.
Em nosso caso o Firebase utiliza JSON para persistir e trabalhar os dados, por isso também utilizamos o termo "nó".
O uso do método setValue() é crítico, pois os dados que não estão configurados nele, mesmo que já salvos no Firebase no caminho de nós indicados, esses dados não configurados são removidos do Firebase.
As outras opções de persistência do Firebase vamos ver em um próximo artigo.
Para podermos utilizar o objeto da classe User como parâmetro de entrada em setValue() temos primeiro que nos certificarmos de que a classe tem métodos getters para as variáveis de instância que devem ter os valores salvos no Firebase e também garantir a existência de um construtor vazio, como o abaixo:
...
public User(){}
...
A base de dados, quando utilizada, ficará com uma estrutura similar a apresentada abaixo (via Firebase Dashboard):
Voltando ao método saveUser() que está na SignUpActivity, caso dê tudo certo e o usuário seja salvo, próximo ao final do processamento é chamado o método unauth() de Firebase.
A ideia ai é desconectar o usuário, pois ele apenas realizou o cadastro, terá de realizar o login ainda.
Caso não faça isso o aplicativo deixará o usuário conectado, a desvantagem vem se seu sistema tiver um processo de verificação de email para comprovar que é o usuário proprietário do email mesmo.
Como essa confirmação é parte de um processo de segurança, mesmo que ainda não implementado no aplicativo de exemplo, vamos seguir o fluxo desse script, desconectando o usuário para obrigá-lo a logar novamente.
Como informado anteriormente, o código completo está no GitHub em: https://github.com/viniciusthiengo/nosso-chate.
Note que em SignUpActivity a variável "firebase" é uma variável de instância.
Note também que a utilização da superclasse CommonActivity é necessária para evitar duplicação de código em LoginActivity e SignUpActivity.
O próximo passo é a configuração da LoginActivity.
Começamos iniciando a variável de instância "firebase", dentro do método onCreate(), como fizemos em SignUpActivity:
...
@Override
protected void onCreate( Bundle savedInstanceState ){
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_login );
firebase = LibraryClass.getFirebase();
initViews();
verifyUserLogged();
}
...
Note a presença do método verifyUserLogged().
Esse método é responsável por verificar, antes de apresentar a tela de login, se o usuário já estava logado no aplicativo.
Caso sim, esse método deve também chamar a atividade que é apresentada somente para usuários logados. Em nosso caso é a MainActivity.
Logo o próximo passo é desenvolver o código desse método:
...
private void verifyUserLogged(){
if( firebase.getAuth() != null ){
callMainActivity();
}
else{
initUser();
if( !user.getTokenSP(this).isEmpty() ){
firebase.authWithPassword(
"password",
user.getTokenSP( this ),
new Firebase.AuthResultHandler(){
@Override
public void onAuthenticated( AuthData authData ){
user.saveTokenSP( LoginActivity.this, authData.getToken() );
callMainActivity();
}
@Override
public void onAuthenticationError( FirebaseError firebaseError ){}
}
);
}
}
}
...
Primeiro verificamos se getAuth() tem algum dado diferente de null, segundo a documentação do Firebase, se o valor retornado desse método for diferente de null então o usuário já está conectado.
Caso essa condicional falhe, ainda temos de verificar via token se o usuário pode ser considerado ou não conectado.
O termo "password" na verdade identifica o tipo de provider que estamos utilizando junto a autenticação dos usuários e consequentemente na geração dos tokens.
Os outros providers são: Facebook, Google, Twitter, ...
O método getTokenSP() de User está na verdade delegando o trabalho de busca de token para o método getSP() de nossa LibraryClass.
Segue implementação em User:
...
public String getTokenSP( Context context ){
String token = LibraryClass.getSP( context, TOKEN );
return( token );
}
...
Então a implementação em LibraryClass:
...
static public String getSP( Context context, String key ){
SharedPreferences sp = context.getSharedPreferences( PREF, Context.MODE_PRIVATE );
String token = sp.getString( key, "" );
return( token );
}
...
Essa delegação via classe User dá mais intenção ao código, mesmo que tenha uma chamada a mais ao verdadeiro processamento. Fica mais fácil de entender o código do que chamar LibraryClass.getSP() diretamente.
Voltando ao método verifyUserLogged(), em onAuthenticated() é salvo o token na sequência de métodos chamados.
Classe User:
...
public void saveTokenSP( Context context, String token ){
LibraryClass.saveSP( context, TOKEN, token );
}
...
Classe LibraryClass:
...
static public void saveSP(
Context context,
String key,
String value ){
SharedPreferences sp = context.getSharedPreferences( PREF, Context.MODE_PRIVATE );
sp.edit().putString( key, value ).apply();
}
...
Logo depois é chamado o método callMainActivity() que faz o que o nome indica, chama a MainActivity caso o usuário esteja realmente conectado.
Esse método também chama o finish() para remover a LoginActivity da pilha de atividades:
...
private void callMainActivity(){
Intent intent = new Intent( this, MainActivity.class );
startActivity( intent );
finish();
}
...
O próximo passo é implementar o código do método verifyLogin().
Esse método é chamado dentro do método sendLoginData() que é acionado com o clique no botão de login do aplicativo.
Segue área de login:
E código do método sendLoginData():
...
public void sendLoginData( View view ){
openProgressBar();
initUser();
verifyLogin();
}
...
Note que esse método somente passivo de ser acionado caso o usuário não esteja já conectado, desse forma a página de login normal será apresentada a ele.
Segue código do método verifyLogin():
...
private void verifyLogin(){
firebase.authWithPassword(
user.getEmail(),
user.getPassword(),
new Firebase.AuthResultHandler(){
@Override
public void onAuthenticated( AuthData authData ){
user.saveTokenSP( LoginActivity.this, authData.getToken() );
closeProgressBar();
callMainActivity();
}
@Override
public void onAuthenticationError( FirebaseError firebaseError ){
showSnackbar( firebaseError.getMessage() );
closeProgressBar();
}
}
);
}
...
Bem similar ao código de verificação de token, porém dessa vez enviamos o email e senha para verificação no Firebase.
Note que se dessa vez algo dê errado, um Snackbar é utilizado para alertar o usuário.
Com o login dando certo devemos ser redirecionados a MainActivity.
Nessa atividade, neste primeiro artigo, apenas vamos permitir o logout do aplicativo, chamando em seguida a LoginActivity.
A interface de MainActivity é como se segue:
O que nos resta é colocarmos uma ação no botão de Logout.
Esse botão tem um método logout() vinculado ao listener de clique dele.
Segue código do método:
...
public void logout(View view){
Firebase firebase = LibraryClass.getFirebase();
firebase.unauth();
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
}
...
A chamada firebase.unauth() já é conhecida sua, estamos realizando o logout nessa chamada.
Com isso terminamos a implementação de nosso cadastro e login no aplicativo Android Nosso Chat.
Antes de partir para a vídeo aula e para a conclusão...
Não deixe de se inscrever na 📩 lista de emails do Blog para receber em primeira mão conteúdos Android exclusivos.
Se inscreva também no canal do Blog em: YouTube Thiengo.
Vídeo
A seguir o vídeo onde é apresentada, passo a passo, a construção do aplicativo Android de exemplo com o conjunto de APIs Firebase:
Como já informado algumas vezes neste artigo, o código completo do projeto Android de exemplo pode ser encontrado no seguinte repositório GitHub:
Não deixe de acessar o repositório e de ler todas as dicas presentes nele. Dicas importantes para a implementação do projeto de exemplo em seu próprio ambiente de desenvolvimento Android.
Conclusão
Principalmente a API de persistência do Firebase, mais precisamente a API Database.
Principalmente está API vai vir para literalmente sacudir o mercado de aplicativos com conteúdos compartilhados.
O que quero dizer é que:
Construir uma rede social, por exemplo, será algo muito mais simples.
Pois a crítica tarefa de gerência de banco de dados remoto será transferida para os servidores do Firbease Database e para todos os profissionais e sistemas deles.
Desta forma, nós desenvolvedores teremos que somente consumir API.
Obviamente que haverá um custo para isso, mas tudo indica que o "custo benefício" será excelente para desenvolvedores Android e para desenvolvedores das outras demais plataformas que são atendidas pelo Firebase.
Lembrando que este é o primeiro artigo da série sobre o conjunto de APIs Firebase em aplicativos Android.
Note que na pressa o "chate" saiu com "e" mesmo.
Então é isso.
Não deixe de se inscrever na 📩 lista de emails do Blog para receber todos os conteúdos de desenvolvimento de maneira gratuita e em primeira mão.
Lembrando que a versão em PDF dos artigos é entregue somente para os inscritos na lista de e-mails.
Surgindo dúvidas, pode deixar abaixo nos comentários que logo eu lhe respondo.
Abraço.
Comentários Facebook