2014-04-24 18 views
16

Da Android 4.2.2 è possibile eseguire i servizi Google sull'emulatore Android. Attualmente sto creando un'app per Android e ho realizzato un progetto di test per vedere se riesco a ottenere l'accesso e la disconnessione di Google+ per funzionare.: questa app non verrà eseguita senza i servizi Google Play

ho seguito il seguente tutorial: http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/

Con info extra usato dai seguenti tutorial/Siti:

Questa generato il codice seguente:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.example.testproject_gmaillogin" 
    android:versionCode="1" 
    android:versionName="1.0" > 

    <uses-sdk 
     android:minSdkVersion="9" 
     android:targetSdkVersion="19" /> 

    <uses-permission android:name="android.permission.INTERNET" /> 
    <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 
    <uses-permission android:name="android.permission.USE_CREDENTIALS" /> 

    <application 
     android:allowBackup="true" 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 

     <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> 

     <activity 
      android:name="com.example.testproject_gmaillogin.MainActivity" 
      android:label="@string/app_name" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
    </application> 

</manifest> 

strings.xml:

<?xml version="1.0" encoding="utf-8"?> 
<resources> 

    <string name="app_name">TestProject_GmailLogin</string> 
    <string name="action_settings">Settings</string> 

    <string name="profile_pic_description">Google Profile Picture</string> 
    <string name="btn_logout_from_google">Logout from Google</string> 
    <string name="btn_revoke_access">Revoke Access</string> 

</resources> 

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" 
    android:padding="16dp" 
    tools:context=".MainActivity" > 

    <LinearLayout 
     android:id="@+id/profile_layout" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="20dp" 
     android:orientation="horizontal" 
     android:weightSum="3" 
     android:visibility="gone"> 

     <ImageView 
      android:id="@+id/img_profile_pic" 
      android:contentDescription="@string/profile_pic_description" 
      android:layout_width="80dp" 
      android:layout_height="wrap_content" 
      android:layout_weight="1"/> 

     <LinearLayout 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginLeft="10dp" 
      android:orientation="vertical" 
      android:layout_weight="2" > 

      <TextView 
       android:id="@+id/txt_name" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:padding="5dp" 
       android:textSize="20sp" /> 

      <TextView 
       android:id="@+id/txt_email" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:padding="5dp" 
       android:textSize="18sp" /> 
     </LinearLayout> 
    </LinearLayout> 

    <com.google.android.gms.common.SignInButton 
     android:id="@+id/btn_sign_in" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="20dp"/> 

    <Button 
     android:id="@+id/btn_sign_out" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:text="@string/btn_logout_from_google" 
     android:visibility="gone" 
     android:layout_marginBottom="10dp"/> 

    <Button 
     android:id="@+id/btn_revoke_access" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:text="@string/btn_revoke_access" 
     android:visibility="gone" /> 

</LinearLayout> 

MainActivity.java:

package com.example.testproject_gmaillogin; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.GooglePlayServicesUtil; 
import com.google.android.gms.common.SignInButton; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; 
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; 
import com.google.android.gms.common.api.ResultCallback; 
import com.google.android.gms.common.api.Status; 
import com.google.android.gms.plus.Plus; 
import com.google.android.gms.plus.model.people.Person; 

import android.support.v7.app.ActionBarActivity; 
import android.content.Intent; 
import android.content.IntentSender.SendIntentException; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.ImageView; 
import android.widget.LinearLayout; 
import android.widget.TextView; 
import android.widget.Toast; 

public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, OnClickListener 
{ 
    // Logcat tag 
    private static final String TAG = "MainActivity"; 

    // Profile pix image size in pixels 
    private static final int PROFILE_PIC_SIZE = 400; 

    // Request code used to invoke sign in user interactions 
    private static final int RC_SIGN_IN = 0; 

    // Client used to interact with Google APIs 
    private GoogleApiClient mGoogleApiClient; 

    // A flag indicating that a PendingIntent is in progress and prevents 
    // us from starting further intents 
    private boolean mIntentInProgress; 

    // Track whether the sign-in button has been clicked so that we know to resolve 
    // all issues preventing sign-in without waiting 
    private boolean mSignInClicked; 

    // Store the connection result from onConnectionFailed callbacks so that we can 
    // resolve them when the user clicks sign-in 
    private ConnectionResult mConnectionResult; 

    // The used UI-elements 
    private SignInButton btnSignIn; 
    private Button btnSignOut, btnRevokeAccess; 
    private ImageView imgProfilePic; 
    private TextView txtName, txtEmail; 
    private LinearLayout profileLayout; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     // Get the UI-elements 
     btnSignIn = (SignInButton) findViewById(R.id.btn_sign_in); 
     btnSignOut = (Button) findViewById(R.id.btn_sign_out); 
     btnRevokeAccess = (Button) findViewById(R.id.btn_revoke_access); 
     imgProfilePic = (ImageView) findViewById(R.id.img_profile_pic); 
     txtName = (TextView) findViewById(R.id.txt_name); 
     txtEmail = (TextView) findViewById(R.id.txt_email); 
     profileLayout = (LinearLayout) findViewById(R.id.profile_layout); 

     // Set the Button onClick-listeners 
     btnSignIn.setOnClickListener(this); 
     btnSignOut.setOnClickListener(this); 
     btnRevokeAccess.setOnClickListener(this); 

     mGoogleApiClient = new GoogleApiClient.Builder(this) 
      .addConnectionCallbacks(this) 
      .addOnConnectionFailedListener(this) 
      .addApi(Plus.API, null) 
      .addScope(Plus.SCOPE_PLUS_LOGIN) 
      .build(); 
    } 

    @Override 
    protected void onStart(){ 
     super.onStart(); 
     mGoogleApiClient.connect(); 
    } 

    @Override 
    protected void onStop(){ 
     super.onStop(); 

     if(mGoogleApiClient.isConnected()) 
      mGoogleApiClient.disconnect(); 
    } 

    @Override 
    public void onClick(View view){ 
     switch(view.getId()){ 
      case R.id.btn_sign_in: 
       signInWithGPlus(); 
       break; 
      case R.id.btn_sign_out: 
       signOutFromGPlus(); 
       break; 
      case R.id.btn_revoke_access: 
       revokeGPlusAccess(); 
       break; 
     } 
    } 

    @Override 
    public void onConnectionFailed(ConnectionResult result) { 
     if(!result.hasResolution()){ 
      GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, 0).show(); 
      return; 
     } 

     if(!mIntentInProgress){ 
      // Store the ConnectionResult so that we can use it later when the user clicks 'sign-in' 
      mConnectionResult = result; 

      if(mSignInClicked) 
       // The user has already clicked 'sign-in' so we attempt to resolve all 
       // errors until the user is signed in, or they cancel 
       resolveSignInErrors(); 
     } 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int responseCode, Intent intent){ 
     if(requestCode == RC_SIGN_IN && responseCode == RESULT_OK) 
      SignInClicked = true; 

      mIntentInProgress = false; 

      if(!mGoogleApiClient.isConnecting()) 
       mGoogleApiClient.connect(); 
     } 
    } 

    @Override 
    public void onConnected(Bundle connectionHint) { 
     mSignInClicked = false; 
     Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show(); 

     // Get all the user's information 
     getProfileInformation(); 

     // Update the UI after sign-in 
     updateUI(true); 
    } 

    @Override 
    public void onConnectionSuspended(int cause){ 
     mGoogleApiClient.connect(); 
     updateUI(false); 
    } 

    // Updating the UI, showing/hiding buttons and profile layout 
    private void updateUI(boolean isSignedIn){ 
     if(isSignedIn){ 
      btnSignIn.setVisibility(View.GONE); 
      btnSignOut.setVisibility(View.VISIBLE); 
      btnRevokeAccess.setVisibility(View.VISIBLE); 
      profileLayout.setVisibility(View.VISIBLE); 
     } 
     else{ 
      btnSignIn.setVisibility(View.VISIBLE); 
      btnSignOut.setVisibility(View.GONE); 
      btnRevokeAccess.setVisibility(View.GONE); 
      profileLayout.setVisibility(View.GONE); 
     } 
    } 

    // Sign-in into Google 
    private void signInWithGPlus(){ 
     if(!mGoogleApiClient.isConnecting()){ 
      mSignInClicked = true; 
      resolveSignInErrors(); 
     } 
    } 

    // Method to resolve any sign-in errors 
    private void resolveSignInErrors(){ 
     if(mConnectionResult.hasResolution()){ 
      try{ 
       mIntentInProgress = true; 

       //Toast.makeText(this, "Resolving Sign-in Errors", Toast.LENGTH_SHORT).show(); 

       mConnectionResult.startResolutionForResult(this, RC_SIGN_IN); 
      } 
      catch(SendIntentException e){ 
       // The intent was cancelled before it was sent. Return to the default 
       // state and attempt to connect to get an updated ConnectionResult 
       mIntentInProgress = false; 
       mGoogleApiClient.connect(); 
      } 
     } 
    } 

    // Fetching the user's infromation name, email, profile pic 
    private void getProfileInformation(){ 
     try{ 
      if(Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null){ 
       Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient); 
       String personName = currentPerson.getDisplayName(); 
       String personPhotoUrl = currentPerson.getImage().getUrl(); 
       String personGooglePlusProfile = currentPerson.getUrl(); 
       String personEmail = Plus.AccountApi.getAccountName(mGoogleApiClient); 

       Log.e(TAG, "Name: " + personName + ", " 
         + "plusProfile: " + personGooglePlusProfile + ", " 
         + "email: " + personEmail + ", " 
         + "image: " + personPhotoUrl); 

       txtName.setText(personName); 
       txtEmail.setText(personEmail); 

       // by default the profile url gives 50x50 px image, 
       // but we can replace the value with whatever dimension we 
       // want by replacing sz=X 
       personPhotoUrl = personPhotoUrl.substring(0, personPhotoUrl.length() - 2) 
         + PROFILE_PIC_SIZE; 

       new LoadProfileImage(imgProfilePic).execute(personPhotoUrl); 
      } 
      else{ 
       Toast.makeText(getApplicationContext(), "Person information is null", Toast.LENGTH_LONG).show(); 
      } 
     } 
     catch(Exception ex){ 
      ex.printStackTrace(); 
     } 
    } 

    // Sign-out from Google 
    private void signOutFromGPlus(){ 
     if(mGoogleApiClient.isConnected()){ 
      Plus.AccountApi.clearDefaultAccount(mGoogleApiClient); 
      mGoogleApiClient.disconnect(); 
      mGoogleApiClient.connect(); 
      updateUI(false); 
     } 
    } 

    // Revoking access from Google 
    private void revokeGPlusAccess(){ 
     if(mGoogleApiClient.isConnected()){ 
      Plus.AccountApi.clearDefaultAccount(mGoogleApiClient); 
      Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient) 
       .setResultCallback(new ResultCallback<Status>(){ 
        @Override 
        public void onResult(Status s){ 
         Log.e(TAG, "User access revoked!"); 
         mGoogleApiClient.connect(); 
         updateUI(false); 
        } 
       }); 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 
     if (id == R.id.action_settings) 
      return true; 

     return super.onOptionsItemSelected(item); 
    } 
} 

LoadProfileImage.java:

package com.example.testproject_gmaillogin; 

import java.io.InputStream; 

import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.os.AsyncTask; 
import android.util.Log; 
import android.widget.ImageView; 

/** 
* Background async task to load user profile picture from url 
**/ 
public class LoadProfileImage extends AsyncTask<String, Void, Bitmap> { 
    private ImageView bmImage; 

    public LoadProfileImage(ImageView bmImage){ 
     this.bmImage = bmImage; 
    } 

    @Override 
    protected Bitmap doInBackground(String... urls){ 
     String urlDisplay = urls[0]; 
     Bitmap mIcon11 = null; 
     try{ 
      InputStream in = new java.net.URL(urlDisplay).openStream(); 
      mIcon11 = BitmapFactory.decodeStream(in); 
     } 
     catch(Exception ex){ 
      Log.e("Error", ex.getMessage()); 
      ex.printStackTrace(); 
     } 
     return mIcon11; 
    } 

    @Override 
    protected void onPostExecute(Bitmap result){ 
     bmImage.setImageBitmap(result); 
    } 
} 

Gli altri passi che ho fatto erano:

A https://console.developers.google.com/project Ho creato un progetto con:

Google+ API on:

Google+ API on

E un ID cliente creato con la corretta SHA1 e esattamente lo stesso spazio dei nomi come il progetto:

And a Client ID created with the correct SHA1

In Eclipse:

Ho installato la libreria di google-play-servizi:

Google-play services installed

Ed è aggiunto alla il progetto:

Google-play services library added (2) Google-play services library added (2)

Ho anche creato un emulatore con versione 4.4.2:

I've also created an Emulator with version 4.4.2

Ma quando faccio funzionare l'applicazione io ottenere il seguente errore e questo errore continua a comparire quando si fa clic sul pulsante:

Get Google Play services Error

Qualcuno ha idea di dove va storto? Grazie in anticipo per le risposte.

+0

Nizza domanda :) – shkschneider

risposta

14

Ok, dopo aver provato alcune cose si è scoperto che avevo una ultima opzione non correttamente controllato, che non è stato menzionato da nessuna parte nel/i tutorial ..

Invece di Android 4.4.2 come Target di creazione progetto & Target emulatore, Ho selezionato API Google 4.4.2. Ora non ricevo più l'errore dei servizi di Google Play.

io capisco un NullPointerException, però, ma almeno posso continua ..;)

EDIT: Risolto il NullPointerException e modificato il codice nel mio post originale. Tutto funziona come dovrebbe ora e spero che questo post aiuti altre persone con gli stessi (o altri) errori utilizzando l'accesso ai servizi di gioco di google utilizzando un emulatore Android.

Solution Error Solution Error Emulator

+1

Puoi spiegare come arrivare alla schermata Target di progetto, quindi posso verificare che il mio progetto stia utilizzando la lib di google play services? –

+0

@TonyWickham Non ho Eclipse sul mio nuovo laptop, quindi non posso verificarlo, ma credo che fosse il mouse destro sul progetto -> Proprietà -> scheda Android sulla sinistra. –

+0

Ah stavi usando Eclipse - Sto usando Android Studio che spiega perché sembra diverso. –

8

Provare a utilizzare il livello di API Goole API 19 come bersaglio emulatore invece che a livello di API normale 19.

+0

quando stavo facendo le immagini della domanda che ho provato a cambiare l'Android 4.4.2 per Google API 4.4.2 nel target Genera, e funziona davvero. (Ho appena finito la mia domanda per aiutare altre persone con gli stessi problemi, dal momento che ho visto alcuni post con questo errore.) –

+1

Ho avuto anche questo poche volte, quindi non ho nemmeno letto l'intera domanda e ho risposto correttamente dopo aver visto il nome dell'obiettivo dello screenshot dell'emulatore. ' –

+1

Hai salvato la mia giornata, mi chiedo perché queste informazioni non sono ben documentate. – user2812866

Problemi correlati