簡體   English   中英

Android谷歌+登錄片段

[英]Android google+ login in a fragment

目前我正在嘗試使用片段實現谷歌+登錄,以便我可以在不同的活動中使用它。 我已經創建了這樣的片段

public class GoogleSignUpFragment extends Fragment implements
    ConnectionCallbacks, OnConnectionFailedListener, OnClickListener {

// PlusClient Variables
private static final int REQUEST_CODE_RESOLVE_ERR = 9000;
private ProgressDialog mConnectionProgressDialog;
private PlusClient mPlusClient;
private ConnectionResult mConnectionResult;

@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);

    mPlusClient = new PlusClient.Builder(getActivity()
            .getApplicationContext(), this, this)
            .setActions("http://schemas.google.com/AddActivity",
                    "http://schemas.google.com/BuyActivity")
            .setScopes(Scopes.PLUS_LOGIN, Scopes.PLUS_PROFILE).build();

    getActivity().findViewById(R.id.sign_in_button)
            .setOnClickListener(this);

    // Progress bar to be displayed if the connection failure is not
    // resolved.
    mConnectionProgressDialog = new ProgressDialog(getActivity());
    mConnectionProgressDialog.setMessage("Signing in...");

}

@Override
public void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
    mPlusClient.connect();
}

@Override
public void onStop() {
    // TODO Auto-generated method stub
    super.onStop();
    mPlusClient.disconnect();
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (requestCode == REQUEST_CODE_RESOLVE_ERR
            && resultCode == Activity.RESULT_OK) {
        mConnectionResult = null;
        mPlusClient.connect();
    }
}

@Override
public void onClick(View view) {
    if (view.getId() == R.id.sign_in_button && !mPlusClient.isConnected()) {
        if (mConnectionResult == null) {
            mConnectionProgressDialog.show();

        } else {
            try {
                mConnectionResult.startResolutionForResult(getActivity(),
                        REQUEST_CODE_RESOLVE_ERR);
            } catch (SendIntentException e) {
                // Try connecting again.
                mConnectionResult = null;
                mPlusClient.connect();
            }
        }
    }
}

@Override
public void onConnectionFailed(ConnectionResult result) {
    if (mConnectionProgressDialog.isShowing()) {
        // The user clicked the sign-in button already. Start to resolve
        // connection errors. Wait until onConnected() to dismiss the
        // connection dialog.
        if (result.hasResolution()) {
            try {
                result.startResolutionForResult(getActivity(),
                        REQUEST_CODE_RESOLVE_ERR);
            } catch (SendIntentException e) {
                mPlusClient.connect();
            }
        }
    }

}

@Override
public void onConnected(Bundle connectionHint) {
    mConnectionProgressDialog.dismiss();
    Toast.makeText(getActivity().getApplicationContext(),
            "User is connected!", Toast.LENGTH_LONG).show();
    Intent intent = new Intent(getActivity().getApplicationContext(),
            LogoutActivity.class);
    startActivity(intent);

}

@Override
public void onDisconnected() {
    // TODO Auto-generated method stub

}

}

我正在使用官方教程,然后在片段中重新使用它。

在主要活動中,我有:

FragmentManager fragmentManager = getSupportFragmentManager();
    android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    googleSignUpFragment = new GoogleSignUpFragment();
    fragmentTransaction.add(R.id.detailFragment, googleSignUpFragment);
    fragmentTransaction.commit();

但是,每當我單擊登錄按鈕時,只有一個對話框顯示“正在登錄...”,沒有其他任何事情發生。 任何想法如何解決這個問題? 它在正常活動中工作得很好。

謝謝你的幫助。

@編輯。 我已經發現onConnectionFailed方法沒有啟動,所以看起來沒有onActivityResult,但是當我直接將mPlusClient.connect()置於我的點擊中時它起作用,但我覺得這不是一個正確的方法。 也許問題是onConnectionFailed沒有beign啟動

@Edit 2.現在我已經發現問題似乎與dialog.isShowing()一樣,當我刪除該行時,帳戶選擇器正在顯示,在啟動后,嘗試使用bool值,我點擊后更改但是這個不起作用......

為了在官方教程中使用Fragments,您必須知道onActivityResult方法將在擁有Fragment的Activity中調用。

然后在片段中實現public connect()方法,在活動的onActivityResult中調用plus.connect();而不是調用plus.connect(); 直。 這樣turotial將使用片段,完全按照預期的方式使用Activity。 如果您需要詳細示例,我可以將編輯添加到此答案中。

我建議使用Activity而不是Fragment,因為代碼模塊化,更容易實現和處理on鍵后退按鈕,以防止進入應用程序等。

對於想要在Android Studio中查看示例的用戶,只需創建一個LoginActivity,選中“Include Google+ sig in”。
如果您正在使用Fragment,只需在Activity中添加對onActivityResult的調用,如下所示:

FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.findFragmentById(R.id.login_fragment_leftPanel).onActivityResult(requestCode, resultCode, data);

在AS創建的示例中,您不應在活動中實現抽象函數...只需在片段中使用。 使用com.google.android.gms:play-services:6.1.11為我工作,如果您需要代碼,只需要它。

用戶代碼@SHADOW

Sure Shadow,我所做的是使以下代碼有效。 之后,我為我的項目修改了它。
他們使用2類(PlusBaseActivity和LoginActivity)。

/ **
*登錄屏幕,通過電子郵件/密碼和Google+登錄提供登錄。
* * ************重要設置說明:************
*要讓Google+登錄使用您的應用,您必須先訪問:
* https://developers.google.com/+/mobile/android/getting-started#step_1_enable_the_google_api
*並按照“步驟1”中的步驟為您的包創建OAuth 2.0客戶端。
* /

public class LoginActivity extends PlusBaseActivity implements LoaderCallbacks<Cursor>{

/**
 * A dummy authentication store containing known user names and passwords.
 * TODO: remove after connecting to a real authentication system.
 */
private static final String[] DUMMY_CREDENTIALS = new String[]{
        "foo@example.com:hello", "bar@example.com:world"
};
/**
 * Keep track of the login task to ensure we can cancel it if requested.
 */
private UserLoginTask mAuthTask = null;

// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
private View mProgressView;
private View mEmailLoginFormView;
private SignInButton mPlusSignInButton;
private View mSignOutButtons;
private View mLoginFormView;

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

    // Find the Google+ sign in button.
    mPlusSignInButton = (SignInButton) findViewById(R.id.plus_sign_in_button);
    if (supportsGooglePlayServices()) {
        // Set a listener to connect the user when the G+ button is clicked.
        mPlusSignInButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                signIn();
            }
        });
    } else {
        // Don't offer G+ sign in if the app's version is too low to support Google Play
        // Services.
        mPlusSignInButton.setVisibility(View.GONE);
        return;
    }

    // Set up the login form.
    mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
    populateAutoComplete();

    mPasswordView = (EditText) findViewById(R.id.password);
    mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
            if (id == R.id.login || id == EditorInfo.IME_NULL) {
                attemptLogin();
                return true;
            }
            return false;
        }
    });

    Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
    mEmailSignInButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            attemptLogin();
        }
    });

    mLoginFormView = findViewById(R.id.login_form);
    mProgressView = findViewById(R.id.login_progress);
    mEmailLoginFormView = findViewById(R.id.email_login_form);
    mSignOutButtons = findViewById(R.id.plus_sign_out_buttons);
}

private void populateAutoComplete() {
    getLoaderManager().initLoader(0, null, this);
}


/**
 * Attempts to sign in or register the account specified by the login form.
 * If there are form errors (invalid email, missing fields, etc.), the
 * errors are presented and no actual login attempt is made.
 */
public void attemptLogin() {
    if (mAuthTask != null) {
        return;
    }

    // Reset errors.
    mEmailView.setError(null);
    mPasswordView.setError(null);

    // Store values at the time of the login attempt.
    String email = mEmailView.getText().toString();
    String password = mPasswordView.getText().toString();

    boolean cancel = false;
    View focusView = null;


    // Check for a valid password, if the user entered one.
    if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
        mPasswordView.setError(getString(R.string.error_invalid_password));
        focusView = mPasswordView;
        cancel = true;
    }

    // Check for a valid email address.
    if (TextUtils.isEmpty(email)) {
        mEmailView.setError(getString(R.string.error_field_required));
        focusView = mEmailView;
        cancel = true;
    } else if (!isEmailValid(email)) {
        mEmailView.setError(getString(R.string.error_invalid_email));
        focusView = mEmailView;
        cancel = true;
    }

    if (cancel) {
        // There was an error; don't attempt login and focus the first
        // form field with an error.
        focusView.requestFocus();
    } else {
        // Show a progress spinner, and kick off a background task to
        // perform the user login attempt.
        showProgress(true);
        mAuthTask = new UserLoginTask(email, password);
        mAuthTask.execute((Void) null);
    }
}
private boolean isEmailValid(String email) {
    //TODO: Replace this with your own logic
    return email.contains("@");
}

private boolean isPasswordValid(String password) {
    //TODO: Replace this with your own logic
    return password.length() > 4;
}

/**
 * Shows the progress UI and hides the login form.
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
public void showProgress(final boolean show) {
    // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
    // for very easy animations. If available, use these APIs to fade-in
    // the progress spinner.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);

        mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
        mLoginFormView.animate().setDuration(shortAnimTime).alpha(
                show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
            }
        });

        mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
        mProgressView.animate().setDuration(shortAnimTime).alpha(
                show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
            }
        });
    } else {
        // The ViewPropertyAnimator APIs are not available, so simply show
        // and hide the relevant UI components.
        mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
        mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
    }
}

@Override
protected void onPlusClientSignIn() {
    //Set up sign out and disconnect buttons.
    Button signOutButton = (Button) findViewById(R.id.plus_sign_out_button);
    signOutButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            signOut();
        }
    });
    Button disconnectButton = (Button) findViewById(R.id.plus_disconnect_button);
    disconnectButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            revokeAccess();
        }
    });
}

@Override
protected void onPlusClientBlockingUI(boolean show) {
    showProgress(show);
}

@Override
protected void updateConnectButtonState() {
    //TODO: Update this logic to also handle the user logged in by email.
    boolean connected = getPlusClient().isConnected();

    mSignOutButtons.setVisibility(connected ? View.VISIBLE : View.GONE);
    mPlusSignInButton.setVisibility(connected ? View.GONE : View.VISIBLE);
    mEmailLoginFormView.setVisibility(connected ? View.GONE : View.VISIBLE);
}

@Override
protected void onPlusClientRevokeAccess() {
    // TODO: Access to the user's G+ account has been revoked.  Per the developer terms, delete
    // any stored user data here.
}

@Override
protected void onPlusClientSignOut() {

}

/**
 * Check if the device supports Google Play Services.  It's best
 * practice to check first rather than handling this as an error case.
 *
 * @return whether the device supports Google Play Services
 */
private boolean supportsGooglePlayServices() {
    return GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) ==
            ConnectionResult.SUCCESS;
}

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    return new CursorLoader(this,
            // Retrieve data rows for the device user's 'profile' contact.
            Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
                    ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,

            // Select only email addresses.
            ContactsContract.Contacts.Data.MIMETYPE +
                    " = ?", new String[]{ContactsContract.CommonDataKinds.Email
                                                                 .CONTENT_ITEM_TYPE},

            // Show primary email addresses first. Note that there won't be
            // a primary email address if the user hasn't specified one.
            ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
}

@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
    List<String> emails = new ArrayList<String>();
    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
        emails.add(cursor.getString(ProfileQuery.ADDRESS));
        cursor.moveToNext();
    }

    addEmailsToAutoComplete(emails);
}

@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {

}

private interface ProfileQuery {
    String[] PROJECTION = {
            ContactsContract.CommonDataKinds.Email.ADDRESS,
            ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
    };

    int ADDRESS = 0;
    int IS_PRIMARY = 1;
}


private void addEmailsToAutoComplete(List<String> emailAddressCollection) {
    //Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
    ArrayAdapter<String> adapter =
            new ArrayAdapter<String>(LoginActivity.this,
                    android.R.layout.simple_dropdown_item_1line, emailAddressCollection);

    mEmailView.setAdapter(adapter);
}

/**
 * Represents an asynchronous login/registration task used to authenticate
 * the user.
 */
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {

    private final String mEmail;
    private final String mPassword;

    UserLoginTask(String email, String password) {
        mEmail = email;
        mPassword = password;
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        // TODO: attempt authentication against a network service.

        try {
            // Simulate network access.
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            return false;
        }

        for (String credential : DUMMY_CREDENTIALS) {
            String[] pieces = credential.split(":");
            if (pieces[0].equals(mEmail)) {
                // Account exists, return true if the password matches.
                return pieces[1].equals(mPassword);
            }
        }

        // TODO: register the new account here.
        return true;
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        mAuthTask = null;
        showProgress(false);

        if (success) {
            finish();
        } else {
            mPasswordView.setError(getString(R.string.error_incorrect_password));
            mPasswordView.requestFocus();
        }
    }

    @Override
    protected void onCancelled() {
        mAuthTask = null;
        showProgress(false);
    }
}

}

public abstract class PlusBaseActivity extends Activity
    implements GooglePlayServicesClient.ConnectionCallbacks,
    GooglePlayServicesClient.OnConnectionFailedListener {

private static final String TAG = PlusBaseActivity.class.getSimpleName();

// A magic number we will use to know that our sign-in error resolution activity has completed
private static final int OUR_REQUEST_CODE = 49404;

// A flag to stop multiple dialogues appearing for the user
private boolean mAutoResolveOnFail;

// A flag to track when a connection is already in progress
public boolean mPlusClientIsConnecting = false;

// This is the helper object that connects to Google Play Services.
private PlusClient mPlusClient;

// The saved result from {@link #onConnectionFailed(ConnectionResult)}.  If a connection
// attempt has been made, this is non-null.
// If this IS null, then the connect method is still running.
private ConnectionResult mConnectionResult;


/**
 * Called when the {@link PlusClient} revokes access to this app.
 */
protected abstract void onPlusClientRevokeAccess();

/**
 * Called when the PlusClient is successfully connected.
 */
protected abstract void onPlusClientSignIn();

/**
 * Called when the {@link PlusClient} is disconnected.
 */
protected abstract void onPlusClientSignOut();

/**
 * Called when the {@link PlusClient} is blocking the UI.  If you have a progress bar widget,
 * this tells you when to show or hide it.
 */
protected abstract void onPlusClientBlockingUI(boolean show);

/**
 * Called when there is a change in connection state.  If you have "Sign in"/ "Connect",
 * "Sign out"/ "Disconnect", or "Revoke access" buttons, this lets you know when their states
 * need to be updated.
 */
protected abstract void updateConnectButtonState();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Initialize the PlusClient connection.
    // Scopes indicate the information about the user your application will be able to access.
    mPlusClient =
            new PlusClient.Builder(this, this, this).setScopes(Scopes.PLUS_LOGIN,
                    Scopes.PLUS_ME).build();
}

/**
 * Try to sign in the user.
 */
public void signIn() {
    if (!mPlusClient.isConnected()) {
        // Show the dialog as we are now signing in.
        setProgressBarVisible(true);
        // Make sure that we will start the resolution (e.g. fire the intent and pop up a
        // dialog for the user) for any errors that come in.
        mAutoResolveOnFail = true;
        // We should always have a connection result ready to resolve,
        // so we can start that process.
        if (mConnectionResult != null) {
            startResolution();
        } else {
            // If we don't have one though, we can start connect in
            // order to retrieve one.
            initiatePlusClientConnect();
        }
    }

    updateConnectButtonState();
}

/**
 * Connect the {@link PlusClient} only if a connection isn't already in progress.  This will
 * call back to {@link #onConnected(android.os.Bundle)} or
 * {@link #onConnectionFailed(com.google.android.gms.common.ConnectionResult)}.
 */
private void initiatePlusClientConnect() {
    if (!mPlusClient.isConnected() && !mPlusClient.isConnecting()) {
        mPlusClient.connect();
    }
}

/**
 * Disconnect the {@link PlusClient} only if it is connected (otherwise, it can throw an error.)
 * This will call back to {@link #onDisconnected()}.
 */
private void initiatePlusClientDisconnect() {
    if (mPlusClient.isConnected()) {
        mPlusClient.disconnect();
    }
}

/**
 * Sign out the user (so they can switch to another account).
 */
public void signOut() {

    // We only want to sign out if we're connected.
    if (mPlusClient.isConnected()) {
        // Clear the default account in order to allow the user to potentially choose a
        // different account from the account chooser.
        mPlusClient.clearDefaultAccount();

        // Disconnect from Google Play Services, then reconnect in order to restart the
        // process from scratch.
        initiatePlusClientDisconnect();

        Log.v(TAG, "Sign out successful!");
    }

    updateConnectButtonState();
}

/**
 * Revoke Google+ authorization completely.
 */
public void revokeAccess() {

    if (mPlusClient.isConnected()) {
        // Clear the default account as in the Sign Out.
        mPlusClient.clearDefaultAccount();

        // Revoke access to this entire application. This will call back to
        // onAccessRevoked when it is complete, as it needs to reach the Google
        // authentication servers to revoke all tokens.
        mPlusClient.revokeAccessAndDisconnect(new PlusClient.OnAccessRevokedListener() {
            public void onAccessRevoked(ConnectionResult result) {
                updateConnectButtonState();
                onPlusClientRevokeAccess();
            }
        });
    }

}

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

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

public boolean isPlusClientConnecting() {
    return mPlusClientIsConnecting;
}

private void setProgressBarVisible(boolean flag) {
    mPlusClientIsConnecting = flag;
    onPlusClientBlockingUI(flag);
}

/**
 * A helper method to flip the mResolveOnFail flag and start the resolution
 * of the ConnectionResult from the failed connect() call.
 */
private void startResolution() {
    try {
        // Don't start another resolution now until we have a result from the activity we're
        // about to start.
        mAutoResolveOnFail = false;
        // If we can resolve the error, then call start resolution and pass it an integer tag
        // we can use to track.
        // This means that when we get the onActivityResult callback we'll know it's from
        // being started here.
        mConnectionResult.startResolutionForResult(this, OUR_REQUEST_CODE);
    } catch (IntentSender.SendIntentException e) {
        // Any problems, just try to connect() again so we get a new ConnectionResult.
        mConnectionResult = null;
        initiatePlusClientConnect();
    }
}

/**
 * An earlier connection failed, and we're now receiving the result of the resolution attempt
 * by PlusClient.
 *
 * @see #onConnectionFailed(ConnectionResult)
 */
@Override
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
    updateConnectButtonState();
    if (requestCode == OUR_REQUEST_CODE && responseCode == RESULT_OK) {
        // If we have a successful result, we will want to be able to resolve any further
        // errors, so turn on resolution with our flag.
        mAutoResolveOnFail = true;
        // If we have a successful result, let's call connect() again. If there are any more
        // errors to resolve we'll get our onConnectionFailed, but if not,
        // we'll get onConnected.
        initiatePlusClientConnect();
    } else if (requestCode == OUR_REQUEST_CODE && responseCode != RESULT_OK) {
        // If we've got an error we can't resolve, we're no longer in the midst of signing
        // in, so we can stop the progress spinner.
        setProgressBarVisible(false);
    }
}

/**
 * Successfully connected (called by PlusClient)
 */
@Override
public void onConnected(Bundle connectionHint) {
    updateConnectButtonState();
    setProgressBarVisible(false);
    onPlusClientSignIn();
}

/**
 * Successfully disconnected (called by PlusClient)
 */
@Override
public void onDisconnected() {
    updateConnectButtonState();
    onPlusClientSignOut();
}

/**
 * Connection failed for some reason (called by PlusClient)
 * Try and resolve the result.  Failure here is usually not an indication of a serious error,
 * just that the user's input is needed.
 *
 * @see #onActivityResult(int, int, Intent)
 */
@Override
public void onConnectionFailed(ConnectionResult result) {
    updateConnectButtonState();

    // Most of the time, the connection will fail with a user resolvable result. We can store
    // that in our mConnectionResult property ready to be used when the user clicks the
    // sign-in button.
    if (result.hasResolution()) {
        mConnectionResult = result;
        if (mAutoResolveOnFail) {
            // This is a local helper function that starts the resolution of the problem,
            // which may be showing the user an account chooser or similar.
            startResolution();
        }
    }
}

public PlusClient getPlusClient() {
    return mPlusClient;
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM