Доступ к клиенту Google Plus из нескольких действий

Я разрабатываю приложение, в которое я интегрировал Google Plus. Пока все работает нормально, я могу получить профиль пользователя.

Но сейчас я хочу сделать следующее:

1) у меня два вида деятельности signInActivity а также shareActivity,

2) Если пользователь уже вошел в систему, используя signInActivity тогда он не должен просить войти снова вshareActivity и должен напрямую делиться контентом.

3) Если пользователь не вошел в signInActivity и попытаться поделиться данными с помощью shareActivityЗатем приложение должно войти в систему пользователя, а затем только поделиться данными. В этом случае, если пользователь возвращается к signInActivity тогда приложение должно показать, что "вы уже вошли"

Короче говоря, я хочу, чтобы пользовательский вход был центральным в приложении, так что, если он подписан как alrady, он должен быть доступен из любого действия.

Я слышал о токене доступа, но я не знаю, как его использовать, и в документе говорится, что срок его действия истекает через час, а это не то, чего я хочу.

Как я могу сделать центральный вход в Google Plus? Является ли это возможным? или мне нужно аутентифицировать пользователя в каждом действии?

3 ответа

Решение

Управление отдельным экземпляром GoogleApiClient в каждом действии не приведет к тому, что пользователю будет предложено войти в систему несколько раз.

Вход в Google+ (т. Е. GoogleApiClient) обеспечивает интерфейс с учетными записями Google на устройстве и основной службой служб Google Play - он не имеет состояния для экземпляра GoogleApiClient. Поэтому, как только учетная запись устройства будет аутентифицирована для вашего приложения, новые экземпляры GoogleApiClient получат доступ к тому же состоянию. GoogleApiClient специально разработан для облегчения доступа к центральному штату, управляемому службами Google Play.

Вам повезло с токенами доступа! Сервисы Google Play позаботятся обо всем управлении токенами. Таким образом, хотя токены доступа действуют только в течение одного часа, как вы говорите, если вы пытаетесь использовать свой PlusClient для доступа к API Google, а срок действия вашего токена доступа истек, службы Google Play прозрачно запросят у вас новый токен доступа и завершат вызов.

Взгляните на первую часть этого выступления по вводу / выводу Google для более подробной информации:

http://www.youtube.com/watch?v=_KBHf1EODuk

0. TL;DR

Для нетерпеливого кодера рабочую версию следующей реализации можно найти на GitHub. Это тот же ответ, который написан в другом сообщении о переполнении стека.

После переписывания кода активности входа в систему несколько раз во многих различных приложениях, простым (и не очень элегантным) решением было создание клиента API Google в качестве объекта класса приложения. Но, поскольку состояние соединения влияет на поток UX, я никогда не был доволен этим подходом.

Сводя нашу проблему только к концепции подключения, мы можем считать, что:

  1. Он скрывает клиент Google API.
  2. У него конечные состояния.
  3. Это (довольно) уникальный.
  4. Текущее состояние влияет на поведение приложения.

1. Прокси шаблон

Так как Connection заключает в капсулу GoogleApiClient, он будет реализовывать ConnectionCallbacks а также OnConnectionFailedListener:

@Override
public void onConnected(Bundle hint) {
    changeState(State.OPENED);
}

@Override
public void onConnectionSuspended(int cause) {
    changeState(State.CLOSED);
    connect();
}

@Override
public void onConnectionFailed(ConnectionResult result) {
    if (currentState.equals(State.CLOSED) && result.hasResolution()) {
        changeState(State.CREATED);
        connectionResult = result;
    } else {
        connect();
    }
}

Действия могут общаться с классом Connection через методы connect, disconnect, а также revoke, но их поведение определяется текущим состоянием. Для конечного автомата требуются следующие методы:

protected void onSignIn() {
    if (!googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
        googleApiClient.connect();
    }
}

protected void onSignOut() {
    if (googleApiClient.isConnected()) {
        Plus.AccountApi.clearDefaultAccount(googleApiClient);
        googleApiClient.disconnect();
        googleApiClient.connect();
        changeState(State.CLOSED);
    }
}

protected void onSignUp() {
    Activity activity = activityWeakReference.get();
    try {
        changeState(State.OPENING);
        connectionResult.startResolutionForResult(activity, REQUEST_CODE);
    } catch (IntentSender.SendIntentException e) {
        changeState(State.CREATED);
        googleApiClient.connect();
    }
}

protected void onRevoke() {
    Plus.AccountApi.clearDefaultAccount(googleApiClient);
    Plus.AccountApi.revokeAccessAndDisconnect(googleApiClient);
    googleApiClient = googleApiClientBuilder.build();
    googleApiClient.connect();
    changeState(State.CLOSED);
}

2. Государственный паттерн

Это поведенческий паттерн, позволяющий объекту изменять свое поведение при изменении его внутреннего состояния. В книге GoF Design Patterns описывается, как TCP-соединение может быть представлено этим шаблоном (что также является нашим случаем).

Состояние из конечного автомата должно быть singletonи проще всего сделать это на Java было создать Enum названный State следующее:

public enum State {
    CREATED {
        @Override
        void connect(Connection connection) {
            connection.onSignUp();
        }
        @Override
        void disconnect(Connection connection) {
            connection.onSignOut();
        }
    },
    OPENING {},
    OPENED {
        @Override
        void disconnect(Connection connection) {
            connection.onSignOut();
        }
        @Override
        void revoke(Connection connection) {
            connection.onRevoke();
        }
    },
    CLOSED {
        @Override
        void connect(Connection connection) {
            connection.onSignIn();
        }
    };

void connect(Connection connection) {}
void disconnect(Connection connection) {}
void revoke(Connection connection) {}

Connection класс содержит контекст, то есть текущее состояние, которое определяет, как Connection методы connect, disconnect, а также revoke будет вести себя

public void connect() {
    currentState.connect(this);
}

public void disconnect() {
    currentState.disconnect(this);
}

public void revoke() {
    currentState.revoke(this);
}

private void changeState(State state) {
    currentState = state;
    setChanged();
    notifyObservers(state);
}

3. Синглтон

Поскольку нет необходимости повторно создавать этот класс, мы предоставляем его как одиночный:

public static Connection getInstance(Activity activity) {
    if (null == sConnection) {
        sConnection = new Connection(activity);
    }

    return sConnection;
}

public void onActivityResult(int result) {
    if (result == Activity.RESULT_OK) {
        changeState(State.CREATED);
    } else {
        changeState(State.CLOSED);
    }
    onSignIn();
}

private Connection(Activity activity) {
    activityWeakReference = new WeakReference<>(activity);

    googleApiClientBuilder = new GoogleApiClient
           .Builder(activity)
           .addConnectionCallbacks(this)
           .addOnConnectionFailedListener(this)
           .addApi(Plus.API, Plus.PlusOptions.builder().build())
           .addScope(new Scope("email"));

    googleApiClient = googleApiClientBuilder.build();
    currentState = State.CLOSED;
}

4. Наблюдаемая картина

Connection класс расширяет Java ObservableТаким образом, 1 или более действий могут наблюдать изменения состояния:

@Override
protected void onCreate(Bundle bundle) {
    connection = Connection.getInstance(this);
    connection.addObserver(this);
}

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

@Override
protected void onDestroy() {
    connection.deleteObserver(this);
    connection.disconnect();
}

@Override
protected void onActivityResult(int request, int result, Intent data) {
    if (Connection.REQUEST_CODE == request) {
        connection.onActivityResult(result);
    }
}

@Override
public void update(Observable observable, Object data) {
    if (observable != connection) {
        return;
    }
    // Your presentation logic goes here...
}

Для любого, кто читает этот вопрос, вы также можете проверить этот ответ Иана Барбера, а также ответ ниже, на который ответил Ли, в котором объясняются три основных способа работы с Google плюс логин и несколько активаций, которые я считаю очень полезными на самом деле.

Другие вопросы по тегам