sigue servicios services play juegos gratis google funcionar descargar descarga actualizar android android-emulator google-plus google-play-services

android - servicios - play store no descarga



Emulador de Android: esta aplicación no se ejecutará sin los servicios de Google Play (2)

Desde Android 4.2.2 es posible ejecutar los servicios de Google en el emulador de Android. Actualmente estoy creando una aplicación para Android y un proyecto de prueba para ver si puedo obtener el inicio y cierre de sesión de Google+ para que funcione.

He seguido el siguiente tutorial: http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/

Con información extra utilizada de los siguientes tutoriales / sitios:

Esto generó el siguiente código:

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); } }

Los otros pasos que hice fueron:

En https://console.developers.google.com/project he creado un proyecto con:

API de Google+ en:

Y un ID de cliente creado con el SHA1 correcto y exactamente el mismo espacio de nombres que el proyecto:

En Eclipse:

He instalado la biblioteca de servicios de Google Play:

Y lo agregó al proyecto:

También he creado un emulador con la versión 4.4.2:

Pero cuando ejecuto la aplicación, aparece el siguiente error, y este error sigue apareciendo cuando hago clic en el botón:

¿Alguien tiene alguna idea de dónde va mal? Gracias de antemano por las respuestas.


Intente utilizar el nivel 19 de API de Goole API como destino del emulador en lugar del nivel 19 de API normal.


Ok, después de probar algunas cosas, resultó que tenía una última opción que no estaba marcada correctamente, que no se mencionó en ninguna parte del tutorial (s).

En lugar de Android 4.4.2 como Project Build Target & Emulator Target, seleccioné las API de Google 4.4.2. Ahora ya no me sale el error de los servicios de Google Play.

Sin embargo, sí obtengo una NullPointerException, pero al menos puedo continuar ...;)

EDITAR: Se corrigió la excepción NullPointerException y se modificó el código en mi publicación original. Todo funciona como debería ahora y espero que esta publicación ayude a otras personas con los mismos (u otros) errores que utilizan los servicios de Google Play para iniciar sesión con un emulador de Android.