8

Tôi đang làm theo hướng dẫn này https://developers.google.com/+/mobile/android/recommend để tích hợp nút +1 trong ứng dụng của tôi.Các lớp sau không thể được khởi tạo: - com.google.android.gms.plus.PlusOneButton

Ngay sau khi tôi đặt mã này trong xml tôi nhận sai sót trong GraphicalLayout

<com.google.android.gms.plus.PlusOneButton 
xmlns:plus="http://schemas.android.com/apk/lib/com.google.android.gms.plus" 
android:id="@+id/plus_one_button" 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
plus:size="standard" 
plus:annotation="inline" /> 

Tôi cũng đã cố gắng đưa xmlns:plus="http://schemas.android.com/apk/lib/com.google.android.gms.plus" trong mẹ RelativeLayout, nhưng lỗi tương tự.

The following classes could not be instantiated: 
- com.google.android.gms.plus.PlusOneButton (Open Class, Show Error Log) 
See the Error Log (Window > Show View) for more details. 


java.lang.NullPointerException 
at com.google.android.gms.plus.PlusOneDummyView$zzb.isValid( at com.google.android.gms.plus.PlusOneDummyView.zzrJ( at com.google.android.gms.plus.PlusOneDummyView.<init>( at com.google.android.gms.plus.internal.zzg.zza( at com.google.android.gms.plus.PlusOneButton.zzN( at com.google.android.gms.plus.PlusOneButton.<init>( at sun.reflect.NativeConstructorAccessorImpl.newInstance0( at sun.reflect.NativeConstructorAccessorImpl.newInstance( at sun.reflect.DelegatingConstructorAccessorImpl.newInstance( at java.lang.reflect.Constructor.newInstance( at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.instantiateClass(ProjectCallback.java:438) 
at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.loadView(ProjectCallback.java:190) 
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:207) 
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:132) 
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:806) 
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64) 
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:504) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:385) 

Trợ giúp !!

+0

Bạn đang sử dụng Android Studio? Đăng tệp build.gradle của bạn. –

+0

xin lỗi bằng cách sử dụng Eclipse cho số này –

+0

Ahh! Được. Bạn đã nhập dự án thư viện dịch vụ google play chưa? –

Trả lời

2

Android Studio giải pháp:

Tôi chỉ có một ví dụ đơn giản làm việc bằng cách bắt đầu với mã từ gplus-quickstart, và sau đó thêm một nút +1 bằng cách sử dụng hướng dẫn liên kết trong câu hỏi.

build.gradle phụ thuộc:

dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    compile 'com.android.support:appcompat-v7:22.1.1' 
    compile 'com.google.android.gms:play-services:7.0.0' 
} 

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.plustest.daniel.googleplusone" > 

    <application 
     android:allowBackup="true" 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name=".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> 

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

</manifest> 

tôi thêm com.google.android.gms.plus.PlusOneButton xuống đáy activity_main.xml, mà là dựa trên main_activity.xml từ mã bắt đầu nhanh:

xmlns:plus="http://schemas.android.com/apk/lib/com.google.android.gms.plus" 
      android:id="@+id/plus_one_button" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      plus:size="standard" 
      plus:annotation="inline" /> 

MainActivity.java, với nút +1 được thêm vào .

Lưu ý rằng đối với URL Tôi đã sử dụng trang Google+ của Khoa học máy tính Carnegie Mellon.

public class MainActivity extends FragmentActivity implements 
     ConnectionCallbacks, OnConnectionFailedListener, 
     ResultCallback<LoadPeopleResult>, View.OnClickListener, 
     CheckBox.OnCheckedChangeListener, GoogleApiClient.ServerAuthCodeCallbacks { 

    private static final String TAG = "android-plus-quickstart"; 

    private static final int STATE_DEFAULT = 0; 
    private static final int STATE_SIGN_IN = 1; 
    private static final int STATE_IN_PROGRESS = 2; 

    private static final int RC_SIGN_IN = 0; 

    private static final String SAVED_PROGRESS = "sign_in_progress"; 

    // Client ID for a web server that will receive the auth code and exchange it for a 
    // refresh token if offline access is requested. 
    private static final String WEB_CLIENT_ID = "WEB_CLIENT_ID"; 

    // Base URL for your token exchange server, no trailing slash. 
    private static final String SERVER_BASE_URL = "SERVER_BASE_URL"; 

    // URL where the client should GET the scopes that the server would like granted 
    // before asking for a serverAuthCode 
    private static final String EXCHANGE_TOKEN_URL = SERVER_BASE_URL + "/exchangetoken"; 

    // URL where the client should POST the serverAuthCode so that the server can exchange 
    // it for a refresh token, 
    private static final String SELECT_SCOPES_URL = SERVER_BASE_URL + "/selectscopes"; 


    private int mSignInProgress; 

    // Used to store the PendingIntent most recently returned by Google Play 
    // services until the user clicks 'sign in'. 
    private PendingIntent mSignInIntent; 

    // Used to store the error code most recently returned by Google Play services 
    // until the user clicks 'sign in'. 
    private int mSignInError; 

    // Used to determine if we should ask for a server auth code when connecting the 
    // GoogleApiClient. False by default so that this sample can be used without configuring 
    // a WEB_CLIENT_ID and SERVER_BASE_URL. 
    private boolean mRequestServerAuthCode = false; 

    // Used to mock the state of a server that would receive an auth code to exchange 
    // for a refresh token, If true, the client will assume that the server has the 
    // permissions it wants and will not send an auth code on sign in. If false, 
    // the client will request offline access on sign in and send and new auth code 
    // to the server. True by default because this sample does not implement a server 
    // so there would be nowhere to send the code. 
    private boolean mServerHasToken = true; 

    private SignInButton mSignInButton; 
    private Button mSignOutButton; 
    private Button mRevokeButton; 
    private TextView mStatus; 
    private ListView mCirclesListView; 
    private ArrayAdapter<String> mCirclesAdapter; 
    private ArrayList<String> mCirclesList; 

    //added: 
    private PlusOneButton mPlusOneButton; 
    private String URL = "https://plus.google.com/101009371381835899795/posts"; 

    private static final int PLUS_ONE_REQUEST_CODE = 0; 

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

     mSignInButton = (SignInButton) findViewById(R.id.sign_in_button); 
     mSignOutButton = (Button) findViewById(R.id.sign_out_button); 
     mRevokeButton = (Button) findViewById(R.id.revoke_access_button); 
     mStatus = (TextView) findViewById(R.id.sign_in_status); 
     mCirclesListView = (ListView) findViewById(R.id.circles_list); 

     //added: 
     mPlusOneButton = (PlusOneButton) findViewById(R.id.plus_one_button); 

     // Button listeners 
     mSignInButton.setOnClickListener(this); 
     mSignOutButton.setOnClickListener(this); 
     mRevokeButton.setOnClickListener(this); 

     // CheckBox listeners 
     ((CheckBox) findViewById(R.id.request_auth_code_checkbox)).setOnCheckedChangeListener(this); 
     ((CheckBox) findViewById(R.id.has_token_checkbox)).setOnCheckedChangeListener(this); 

     mCirclesList = new ArrayList<String>(); 
     mCirclesAdapter = new ArrayAdapter<String>(
       this, R.layout.circle_member, mCirclesList); 
     mCirclesListView.setAdapter(mCirclesAdapter); 

     if (savedInstanceState != null) { 
      mSignInProgress = savedInstanceState 
        .getInt(SAVED_PROGRESS, STATE_DEFAULT); 
     } 

     mGoogleApiClient = buildGoogleApiClient(); 
    } 

    private GoogleApiClient buildGoogleApiClient() { 
     // When we build the GoogleApiClient we specify where connected and 
     // connection failed callbacks should be returned, which Google APIs our 
     // app uses and which OAuth 2.0 scopes our app requests. 
     GoogleApiClient.Builder builder = new GoogleApiClient.Builder(this) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(Plus.API, Plus.PlusOptions.builder().build()) 
       .addScope(Plus.SCOPE_PLUS_LOGIN); 

     if (mRequestServerAuthCode) { 
      checkServerAuthConfiguration(); 
      builder = builder.requestServerAuthCode(WEB_CLIENT_ID, this); 
     } 

     return builder.build(); 
    } 

    //added: 
    @Override 
    protected void onResume() { 
     super.onResume(); 
     // Refresh the state of the +1 button each time the activity receives focus. 
     mPlusOneButton.initialize(URL, PLUS_ONE_REQUEST_CODE); 
    } 

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

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

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

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     outState.putInt(SAVED_PROGRESS, mSignInProgress); 
    } 

    @Override 
    public void onClick(View v) { 
     if (!mGoogleApiClient.isConnecting()) { 
      // We only process button clicks when GoogleApiClient is not transitioning 
      // between connected and not connected. 
      switch (v.getId()) { 
       case R.id.sign_in_button: 
        mStatus.setText(R.string.status_signing_in); 
        mSignInProgress = STATE_SIGN_IN; 
        mGoogleApiClient.connect(); 
        break; 
       case R.id.sign_out_button: 
        // We clear the default account on sign out so that Google Play 
        // services will not return an onConnected callback without user 
        // interaction. 
        if (mGoogleApiClient.isConnected()) { 
         Plus.AccountApi.clearDefaultAccount(mGoogleApiClient); 
         mGoogleApiClient.disconnect(); 
        } 
        onSignedOut(); 
        break; 
       case R.id.revoke_access_button: 
        // After we revoke permissions for the user with a GoogleApiClient 
        // instance, we must discard it and create a new one. 
        Plus.AccountApi.clearDefaultAccount(mGoogleApiClient); 
        // Our sample has caches no user data from Google+, however we 
        // would normally register a callback on revokeAccessAndDisconnect 
        // to delete user data so that we comply with Google developer 
        // policies. 
        Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient); 
        mGoogleApiClient = buildGoogleApiClient(); 
        mGoogleApiClient.connect(); 
        break; 
      } 
     } 
    } 

    @Override 
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
     switch (buttonView.getId()) { 
      case R.id.request_auth_code_checkbox: 
       mRequestServerAuthCode = isChecked; 
       buildGoogleApiClient(); 
       if (isChecked) { 
        findViewById(R.id.layout_has_token).setVisibility(View.VISIBLE); 
       } else { 
        findViewById(R.id.layout_has_token).setVisibility(View.INVISIBLE); 
       } 
       break; 
      case R.id.has_token_checkbox: 
       mServerHasToken = isChecked; 
       break; 
     } 
    } 

    /* onConnected is called when our Activity successfully connects to Google 
    * Play services. onConnected indicates that an account was selected on the 
    * device, that the selected account has granted any requested permissions to 
    * our app and that we were able to establish a service connection to Google 
    * Play services. 
    */ 
    @Override 
    public void onConnected(Bundle connectionHint) { 
     // Reaching onConnected means we consider the user signed in. 
     Log.i(TAG, "onConnected"); 

     // Update the user interface to reflect that the user is signed in. 
     mSignInButton.setEnabled(false); 
     mSignOutButton.setEnabled(true); 
     mRevokeButton.setEnabled(true); 

     // Hide the sign-in options, they no longer apply 
     findViewById(R.id.layout_server_auth).setVisibility(View.GONE); 

     // Retrieve some profile information to personalize our app for the user. 
     Person currentUser = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient); 

     mStatus.setText(String.format(
       getResources().getString(R.string.signed_in_as), 
       currentUser.getDisplayName())); 

     Plus.PeopleApi.loadVisible(mGoogleApiClient, null) 
       .setResultCallback(this); 

     // Indicate that the sign in process is complete. 
     mSignInProgress = STATE_DEFAULT; 
    } 

    /* onConnectionFailed is called when our Activity could not connect to Google 
    * Play services. onConnectionFailed indicates that the user needs to select 
    * an account, grant permissions or resolve an error in order to sign in. 
    */ 
    @Override 
    public void onConnectionFailed(ConnectionResult result) { 
     // Refer to the javadoc for ConnectionResult to see what error codes might 
     // be returned in onConnectionFailed. 
     Log.i(TAG, "onConnectionFailed: ConnectionResult.getErrorCode() = " 
       + result.getErrorCode()); 

     if (result.getErrorCode() == ConnectionResult.API_UNAVAILABLE) { 
      // An API requested for GoogleApiClient is not available. The device's current 
      // configuration might not be supported with the requested API or a required component 
      // may not be installed, such as the Android Wear application. You may need to use a 
      // second GoogleApiClient to manage the application's optional APIs. 
      Log.w(TAG, "API Unavailable."); 
     } else if (mSignInProgress != STATE_IN_PROGRESS) { 
      // We do not have an intent in progress so we should store the latest 
      // error resolution intent for use when the sign in button is clicked. 
      mSignInIntent = result.getResolution(); 
      mSignInError = result.getErrorCode(); 

      if (mSignInProgress == STATE_SIGN_IN) { 
       // STATE_SIGN_IN indicates the user already clicked the sign in button 
       // so we should continue processing errors until the user is signed in 
       // or they click cancel. 
       resolveSignInError(); 
      } 
     } 

     // In this sample we consider the user signed out whenever they do not have 
     // a connection to Google Play services. 
     onSignedOut(); 
    } 


    private void resolveSignInError() { 
     if (mSignInIntent != null) { 
      // We have an intent which will allow our user to sign in or 
      // resolve an error. For example if the user needs to 
      // select an account to sign in with, or if they need to consent 
      // to the permissions your app is requesting. 

      try { 
       // Send the pending intent that we stored on the most recent 
       // OnConnectionFailed callback. This will allow the user to 
       // resolve the error currently preventing our connection to 
       // Google Play services. 
       mSignInProgress = STATE_IN_PROGRESS; 
       startIntentSenderForResult(mSignInIntent.getIntentSender(), 
         RC_SIGN_IN, null, 0, 0, 0); 
      } catch (SendIntentException e) { 
       Log.i(TAG, "Sign in intent could not be sent: " 
         + e.getLocalizedMessage()); 
       // The intent was canceled before it was sent. Attempt to connect to 
       // get an updated ConnectionResult. 
       mSignInProgress = STATE_SIGN_IN; 
       mGoogleApiClient.connect(); 
      } 
     } else { 
      // Google Play services wasn't able to provide an intent for some 
      // error types, so we show the default Google Play services error 
      // dialog which may still start an intent on our behalf if the 
      // user can resolve the issue. 
      createErrorDialog().show(); 
     } 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, 
            Intent data) { 
     switch (requestCode) { 
      case RC_SIGN_IN: 
       if (resultCode == RESULT_OK) { 
        // If the error resolution was successful we should continue 
        // processing errors. 
        mSignInProgress = STATE_SIGN_IN; 
       } else { 
        // If the error resolution was not successful or the user canceled, 
        // we should stop processing errors. 
        mSignInProgress = STATE_DEFAULT; 
       } 

       if (!mGoogleApiClient.isConnecting()) { 
        // If Google Play services resolved the issue with a dialog then 
        // onStart is not called so we need to re-attempt connection here. 
        mGoogleApiClient.connect(); 
       } 
       break; 
     } 
    } 

    @Override 
    public void onResult(LoadPeopleResult peopleData) { 
     if (peopleData.getStatus().getStatusCode() == CommonStatusCodes.SUCCESS) { 
      mCirclesList.clear(); 
      PersonBuffer personBuffer = peopleData.getPersonBuffer(); 
      try { 
       int count = personBuffer.getCount(); 
       for (int i = 0; i < count; i++) { 
        mCirclesList.add(personBuffer.get(i).getDisplayName()); 
       } 
      } finally { 
       personBuffer.close(); 
      } 

      mCirclesAdapter.notifyDataSetChanged(); 
     } else { 
      Log.e(TAG, "Error requesting visible circles: " + peopleData.getStatus()); 
     } 
    } 

    private void onSignedOut() { 
     // Update the UI to reflect that the user is signed out. 
     mSignInButton.setEnabled(true); 
     mSignOutButton.setEnabled(false); 
     mRevokeButton.setEnabled(false); 

     // Show the sign-in options 
     findViewById(R.id.layout_server_auth).setVisibility(View.VISIBLE); 

     mStatus.setText(R.string.status_signed_out); 

     mCirclesList.clear(); 
     mCirclesAdapter.notifyDataSetChanged(); 
    } 

    @Override 
    public void onConnectionSuspended(int cause) { 
     // The connection to Google Play services was lost for some reason. 
     // We call connect() to attempt to re-establish the connection or get a 
     // ConnectionResult that we can attempt to resolve. 
     mGoogleApiClient.connect(); 
    } 

    private Dialog createErrorDialog() { 
     if (GooglePlayServicesUtil.isUserRecoverableError(mSignInError)) { 
      return GooglePlayServicesUtil.getErrorDialog(
        mSignInError, 
        this, 
        RC_SIGN_IN, 
        new DialogInterface.OnCancelListener() { 
         @Override 
         public void onCancel(DialogInterface dialog) { 
          Log.e(TAG, "Google Play services resolution cancelled"); 
          mSignInProgress = STATE_DEFAULT; 
          mStatus.setText(R.string.status_signed_out); 
         } 
        }); 
     } else { 
      return new AlertDialog.Builder(this) 
        .setMessage(R.string.play_services_error) 
        .setPositiveButton(R.string.close, 
          new DialogInterface.OnClickListener() { 
           @Override 
           public void onClick(DialogInterface dialog, int which) { 
            Log.e(TAG, "Google Play services error could not be " 
              + "resolved: " + mSignInError); 
            mSignInProgress = STATE_DEFAULT; 
            mStatus.setText(R.string.status_signed_out); 
           } 
          }).create(); 
     } 
    } 

    @Override 
    public CheckResult onCheckServerAuthorization(String idToken, Set<Scope> scopeSet) { 
     Log.i(TAG, "Checking if server is authorized."); 
     Log.i(TAG, "Mocking server has refresh token: " + String.valueOf(mServerHasToken)); 

     if (!mServerHasToken) { 
      // Server does not have a valid refresh token, so request a new 
      // auth code which can be exchanged for one. This will cause the user to see the 
      // consent dialog and be prompted to grant offline access. This callback occurs on a 
      // background thread so it is OK to do synchronous network access. 

      // Ask the server which scopes it would like to have for offline access. This 
      // can be distinct from the scopes granted to the client. By getting these values 
      // from the server, you can change your server's permissions without needing to 
      // recompile the client application. 
      HttpClient httpClient = new DefaultHttpClient(); 
      HttpGet httpGet = new HttpGet(SELECT_SCOPES_URL); 
      HashSet<Scope> serverScopeSet = new HashSet<Scope>(); 

      try { 
       HttpResponse httpResponse = httpClient.execute(httpGet); 
       int responseCode = httpResponse.getStatusLine().getStatusCode(); 
       String responseBody = EntityUtils.toString(httpResponse.getEntity()); 

       if (responseCode == 200) { 
        String[] scopeStrings = responseBody.split(" "); 
        for (String scope : scopeStrings) { 
         Log.i(TAG, "Server Scope: " + scope); 
         serverScopeSet.add(new Scope(scope)); 
        } 
       } else { 
        Log.e(TAG, "Error in getting server scopes: " + responseCode); 
       } 

      } catch (ClientProtocolException e) { 
       Log.e(TAG, "Error in getting server scopes.", e); 
      } catch (IOException e) { 
       Log.e(TAG, "Error in getting server scopes.", e); 
      } 

      // This tells GoogleApiClient that the server needs a new serverAuthCode with 
      // access to the scopes in serverScopeSet. Note that we are not asking the server 
      // if it already has such a token because this is a sample application. In reality, 
      // you should only do this on the first user sign-in or if the server loses or deletes 
      // the refresh token. 
      return CheckResult.newAuthRequiredResult(serverScopeSet); 
     } else { 
      // Server already has a valid refresh token with the correct scopes, no need to 
      // ask the user for offline access again. 
      return CheckResult.newAuthNotRequiredResult(); 
     } 
    } 

    @Override 
    public boolean onUploadServerAuthCode(String idToken, String serverAuthCode) { 
     // Upload the serverAuthCode to the server, which will attempt to exchange it for 
     // a refresh token. This callback occurs on a background thread, so it is OK 
     // to perform synchronous network access. Returning 'false' will fail the 
     // GoogleApiClient.connect() call so if you would like the client to ignore 
     // server failures, always return true. 
     HttpClient httpClient = new DefaultHttpClient(); 
     HttpPost httpPost = new HttpPost(EXCHANGE_TOKEN_URL); 

     try { 
      List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1); 
      nameValuePairs.add(new BasicNameValuePair("serverAuthCode", serverAuthCode)); 
      httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 

      HttpResponse response = httpClient.execute(httpPost); 
      int statusCode = response.getStatusLine().getStatusCode(); 
      final String responseBody = EntityUtils.toString(response.getEntity()); 
      Log.i(TAG, "Code: " + statusCode); 
      Log.i(TAG, "Resp: " + responseBody); 

      // Show Toast on UI Thread 
      runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
        Toast.makeText(MainActivity.this, responseBody, Toast.LENGTH_LONG).show(); 
       } 
      }); 
      return (statusCode == 200); 
     } catch (ClientProtocolException e) { 
      Log.e(TAG, "Error in auth code exchange.", e); 
      return false; 
     } catch (IOException e) { 
      Log.e(TAG, "Error in auth code exchange.", e); 
      return false; 
     } 
    } 

    private void checkServerAuthConfiguration() { 
     // Check that the server URL is configured before allowing this box to 
     // be unchecked 
     if ("WEB_CLIENT_ID".equals(WEB_CLIENT_ID) || 
       "SERVER_BASE_URL".equals(SERVER_BASE_URL)) { 
      Log.w(TAG, "WEB_CLIENT_ID or SERVER_BASE_URL configured incorrectly."); 
      Dialog dialog = new AlertDialog.Builder(this) 
        .setMessage(getString(R.string.configuration_error)) 
        .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() { 
         @Override 
         public void onClick(DialogInterface dialog, int which) { 
          dialog.dismiss(); 
         } 
        }) 
        .create(); 

      dialog.show(); 
     } 
    } 
} 

Kết quả sau khi đăng nhập và nhấp vào nút +1:

Plus One Button Result

+0

Mã của bạn trả về kết nốiĐược đóng bằng mã lỗi 17. Bạn có biết nguyên nhân trực tiếp của điều này không? Tôi có thể bị thiếu quyền. – portfoliobuilder

+1

@portfoliobuilder Thật khó để nói mà không nhìn thấy mã của bạn và thiết lập dự án của bạn. Lưu ý rằng đây chủ yếu là mã khởi động nhanh từ Google, tôi vừa thực hiện một sửa đổi nhỏ để thêm nút +1. Nếu bạn chưa làm như vậy, hãy làm theo các hướng dẫn ban đầu tại đây: https://developers.google.com/+/mobile/android/getting-started –

+0

Hey Daniel, tôi đã nhập mã khởi động nhanh và chỉ chạy dự án. Bất cứ khi nào tôi bấm vào nút signin tôi nhận được errorCode 17. Tôi nhận thấy rằng những gì bạn đăng trực tiếp từ bản demo đó như bạn đã đề cập. Tôi đã hy vọng bạn biết điều gì đó. – portfoliobuilder

1

Thêm compile 'com.google.android.gms:play-services-plus:10.0.1' để gradle của ứng dụng của bạn

Các vấn đề liên quan