如何正确使用Google Plus登录多项活动?

Aca*_*lco 42 android google-api google-plus google-oauth

通过多活动应用程序的流程,将Google+ api客户端生命周期捆绑在一起的好方法/推荐方法是什么?使活动依赖于onConnected api客户端方法来触发其功能,将其用作一次性"激活"的东西,或者可能完全不同的东西?

我目前正在努力了解如何在我的Android应用中正确使用Google+登录,该应用包含多项活动.

在第一阶段,我们的想法是使用G +登录来验证用户,并能够收到她的电子邮件,发送通知和类似的东西.最终我计划推出其他Google功能,例如地图或其他Google Play服务,所以我认为已经实施它很有用.

但是,我的应用程序没有按预期运行,我已经将问题缩小到这样一个事实,即当存在多个活动时,我还没有理解应用程序周期中的G +登录.

实现此auth方法的正确或推荐方法是什么?可能有一种形式可以指导我朝着正确的方向发展吗?

例如,我发现了一个非常简单的api客户端生命周期,但这与app流程有什么关系?

最初我有一个登录活动,我在其中放入登录按钮.按照Google的指南,我可以登录,当调用onConnected方法时,我启动Home Activity(有点像应用程序的仪表板或主屏幕).

这有点工作.例如,为每个活动处理onStart和onStop的好方法是什么?我是否应该每次为每项活动重新连接并重新验证api客户端?因此,使用BaseActivity实现所有这些可能是一个好主意.

另一个问题是,我应该使用相同的api客户端对象并以某种方式传递它,或者可能将它存储在Base Activity类中?或者我应该每次创建和初始化一个新的api客户端对象?

如何使用Login Activity对G +进行身份验证,然后只需获取电子邮件并将其存储在本地数据库中,并将用户标记为"已验证"或"活动"等.这样可以防止我每次关闭应用程序或暂停连接时都必须重新进行身份验证,甚至可以节省一些电量.

该应用程序实际上并没有使用G +发布或任何其他类似的功能.理想情况下,它应该可以脱机工作,只需要连接初始身份验证或其他一次性事物.

非常感谢任何正确方向的建议或指示.

编辑:我已经阅读了我能找到的所有使用Google+的指南和教程,并且每个人都从单一活动的角度来解决这个问题.我认为这是一个普遍存在的问题,它将受益于模式或至少一般的指导方针.

Ian*_*ber 41

重新连接每个活动绝对没问题.从广义上讲,我看到有三种方式可以实现这一点:

  1. 主要在基本活动中实施,并让其他人扩展.这是每个活动中的连接/断开连接,但代码只在一个地方.
  2. 在片段中实现连接/断开,并将其包含在需要auth的活动中.如果您已经具有无法扩展的基本活动(例如某些游戏案例),这将非常有用.
  3. 实现连接/断开连接的服务.如果需要登录,这可以触发广播或类似广告.

所有这些工作,我已经看到它们都在现实世界的应用程序中使用.要记住的主要事情是将99%的逻辑(用户登录或退出,并告知您)从相对罕见的"在当前时刻登录"用例中分离出来.因此,例如,您可能已经onConnected/onConnection失败了很多次,但大多数情况下您忽略或只是略微关于应用程序的状态.只有在带有登录按钮的屏幕上才需要连接结果解析和onActivityResult内容.想想谷歌播放服务连接主要是关于询问用户的状态,而不是签署它们,你应该没问题.


Lee*_*Lee 27

我同意Ian Barber的回答,但为了进一步解释,你Activity应该考虑两种类型 - Activity解决登录的问题,以及Activity需要登录的问题.

大多数Activity人并不关心自己对用户进行身份验证,并且在您的应用中具有相同的逻辑.他们将创建一个GoogleApiClient,它连接到设备上运行的Google Play服务进程并读取用户的缓存登录状态 - onConnected()如果用户已登录则返回,onConnectionFailed()如果没有,则返回.如果用户没有登录,您Activity的大多数人都希望重置您的应用程序状态并启动您LoginActivity.每个人都Activity应该维护自己的实例,GoogleApiClient因为它是一个轻量级对象,用于访问Google Play服务进程持有的共享状态.例如,这种行为可以封装在共享BaseActivity类或共享SignInFragment类中,但每个实例都应该有自己的GoogleApiClient实例.

LoginActivity然而,您需要以不同的方式实施.它也应该创建一个GoogleApiClient,但是当它收到onConnected()指示用户已登录时,它应该开始适合Activity用户和finish().当您LoginActivity收到onConnectionFailed()指示用户未登录时,您应尝试解决登录问题startResolutionForResult().


JP *_*ura 10

0. TL; DR

对于不耐烦的编码器,可以在GitHub上找到以下实现的工作版本.

在许多不同的应用程序中多次重写登录活动代码后,简单(而不是那么优雅)的解决方案是将Google API客户端创建为Application类对象.但是,由于连接状态会影响用户体验流程,因此我从未对这种方法感到高兴.

将我们的问题仅减少到连接概念,我们可以考虑:

  1. 它隐藏了Google API客户端.
  2. 它有有限的状态.
  3. 它是(相当)独特的.
  4. 当前状态会影响应用程序的行为.

1.代理模式

由于Connection封装了GoogleApiClient,它将实现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();
    }
}
Run Code Online (Sandbox Code Playgroud)

活动可以通过方法connectdisconnect,与Connection类进行通信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);
}
Run Code Online (Sandbox Code Playgroud)

2.国家格局

这是一种行为模式,允许对象在其内部状态发生变化时改变其行为.在GoF的设计模式一书描述了一个TCP连接可以通过这种模式来表示(这也是我们的情况下).

来自状态机的状态应该是a 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) {}
Run Code Online (Sandbox Code Playgroud)

Connection类保存上下文,即当前状态,它定义了如何在Connection方法connect,disconnectrevoke将表现:

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);
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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...
}
Run Code Online (Sandbox Code Playgroud)

  • 非常有趣的方法,似乎代码完整甚至.将在某个时候尝试并将其与我的方法进行比较.谢谢! (2认同)