Google SignIn API, Firebase Android - Parte 6
(6743) (13)
CategoriasAndroid, Design, Protótipo
AutorVinÃcius Thiengo
VÃdeo aulas186
Tempo15 horas
ExercÃciosSim
CertificadoSim
CategoriaEngenharia de Software
Autor(es)Vlad Khononov
EditoraAlta Books
Edição1ª
Ano2024
Páginas320
Opa, blz?
Nesse post continuamos com a série Firebase Android, dessa vez abordando o login social com o Google SignIn API. Com uma implementação um pouco mais complexa que a do post anterior, Facebook Login.
Note que no final do post tem a implementação completa também detalhada em vídeo e o projeto completo pode ser encontrado no GitHub: https://github.com/viniciusthiengo/nosso-chate
Antes de prosseguir com a implementação abaixo segue a lista dos posts já liberados dessa série:
Facebook Login, Firebase Android - Parte 5
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
Listados os posts, vamos iniciar acessando nossa conta no Console do Google. Assim que acessar terá uma tela similar à tela abaixo:
Clique em "CRIAR PROJETO", entre com o nome de seu projeto (nessa série vamos utilizar "Nosso Chat Firebase"). Então clique em "Criar".
Na página que foi aberta logo depois do projeto ter sido criado, página como a debaixo, por exemplo:
Clique em "Credenciais", logo depois em "Tela de consentimento OAuth". No formulário aberto preencha ao menos os campos "Endereço de e-mail" e "Nome do produto mostrado aos usuários". Então clique em "Salvar".
Você será redirecionado a tela de credenciais novamente, porém ainda não poderá criá-las, pois deverá aguardar alguns segundos (um pouco mais de 1 minuto em meu caso) até que a tela de consentimento seja realmente configurada com os dados que você colocou e salvou. Uma opção é alternar entre abas, por exemplo: clique em "Credenciais" e depois de algum tempo em "Tela de consentimento OAuth" e vice-versa, isso para visualizar o quanto antes que os dados ficarem disposto no formulário de tela de consentimento indicando que já possível seguir com o próximo passo, criar as credenciais.
Na tela credenciais clique em "Criar credenciais" e logo depois em "ID do cliente OAuth". Na tela seguinte escolha "Android", entre com o nome da Client ID (em nosso caso pode ser: "User Nosso Chat Firebase"). Logo depois temos de fornecer nossa SHA1 de desenvolvimento (estamos ainda em ambiente de desenvolvimento).
Para isso temos de fornecer o caminho até o executável "keytool" e o caminho até nossa keystore de debug (válida para qualquer projeto em ambiente de desenvolvimento). Em meu caso fica:
Será necessário entrar com a senha do keystore de debug, no caso é: android
Então a tela seguinte será printada com a SHA1 que precisamos:
Agora com a SHA1 copiada de nosso prompt de comando, volte ao formulário de credencial e cole ela no campo indicado no formulário. Logo depois acesse o projeto Android em seu AndroidStudio e no AndroidManifest.xml, mais precisamente na tag root <manifest>, copie o conteúdo do atributo "package" e cole no campo destinado a ele no formulário de credencial.
Com esse último passo finalizado clique em "Criar". Uma tela com uma chave será printada, copie essa chave e então dê um ok na tela para ela fechar.
Com a chave copiada acesse sua conta no FIrebase, mais precisamente seu projeto. No menu lateral esquerdo clique em "Login & Auth". Depois clique na aba "Google" e então no formulário apresentado cole a chave copiada no campo "Google Client ID". O campo "Google Client Secret" ficará vazio. Para finalizar no dashboard Firebase dê um check em "Enable Google Authentication". Você terá algo similar a:
Nosso próximo passo é verificar se o Google Play Services está integrado ao nosso IDE AndroidStudio, logo, com o IDE aberto, clique em "Tools", "Android" e então em "SDK Manager". Na tela seguinte clique na aba "SDK Tools" e certifique-se de que o Google Play Services, ao menos o mais atual, seteja com um check, caso não, marque e clique em "Apply", logo depois em "Ok". Segue tela:
Veirifcado isso vamos acessar a página de tutorial do Google SignIn Android, mais precisamente a página Start Integrating no link: https://developers.google.com/identity/sign-in/android/start-integrating
Vá até a sessão "Get a configuration file", clique em "GET A CONFIGURATION FILE". Na página seguinte selecione o nome da APP que criou no Console do Google, logo em baixo coloque o nome do package de seu projeto, como fizemos no formulário de criação de credencial anteriormente. Então clique em "Choose and configure services":
Na próxima tela clique em "ENABLE GOOGLE SIGN IN" e então clique em "Generate configuration files". Na próxima tela clique em "Download google-services.json" e emt seguida clique em "Continue Adding Sign-In".
Com o arquivo que realizou o download, coloque ele dentro da pasta /app de seu projeto, como abaixo:
Com isso podemos começar com a atualização dos códigos de nossa APP. Comece atualizando o o gradle top level, mais precisamente o de nome: build.gradle (Project: ThiengoCalopsitaFBExample). Deixe dependencies da seguinte forma:
...
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.google.gms:google-services:2.0.0-alpha6'
}
...
Agora no gradle APP level, mais precisamente o de nome: build.gradle (Module: app). Nesse devemos realizar várias atualizações, então apenas ajuste para ficar como o apresentado abaixo:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "br.com.thiengo.thiengocalopsitafbexample"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
repositories {
mavenCentral()
}
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)'
compile 'com.google.android.gms:play-services-auth:8.3.0'
}
Agora você deve estar se perguntando: já temos um google play services auth mais atual que o 8.3.0, por que persistir com o antigo? Até o momento desse post o plugin com.google.gms.google-services ainda não trabalhava com versões mais atuais que o google play services 8.3.0, logo utilize essa configuração se a falha persisitir com versões mais atuais.
Veja que não utilizamos o compile genérico do Google Play Services e sim o especifico para autenticação, sempre utilize somente o necessário, veja os compiles aqui: Setting Up Google Play Services
Nosso próximo passo é iniciar com a configuração do Google SignIn no código Java. Primeiro em nossa activity LoginActivity, em onCreate() coloque os seguintes scripts (somente o depois do comentário "GOOGLE SIG IN"):
...
private GoogleApiClient mGoogleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
/* FACEBOOK */
FacebookSdk.sdkInitialize(getApplicationContext());
callbackManager = CallbackManager.Factory.create();
LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
accessFacebookLoginData( loginResult.getAccessToken() );
}
@Override
public void onCancel() {}
@Override
public void onError(FacebookException error) {
showSnackbar( error.getMessage() );
}
});
/* GOOGLE SIGN IN - esse e o codigo novo */
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("O Web Client ID gerado junto a sua Android Client ID")
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
firebase = LibraryClass.getFirebase();
initViews();
verifyUserLogged();
}
...
Para preencher o requestIdToken() acesse novamente o Console do Google, mais precisamente acesse "Credenciais" e então sua tela estará agora similar a:
Copie a hash da coluna "ID do client" da linha "Web client". Então cole em resquestIdToken().
Agora devemos implementar a interface GoogleApiClient.OnConnectionFailedListener, logo nossa LoginActivity terá a seguinte configuração depois dessa implementação:
public class LoginActivity extends CommonActivity
implements GoogleApiClient.OnConnectionFailedListener {
...
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
showSnackbar( connectionResult.getErrorMessage() );
}
}
Caso falho, o showSnackbar() se encarrega de informar o porquê.
Nosso próximo passo é configurar o listener de clique do bottão de login do Google, começamos pelo XML content_login.xml, nesse XML, logo abaixo do botão de login do Facebook coloque o seguinte button:
...
<Button
android:onClick="sendLoginGoogleData"
android:id="@+id/email_sign_in_google_button"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/action_sign_in_google"
android:textStyle="bold" />
...
No arquivo /res/values/string.xml adicionamos a seguinte nova configuração:
<resources>
...
<string name="action_sign_in_google">Sign in com Google</string>
...
</resources>
Voltando a LoginActivity vamos denifir o método sendLoginGoogleData() logo abaixo de sendLoginFacebookData():
...
public void sendLoginGoogleData( View view ){
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN_GOOGLE);
}
...
Há um trecho desse código que ainda não implementamos, a constante RC_SIGN_IN_GOOGLE, logo vamos declará-la no topo de nossa LoginActivity:
public class LoginActivity extends CommonActivity implements GoogleApiClient.OnConnectionFailedListener {
private static final int RC_SIGN_IN_GOOGLE = 7859;
...
}
Agora em onActivityResult() devemos filtrar a resposta (requestCode e resultCode) para saber se devemos prosseguir com o login do Google SignIn ou do Facebook, como a versão Facebook não tem requestCode definido por nós, vamos tratar o primeiro condicional para o Google SignIn, o else fica para o Facebook:
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if( requestCode == RC_SIGN_IN_GOOGLE
&& resultCode == RESULT_OK ){
GoogleSignInResult googleSignInResult = Auth.GoogleSignInApi.getSignInResultFromIntent( data );
GoogleSignInAccount account = googleSignInResult.getSignInAccount();
syncGoogleSignInToken( account );
}
else{
callbackManager.onActivityResult( requestCode, resultCode, data );
}
}
...
Antes de prosseguir com a implementação de syncGoogleSignInToken() vamos refatorar o método accessFacebookLoginData(), pois o conteúdo dele é muito similar ao que vamos ter para o accessGoogleLoginData(), logo com a refatoração temos:
...
private void accessFacebookLoginData(AccessToken accessToken){
accessLoginData(
"facebook",
(accessToken != null ? accessToken.getToken() : null)
);
}
private void accessGoogleLoginData(String accessToken){
accessLoginData(
"google",
accessToken
);
}
private void accessLoginData( String provider, String token ){
if( token != null ){
firebase.authWithOAuthToken(
provider,
token,
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();
}
}
...
Note que já implementamos a versão do Google e também utilizamos um operador ternário em accessFacebookLoginData() para facilitar e não termos de utilizar uma longa estrutura condicional somente para uma simples validação.
Como estamos em um post série, a explicação do conteúdo de onAuthenticated() deixo com sua leitura no post: Facebook Login, Firebase Android - Parte 5
Agora sim podemos implementar nosso método syncGoogleSignInToken() que será responsável por obter um token válido para nossa vinculação Google SignIn e Firebase Login. Como assim? E o account.getIdToken() do onActivityResult()?
Bad news! Enquanto o Firebase não atualize a configuração para login utilizando Google Accounts temos de utilizar o token no modelo antigo. O token do account.getIdToken() é apenas uma antecipação a uma possível atualização do código do Firebase, pois esse token não será aceito até o momento desse post.
Estranho não?! Enfim, somente para não gerar ainda mais dor de cabeça caso a atualização venha. Somente de curiosidade, se voltar ao onCreate() de LoginActivity, mais precisamente na variável de configuração gso do tipo GoogleSignInOptions. Nessa variável colocamos a configuração de requestIdToken() justamente para termos esse account.getIdToken() com um valor válido, caso contrário uma string vazia é retornada.
Ok, agora finalmente a implementação de syncGoogleSignInToken(), pode colocar logo abaixo de accessLoginData():
...
private void syncGoogleSignInToken( GoogleSignInAccount googleSignInAccount ){
AsyncTask<GoogleSignInAccount, Void, String> task = new AsyncTask<GoogleSignInAccount, Void, String>() {
@Override
protected String doInBackground(GoogleSignInAccount... params) {
GoogleSignInAccount gsa = params[0];
String scope = "oauth2:profile email";
String token = null;
try {
token = GoogleAuthUtil.getToken( LoginActivity.this, gsa.getEmail(), scope );
} catch (IOException e) {
e.printStackTrace();
} catch (GoogleAuthException e) {
e.printStackTrace();
}
return token;
}
@Override
protected void onPostExecute(String token) {
super.onPostExecute(token);
if( token != null ){
accessGoogleLoginData( token );
}
else{
showSnackbar("Google login falhou, tente novamente");
}
}
};
task.execute(googleSignInAccount);
}
...
Nesse caso precisamos de uma chamada assincrona via AsyncTask, passamos o GoogleSignInAccount como parâmetro, pois precisamos do email da conta, logo a fundamental importância de requisitarmos o email do usuário na difinição das configurações de nosso GoogleSignInOptions em onCreate().
Se está meio confuso sobre o AsyncTask, veja esse post: AsyncTask no Android, Acesso a Thread Principal de Forma Otimizada. Ou a documentação AsyncTask Android Doc
Terminada a requisição, se o token não for null podemos então chamar nosso accessGoogleLoginData(). Note que se houver a atualização do Firebase para melhor atender ao Google SignIn API, nossa chamada em onActivityResult() ficaria da seguinte maneira (além da remoção do método syncGoogleSignInToken()):
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if( requestCode == RC_SIGN_IN_GOOGLE
&& resultCode == RESULT_OK ){
GoogleSignInResult googleSignInResult = Auth.GoogleSignInApi.getSignInResultFromIntent( data );
GoogleSignInAccount account = googleSignInResult.getSignInAccount();
accessGoogleDataLogin( account.getIdToken() );
}
else{
callbackManager.onActivityResult( requestCode, resultCode, data );
}
}
...
Agora já podemos rodar a APP. Primeiro vamos em "Build", "Rebuild Project". Logo depois, executando o projeto temos:
Clicando em "SIGN IN COM GOOGLE" uma tela de agreement será printada, permita (allow quando em inglês) e então vamos ter o acesso a MainActivity, nossa área de acesso restrita. Se conferirmos nossa base de dados no Firebase temos uma nova conta, agora com o prefixo "google":
Porém ainda temos de ajustar o menu e o logout em MainActivity. O meno para apresentar somente a opção de logout, assim como fazemos quando o usuário se conecta via Facebook. E o Logout tem de ter uma opção para Google logout também.
Vamos começar atualizando a classe User, mais precisamente o método isSocialNetworkLogged(), pois nela temos a verificação de social network somente para Facebook, vamos acrescentar a verificação do Google:
public class User {
...
public boolean isSocialNetworkLogged( Context context ){
retrieveIdSP( context );
return( this.id.contains("facebook") || this.id.contains("google") );
}
...
}
Agora em onCreate() em nossa MainActivity vamos colocar todoa a configuração e conexão ao Google SignIn API novamente, a mesma que em LoginActivity (olha a repetição de código ai):
...
private GoogleAPlClient mGoogleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* PARA GOOGLE LOGOUT */
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("O Web Client ID gerado junto a sua Android Client ID")
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
...
}
...
Temos de implementar novamente a Interface GoogleApiClient.OnConnectionFailedListener, logo nossa MainActivity terá a seguinte configuração com essa Interface:
public class MainActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener {
...
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {}
}
Agora nossa última atualização, em onOptionsItemSelected(), adicionando o Google logout:
...
public boolean onOptionsItemSelected(MenuItem item) {
...
else if(id == R.id.action_logout){
firebase.unauth();
LoginManager.getInstance().logOut();
/* GOOGLE LOGOUT */
if( mGoogleApiClient != null && mGoogleApiClient.isConnected() ){
Auth.GoogleSignInApi.signOut(mGoogleApiClient);
}
finish();
}
return super.onOptionsItemSelected(item);
}
...
Dessa forma terminamos a configuração do Google SignIn API e temos então três formas de login na APP de chat, convencional (email e senha), Facebook e Google. O projeto completo pode ser envcontrado no GitHub: https://github.com/viniciusthiengo/nosso-chate
Abaixo o vídeo com a implementação completa, passo a passo:
Fontes:
Firebase Google Authentication
Google SignIn For Android - Start Integration
Setting Up Google Play Services
Vlw
Comentários Facebook