web-dev-qa-db-ja.com

複数のアクティビティからグーグルプラスクライアントにアクセスする

私はグーグルプラスを統合したアプリケーションを開発しています。これまでのところ正常に動作しているので、ユーザープロファイルを取得できます。

しかし今、私は次のことをしたいと思います:

1)2つのアクティビティsignInActivityshareActivityがあります。

2)ユーザーがすでにsignInActivityを使用してサインインしている場合は、shareActivityで再度サインインを要求せず、コンテンツを直接共有する必要があります。

3)ユーザーがsignInActivityにサインインしておらず、shareActivityを使用してデータを共有しようとした場合、アプリはユーザーにサインインしてから、データのみを共有する必要があります。この場合、ユーザーがsignInActivityに戻ると、アプリは「すでにサインインしています」と表示するはずです。

要するに、ユーザーサインインをアプリケーション内でCentralにして、それがalradyサインインされている場合は、どのアクティビティからでもアクセスできるようにする必要があります。

アクセストークンについて聞いたことがありますが、使用方法がわかりません。ドキュメントには、1時間で期限切れになると記載されていますが、これは私が望んでいることではありません。

どうすれば中央のグーグルプラスサインインを作ることができますか?出来ますか?または、各アクティビティでユーザーを認証する必要がありますか?

24
dd619

各アクティビティでGoogleApiClientの個別のインスタンスを管理すると、notになり、ユーザーは複数回サインインするように求められます。

Google+サインイン(つまり、GoogleApiClient)は、デバイス上のGoogleアカウントとGooglePlay開発者サービスのコアサービスへのインターフェースを提供します。GoogleApiClientインスタンスごとの状態はありません。そのため、アプリのデバイスアカウントが認証されると、GoogleApiClientの新しいインスタンスが同じ状態にアクセスします。 GoogleApiClientは、GooglePlay開発者サービスによって管理されている中央の状態にアクセスするための軽量な方法となるように特別に設計されています。

アクセストークンに関しては幸運です! Google Play開発者サービスが、すべてのトークン管理を処理します。したがって、アクセストークンは1時間しか持続しませんが、おっしゃるように、PlusClientを使用してGoogle APIにアクセスしようとして、アクセストークンの有効期限が切れている場合、GooglePlay開発者サービスは透過的に新しいアクセストークンを要求して通話を完了します。

詳細については、このGoogle I/Oトークの最初の部分をご覧ください。

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

37
Lee

0. TL; DR

せっかちなコーダーの場合、次の実装の動作バージョンは GitHub にあります。これは別の Stack Overflow post に書かれた同じ答えです。

多くの異なるアプリでログインアクティビティコードを数回書き直した後、簡単な(そしてそれほどエレガントではない)ソリューションは、アプリケーションクラスオブジェクトとしてGoogleAPIクライアントを作成することでした。しかし、接続状態はUXフローに影響を与えるため、このアプローチには満足できませんでした。

問題を接続の概念だけに還元すると、次のように考えることができます。

  1. GoogleAPIクライアントを非表示にします。
  2. 有限の状態があります。
  3. それは(むしろ)ユニークです。
  4. 現在の状態はアプリの動作に影響します。

1.プロキシパターン

ConnectionGoogleApiClientをカプセル化するため、ConnectionCallbacksOnConnectionFailedListenerを実装します。

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

アクティビティは、メソッドconnectdisconnect、およびrevokeを介してConnectionクラスと通信できますが、その動作は現在の状態によって決定されます。ステートマシンには次のメソッドが必要です。

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 book は、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メソッドconnectdisconnect、および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...
}
16
JP Ventura

この質問を読んでいる人は誰でも Ian Barberによるこの回答を確認してください そしてLeeが回答した以下の質問もできます。実際に。

6
Acapulco