Facebook Login, Firebase Android - Parte 5
(9003) (9)
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
Opa, blz?
Nesse post continuamos com a série Firebase no Android, dessa vez abordando o login por meio do Facebook Login.
O Firebase ainda permite login com as redes: Twitter, GitHub e Google. Porém esses são assuntos para possíveis vídeos futuros da série.
Antes de prosseguir com o projeto abaixo listo os posts já liberados dessa série:
Remoção de Conta e Dados de Login, Firebase Android - Parte 4
Atualização de Dados, Firebase Android - Parte 3
Eventos de Leitura e Firebase UI Android - Parte 2
Persistência Com Firebase Android - Parte 1
Prosseguindo... Começando pelo Gradle App Level (ou build.gradle(Module: app)). Colocamos a referência a library do Facebook, como segue:
...
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'com.firebase:firebase-client-android:2.5.2+'
compile 'com.firebaseui:firebase-ui:0.3.1'
compile 'com.facebook.android:facebook-android-sdk:[4,5)' /* ESSA LINHA */
}
Logo depois devemos criar nossa Facebook APP no dashboard de desenvolvedor do Facebook acessando o seguinte link: https://developers.facebook.com/
Note que você deve estar conectado a sua conta Facebook para então prosseguir na página de developers Facebook.
Agora no canto superior direito da página clique em "Meus aplicativos". Logo depois, na próxima página clique em "+ Adicionar um novo aplicativo". Então na modal que aparecer clique no logo do Android.
A seguir coloque o nome de sua aplicação no Facebook, logo depois clique em "Criar Novo Número de Identificação de Aplicativo do Facebook". Depois disso um modal será aberto. Coloque seu email para contato, selecione uma categoria (em nosso exemplo foi escolhida "Comunicação", mas você pode escolher a que achar melhor) e então clique em "Crie um ID do Aplicativo".
Depois desses primeiros passos de configuração começamos a alteração de código no projeto. Iniciando pelo arquivo /res/values/strings.xml. Nele vamos colocar uma variável que vai referenciar o ID de nossa APP Facebook, como segue:
<resources>
...
<string name="action_sign_in_facebook">Sign in com Facebook</string>
<string name="facebook_app_id">112993499108891</string>
</resources>
Para adiatntar o desenvolvimento já deixamos também no strings.xml o rótulo de nosso Facebook login button que será colocado no content_login.xml de nossa activity LoginActivity.
O próximo passo é colocar a permissão de Internet em nosso AndroidManifest, porém já fizemos isso logo no primeiro post onde foi necessário devido a utilização do Firebase que também necessita de conexão com a Internet.
Então podemos pular para o passo onde devemos colocar uma <metadata> tag dentro de nossa <application> tag que estará referenciando nossa variável em strings.xml que contém a nossa APP Facebook ID. Segue trecho de código adicionado a AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="br.com.thiengo.thiengocalopsitafbexample">
<uses-permission android:name="android.permission.INTERNET" />
...
<application
android:name=".CustomApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
...
</application>
</manifest>
Voltando ao dashboard Facebook temos que colocar o package name de nossa APP no Facebook, mais precisamente no campo "Package Name". Logo copie o valor do atributo "package" da tag <manifest> de AndroidManifest.xml e cole nesse campo.
Logo depois devemos fornecer também o caminho completo de nossa activity principal, em nosso caso a LoginActivity. Com o mesmo package name copiado anteriormente de <manifest>, cole esse valor no campo "Default Activity Class Name" e então acrescente o .LoginActivity como em: br.com.thiengo.thiengocalopsitafbexample.LoginActivity
Logo depois clique em Next. A tela seguinte (um modal) pode lhe deixar confuso se sua APP já não estiver na PlayStore, mas na verdade é somente uma informação de que o sistema do Facebook não encontrou sua APP na PlayStore e não um bloqueio devido a isso. Segue print do modal:
Logo apenas clique em "Use this package name".
Ainda na mesma página será carregada uma área de continuação de configuração da APP no Facebook. A primeira parte da continuação é o fornecimento de nossa hash de desenvolvimento. Clique em "Show how to generate a development key hash" caso sua APP esteja ainda em fase de desenvolvimento ou clique em "Show how to generate a release key hash" caso já tenha assinado a APP e essa esteja pronta para a fase de produção.
Clicando em "Show how to generate a development key hash" será apresentado como gerar a hash no Mac e logo abaixo no Windows. Copie o modelo referente ao seu sistema operacional e cole no prompt de comando. O resultado será algo similar a:
Pressione "Enter" e entre com a senha "android", isso se estiver com a versão de debug, que é a mesma que estamos utilizando nesse exemplo. Caso contrário forneça a senha que você definiu para seu arquivo de keystore quando estava assinando a APP.
Depois de fornecer a senha e pressionar "Enter" novamente terá a tela, dessa vez apresentando o hash, como segue:
Copie a hash, em meu caso foi w+G0wD6YLH2xLfqejvBliVgkGmU=. Depois cole no campo "Key Hashes" e clique em "Next".
Logo depois mais algumas partes serão carregadas, uma para colocarmos os scripts de tracking do Facebook em nossa Application class e a outra parte com referências a alguns outros tutoriais do Facebook SDK para Android.
Ignore a primeira parte e na segunda parte entitulada "Next Steps" clique no link "Skip to Developer Dashboard" e então será apresentada uma tela similar a tela abaixo:
Então acesse sua conta no site do Firebase, acesse seu projeto e então no menu lateral clique em "Login & Auth" logo depois na aba "Facebook". A tela será como segue:
Logo em seguida, ainda nessa página, clique no checkbox "Enable Facebook Authentication" e então volte ao dashboard de sua APP Facebook, copie seu "ID do Aplicativo" e cole no campo "Facebook App Id" de seu dashboard Firebase. Volte ao dashboard Facebook, clique em "Mostrar", forneça sua senha (se solicitado) e então copie sua "Chave Secreta do Aplicativo" e cole no campo "Facebook App Secret" de seu dashboard Firebase. Feito isso nosso projeto Firebase está pronto para receber logins via Facebook.
Agora vamos prosseguir voltando para a codificação. Mais precisamente ao AndroidManifest.xml, nele vamos configurar a activity que permite o login via Facebook, FacebookActivity:
...
<application
android:name=".CustomApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:label="@string/app_name" />
...
</application>
...
Agora no xml de conteúdo de nossa LoginActivity vamos adicionar um button logo abaixo do button de login convencional. Esse novo button será nosso button personalizado de login via Facebook. Segue trecho de código adicionado ao layout content_login.xml:
...
<Button
android:onClick="sendLoginData"
android:id="@+id/email_sign_in_button"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/action_sign_in"
android:textStyle="bold" />
<!-- ABAIXO O BUTTON ADICIONADO -->
<Button
android:onClick="sendLoginFacebookData"
android:id="@+id/email_sign_in_facebook_button"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/action_sign_in_facebook"
android:textStyle="bold" />
...
Agora em LoginActivity vamos colocar as chamadas de inicialização da Facebook SDK e também a configuração de um callback para gerenciar o retorno de dados do Facebook a nossa APP:
public class LoginActivity extends CommonActivity {
...
private CallbackManager callbackManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
FacebookSdk.sdkInitialize(getApplicationContext());
callbackManager = CallbackManager.Factory.create();
LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult){
/* TODO */
}
@Override
public void onCancel(){}
@Override
public void onError(FacebookException error){
showSnackbar( error.getMessage() );
}
});
firebase = LibraryClass.getFirebase();
initViews();
verifyUserLogged();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
callbackManager.onActivityResult( requestCode, resultCode, data );
}
...
}
O LoginManager.getInstance() é necessário, pois não estamos utilizando o Facebook Login Button. Será com o callback configurado em LoginManager.getInstance().registerCallback() junto a instância anônima de new FacebookCallback<LoginResult> que vamos saber se houve ou não o login como solicitado.
Note que a configuração do método da activity, onActivityResult(), é necessário para passar o retorno do Facebook ao nosso callback CallbackManager.
Dois outros passos essenciais que devemos configurar agora são o método sendLoginFacebookData() que está vinculado ao listener de click do Facebook login button personalizado e também o conteúdo do método onSuccess() de nossa instância anônima em LoginManager.getInstance().registerCallback(). Segue primeiro o método sendLoginFacebookData():
public class LoginActivity extends CommonActivity {
...
public void sendLoginFacebookData( View view ){
LoginManager
.getInstance()
.logInWithReadPermissions(
this,
Arrays.asList("public_profile", "user_friends", "email")
);
}
...
}
No método sendLoginFacebook() colocamos a chamada ao login Facebook junto as permissões necessárias, no caso somente permissões que não necessitam de validação do Facebook para liberação de nossa APP ao público.
Note que o dado "email" é hoje no Facebook um campo que pode sim vir vazio, pois o usuário pode realizar o cadastro utilizando o número de telefone.
Isso se torna um problema segundo nossa lógica de negócio, pois nossa aplicação utiliza o email do usuário como parte da autenticação de acesso dele, dessa forma para que possamos manter o mapeamento do usuário para também realizar o login via modo convencional (entrando com o email e senha) teríamos que verificar o retorno do Facebook e caso o campo email fosse vazio teríamos de colocar um passo extra para o cadastro ser efetivado, o passo estaria com o campo de email para ser preenchido.
E note que mesmo com o email sendo retornado corretamente teríamos de qualquer forma que colocar mais um passo extra para o cadastro ser finalizado, isso para podermos coletar a senha do usuário em nosso sistema, mesmo ele se conectando via Facebook login, pois caso contrário não conseguiria conectar via modo convencional.
Claro que todos esses passo mais complexos seriam necessários se fosse um requisito nossa APP manter o mapeamento de email do usuário com conta convencional e conta via Facebook.
Se analisarmos bem, nossa APP não precisa que o email esteja vinculado ao usuário, na verdade até o momento o email é somente necessário no mode de login Firebase "Email & Senha", mas na base de dados mesmo o que precisamos é o id único gerado para o usuário assim que ele se cadastra em nossa APP, e um id único e o nome do usuário é garantido que podemos acessar assim que o usuário se conecta em nossa APP via Facebook login.
Consequentemente esse id único será o nodo de nosso usuário na base Firebase, onde o campo email poderá estar vazio e o campo nome terá o nome dele no Facebook.
Dessa forma se o usuário se conectar utilizando o Facebook e depois se ele se conectar utilizando o modelo convencional, mesmo que ambas as contas tenham o mesmo endereço de email nosso APP entenderá como se fosse ambas as contas duas contas distintas e isso não causará nenhum problema na lógica utilizada na APP. Essa é a maneira correta? Sim, para a lógica de negócio que adotamos é sim, porém com mapeamento de contas também seria, com alguns muitos passos a mais.
O que devemos notar é que um dos motivos do Facebook login button ser utilizado é a praticidade de evitar que o usuário preencha um formulário de cadastro, porém adotar uma estratégia em que ele utilize os dados dele do Facebook para depois ainda solicitar que entre com dados de senha e / ou email faz com que essa praticidade seja eliminada.
Agora podemos partir para o conteúdo do método onSuccess():
public class LoginActivity extends CommonActivity {
...
private void accessFacebookLoginData(AccessToken accessToken){
if( accessToken != null ){
firebase.authWithOAuthToken(
"facebook",
accessToken.getToken(),
new Firebase.AuthResultHandler() {
@Override
public void onAuthenticated(AuthData authData) {
user.saveTokenSP( LoginActivity.this, authData.getToken() );
user.saveIdSP( LoginActivity.this, authData.getUid() );
user.setId( authData.getUid() );
user.setName( authData.getProviderData().get("displayName").toString() );
user.setEmail( authData.getProviderData().get("email").toString() );
user.saveDB();
callMainActivity();
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
showSnackbar( firebaseError.getMessage() );
}
});
}
else{
firebase.unauth();
}
}
...
}
O que fazemos acima é realizar o processo de login comum no Firebase, porém dessa vez utilizando o Facebook provider junto ao token retornado da conexão via Facebook. Note que mesmo com o login via Facebook estamos salvando o token e o ID retornados, isso no SharedPreferences como já faziamos com o login convencional.
Mas alguns passos são novidade no script de login, os que nos permite salvar os dados do ussuário em nossa base Firebase, da linha referente a user.setId() até a linha referente a user.saveDB().
Por que isso? Porque caso somente realizassemos o login via Facebook nosso usuário não teria nenhum dado na base, como acontece com o cadastro do usuário em nossa APP no modo convencional, os dados de autenticação no Firebase são criados, mas os dados na base não.
Esse passo de salvar os dados na base Firebase, se notar bem, são os mesmo do cadastro de usuário no modo convencional, mas devido a praticidade do login via Facebook (sem o passo de cadastro) temos de seguir esses passos de salvar no onSuccess() mesmo, para depois prosseguir para a MainActvity.
Dessa forma o id, nome e email são colocados no user e então são salvos na base e seguramente sabemos que o id é único por usuário mesmo sendo ele de uma vinculação Firebase e rede social.
Feito isso toda nossa configuração em LoginActivity está terminada, porém ainda temos algumas coisas a resolver. Se realizar o login utilizando uma conta convencional perceberá que o menu no topo direito da APP apresenta opções de atualização:
Porém quando conectado via Facebook login o usuário não poderá alterar senha, nome, email e nem mesmo remover, pois vamos deixar essas funcionalidades todas com o Facebook, apenas vamos ficar com a funcionalidade de obter os dados mais atuais do usuário.
Logo o que devemos fazer é bloquear aquele menu completo quando o usuário está logado via Facebook e apresentar um menu que tem somente a opção de "Logout".
Nosso próximo passo é criar um novo layout de menu xml dentro do folder /res/menu. Segue código de menu_social_network_logged.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item
android:id="@+id/action_logout"
android:orderInCategory="100"
android:title="@string/logout"
app:showAsAction="never" />
</menu>
Agora devemos ter na classe User um método que vai nos permitir verificar se o usuário atual está ou não logado via Facebook. Antes de prosseguir vale a apresentação de como é o id único do usuário quando ele está conectado via Facebook. Segue id de exemplo: facebook:1179701782054006
Note que o id gerado sempre tem esse prefixo "facebook", logo podemos criar um método que vai acessar o id do usuário atual e então verificar se há esse padrão, caso sim esse é um usuário conectado via rede social, via Facebook.
Na classe User adicione o seguinte método:
public class User {
...
public boolean isSocialNetworkLogged( Context context ){
retrieveIdSP( context );
return( this.id.contains("facebook") );
}
...
}
Note o uso do método retrieveIdSP(), isso vai nos permitir acessar o id único sem precisar de acesso ao Firebase. Lembrando que no login, convencional ou via Facebook, salvamos o id único do usuário no SharedPreferences. E com o contains conseguimos facilmente realizar essa verificação de usuário via rede social ou não.
Por que um nome tão genérico e não isFacebookLogged diretamente no método de verificação? Pois com o Firebase podemos ter ainda outras redes sendo utilizadas como login, logo esse método será o mesmo para login via Twitter, GitHub e Google.
Agora voltando ao código da MainActivity temos de atualizar o método onCreateOptionsMenu(), segue atualização:
...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
User user = new User();
if( user.isSocialNetworkLogged( this ) ){
getMenuInflater().inflate(R.menu.menu_social_network_logged, menu);
}
else{
getMenuInflater().inflate(R.menu.menu, menu);
}
return true;
}
...
Nosso próximo passo é atualizar o método onOptionsItemSelected(), mais precisamente o conteúdo do condicional responsável pelo logout do usuário, vamos ter de desconecta-lo também do Facebook:
...
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == R.id.action_update){
startActivity(new Intent(this, UpdateActivity.class));
}
else if(id == R.id.action_update_login){
startActivity(new Intent(this, UpdateLoginActivity.class));
}
else if(id == R.id.action_update_password){
startActivity(new Intent(this, UpdatePasswordActivity.class));
}
else if(id == R.id.action_remove_user){
startActivity(new Intent(this, RemoveUserActivity.class));
}
else if(id == R.id.action_logout){
/* ATUALIZACAO ABAIXO */
firebase.unauth();
LoginManager.getInstance().logOut();
finish();
}
return super.onOptionsItemSelected(item);
}
...
Com isso finalizamos o login via Facebook, com um novo usuário podemos realizar o teste, logo no login teremos. Activity de login o Facebook button:
Login WebView Facebook. O WebView foi utilizado, pois na APP não tinha a APP nativa do Facebook instalada:
Logo depois a validação:
E então o usuário conectado e o menu aberto, apresentando somente uma opção:
Assim terminamos e testamos a vinculação do Facebook login a nossa APP. Para acesso ao projeto completo entre no GitHub: https://github.com/viniciusthiengo/nosso-chate
Abaixo o vídeo com a implementação passo a passo:
Fonte:
Firebase - Java Android Guide Facebook Authentication
Vlw
Comentários Facebook