Android 安卓谷歌&x2B;集成-重复的UserRecoverableAuthException

Android 安卓谷歌&x2B;集成-重复的UserRecoverableAuthException,android,oauth-2.0,google-plus,Android,Oauth 2.0,Google Plus,我们已经就此联系了谷歌,并且 这一问题似乎已经解决,但三星手机除外 我正在为每个应用程序添加Google+登录选项。一旦用户选择了他们的帐户,我希望我的服务器检索他们的Google+个人资料信息,并在我们的网站上更新他们的个人资料以匹配 第一部分——让用户在本地选择一个谷歌账户——似乎效果不错。当我尝试为所选帐户请求令牌时,Google auth对话框会显示相应的参数;但是,当我使用该对话框授权应用程序并重新请求令牌时,GoogleAuthUtil.getToken(…)再次抛出一个UserRe

我们已经就此联系了谷歌,并且

这一问题似乎已经解决,但三星手机除外

我正在为每个应用程序添加Google+登录选项。一旦用户选择了他们的帐户,我希望我的服务器检索他们的Google+个人资料信息,并在我们的网站上更新他们的个人资料以匹配

第一部分——让用户在本地选择一个谷歌账户——似乎效果不错。当我尝试为所选帐户请求令牌时,Google auth对话框会显示相应的参数;但是,当我使用该对话框授权应用程序并重新请求令牌时,
GoogleAuthUtil.getToken(…)
再次抛出一个
UserRecoverableAuthException
NeedPermission
,而不是
GooglePlayServicesAvailabilityException
),我得到了同样的对话框要求我批准

运行安卓4.1.1(有3个谷歌账户)的三星S3和运行4.0.3的宏碁A100都存在这种行为。运行2.3.4的HTC冰川上不存在这种物质。相反,HTC Glacier为我提供了一个有效的身份验证代码。所有设备都安装了最新版本的Google Play服务,并使用不同的Google+帐户

有人见过这个吗?从哪里开始调试

这是完整的代码-有什么明显的错误吗

public class MyGooglePlusClient {
private static final String LOG_TAG = "GPlus";
private static final String SCOPES_LOGIN = Scopes.PLUS_LOGIN + " " + Scopes.PLUS_PROFILE;
private static final String ACTIVITIES_LOGIN = "http://schemas.google.com/AddActivity";
private static MyGooglePlusClient myGPlus = null;
private BaseActivity mRequestingActivity = null;
private String mSelectedAccount = null;
    
/**
 * Get the GPlus singleton
 * @return GPlus
 */
public synchronized static MyGooglePlusClient getInstance() {
    if (myGPlus == null)
        myGPlus = new MyGooglePlusClient();
    return myGPlus;
}

public boolean login(BaseActivity requester) {
    Log.w(LOG_TAG, "Starting login...");
    if (mRequestingActivity != null) {
        Log.w(LOG_TAG, "Login attempt already in progress.");
        return false; // Cannot launch a new request; already in progress
    }
    
    mRequestingActivity = requester;
    if (mSelectedAccount == null) {
        Intent intent = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, false,
                null, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE, null, null);
        mRequestingActivity.startActivityForResult(intent, BaseActivity.REQUEST_GPLUS_SELECT);
    }
    return true;
}

public void loginCallback(String accountName) {
    mSelectedAccount = accountName;
    authorizeCallback();
}
    
public void logout() {
    Log.w(LOG_TAG, "Logging out...");
    mSelectedAccount = null;
}

public void authorizeCallback() {
    Log.w(LOG_TAG, "User authorized");

    AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            String token = null;
            try {
                Bundle b = new Bundle();
                b.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES, ACTIVITIES_LOGIN);
                token = GoogleAuthUtil.getToken(mRequestingActivity,
                        mSelectedAccount,
                        "oauth2:server:client_id:"+Constants.GOOGLE_PLUS_SERVER_OAUTH_CLIENT
                        +":api_scope:" + SCOPES_LOGIN,
                        b);
            } catch (IOException transientEx) {
                // Network or server error, try later
                Log.w(LOG_TAG, transientEx.toString());
                onCompletedLoginAttempt(false);
            } catch (GooglePlayServicesAvailabilityException e) {
                Log.w(LOG_TAG, "Google Play services not available.");
                Intent recover = e.getIntent();
                mRequestingActivity.startActivityForResult(recover, BaseActivity.REQUEST_GPLUS_AUTHORIZE);
            } catch (UserRecoverableAuthException e) {
                // Recover (with e.getIntent())
                Log.w(LOG_TAG, "User must approve "+e.toString());
                Intent recover = e.getIntent();
                mRequestingActivity.startActivityForResult(recover, BaseActivity.REQUEST_GPLUS_AUTHORIZE);
            } catch (GoogleAuthException authEx) {
                // The call is not ever expected to succeed
                Log.w(LOG_TAG, authEx.toString());
                onCompletedLoginAttempt(false);
            }

            Log.w(LOG_TAG, "Finished with task; token is "+token);
            if (token != null) {
                authorizeCallback(token);
            }
            
            return token;
        }

    };
    task.execute();
}

public void authorizeCallback(String token) {
    Log.w(LOG_TAG, "Token obtained: "+token);
    // <snipped - do some more stuff involving connecting to the server and resetting the state locally>
}

public void onCompletedLoginAttempt(boolean success) {
    Log.w(LOG_TAG, "Login attempt "+(success ? "succeeded" : "failed"));
    mRequestingActivity.hideProgressDialog();
    mRequestingActivity = null;
}
}
公共类MyGooglePlusClient{
私有静态最终字符串日志\u TAG=“GPlus”;
私有静态最终字符串SCOPES\u LOGIN=SCOPES.PLUS\u LOGIN+“”+SCOPES.PLUS\u配置文件;
私有静态最终字符串活动\u登录=”http://schemas.google.com/AddActivity";
私有静态MyGooglePlusClient myGPlus=null;
private BaseActivity mRequestingActivity=null;
私有字符串mSelectedAccount=null;
/**
*获取GPlus单例
*@return GPlus
*/
公共同步静态MyGooglePlusClient getInstance(){
if(myGPlus==null)
myGPlus=新的MyGooglePlusClient();
返回myGPlus;
}
公共布尔登录(BaseActivity请求程序){
w(Log_标签,“开始登录…”);
if(mRequestingActivity!=null){
w(Log_标记,“登录尝试已在进行中”);
return false;//无法启动新请求;已在进行中
}
mRequestingActivity=请求者;
如果(mSelectedAccount==null){
Intent Intent=AccountPicker.newchooseaccountcontent(null,null,新字符串[]{GoogleAuthUtil.GOOGLE\u ACCOUNT\u TYPE},false,
null,GoogleAuthUtil.GOOGLE_账户类型,null,null);
mRequestingActivity.startActivityForResult(intent、BaseActivity.REQUEST\u GPLUS\u SELECT);
}
返回true;
}
public void loginCallback(字符串accountName){
mSelectedAccount=accountName;
授权回调();
}
公开作废注销(){
Log.w(Log_标签,“注销…”);
mSelectedAccount=null;
}
公共资源回收(){
Log.w(Log_标签,“用户授权”);
AsyncTask任务=新建AsyncTask(){
@凌驾
受保护字符串doInBackground(无效…参数){
字符串标记=null;
试一试{
Bundle b=新Bundle();
b、 putString(GoogleAuthUtil.KEY\请求\可见\活动、活动\登录);
token=GoogleAuthUtil.getToken(mRequestingActivity,
mSelectedAccount,
“oauth2:server:client\u id:”+Constants.GOOGLE\u PLUS\u server\u OAUTH\u client
+“:api_范围:“+SCOPES_登录,
b) );
}捕获(IOException transientEx){
//网络或服务器错误,请稍后再试
Log.w(Log_标记,transientEx.toString());
OnCompletedLoginAttent(假);
}捕获(谷歌PlayServicesAvailabilityException e){
w(Log_标签,“谷歌播放服务不可用”);
Intent recover=e.getIntent();
mRequestingActivity.startActivityForResult(恢复、BaseActivity.REQUEST\u GPLUS\u授权);
}捕获(UserRecoverableAuthe异常){
//恢复(使用e.getIntent())
Log.w(Log_标签,“用户必须批准”+e.toString());
Intent recover=e.getIntent();
mRequestingActivity.startActivityForResult(恢复、BaseActivity.REQUEST\u GPLUS\u授权);
}捕获(GoogleAuthException authEx){
//这一呼吁永远不会成功
Log.w(Log_标记,authEx.toString());
OnCompletedLoginAttent(假);
}
Log.w(Log_标记,“已完成任务;令牌为”+令牌);
if(令牌!=null){
授权回调(令牌);
}
返回令牌;
}
};
task.execute();
}
公共无效回调(字符串令牌){
Log.w(Log_标记,“获得的令牌:”+令牌);
// 
}
public void onCompletedLoginAttent(布尔值成功){
Log.w(Log_标记,“登录尝试”+(成功?:“失败”);
mRequestingActivity.hideProgressDialog();
mRequestingActivity=null;
}
}
编辑(2013年8月6日):这似乎已经为我解决了,我的代码没有任何更改。

我看到的第一个潜在问题是,在获得
onConnected()
回调后,您正在调用
GoogleAuthUtil.getToken()
。这是一个问题,因为使用
GoogleAuthUtil.getToken()
为服务器请求授权代码将始终向用户显示同意屏幕。因此,您应该只获取新用户的授权码,为了避免向新用户显示两个同意屏幕,您必须获取授权码并在服务器上进行交换,然后才能从
PlusClient
解决任何连接故障

其次,确保您实际上需要一个PlusClient和一个授权代码
String url = "https://accounts.google.com/o/oauth2/auth?scope=" + Scopes.PLUS_LOGIN + "&client_id=" + webLoginClientId + "&response_type=code&access_type=offline&approval_prompt=force&redirect_uri=" + redirect;
String token = GoogleAuthUtil.getToken(this, accountName, scopeString, appActivities);
startActivityForResult(e.getIntent(), RECOVERABLE_REQUEST_CODE);
@Override
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
    if (requestCode == RECOVERABLE_REQUEST_CODE && responseCode == RESULT_OK) {
        Bundle extra = intent.getExtras();
        String oneTimeToken = extra.getString("authtoken");
    }
}
private void getProfileInformation() {
    try {
        if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null) {
            Person currentPerson = Plus.PeopleApi
                    .getCurrentPerson(mGoogleApiClient);
            String personName = currentPerson.getDisplayName();
            String personPhotoUrl = currentPerson.getImage().getUrl();
            String personGooglePlusProfile = currentPerson.getUrl();
            String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
            getOneTimeToken(); // <-------
            ...
private void getOneTimeToken(){
    if (task==null){
    task = new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            LogHelper.log('d',LOGTAG, "Executing background task....");
            Bundle appActivities = new Bundle();
            appActivities.putString(
                         GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
                         ACTIVITIES_LOGIN);
            String scopes = "oauth2:server" + 
                            ":client_id:" + SERVER_CLIENT_ID + 
                            ":api_scope:" + SCOPES_LOGIN;
            String token = null;
            try {
                token = GoogleAuthUtil.getToken(
                        ActivityPlus.this,
                        Plus.AccountApi.getAccountName(mGoogleApiClient),
                        scopes,
                        appActivities
                );
            } catch (IOException transientEx) {
                /* Original comment removed*/
                LogHelper.log('e',LOGTAG, transientEx.toString());
            } catch (UserRecoverableAuthException e) {
                /* Original comment removed*/
                LogHelper.log('e',LOGTAG, e.toString());
                startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST);
            } catch (GoogleAuthException authEx) {
                /* Original comment removed*/
                LogHelper.log('e',LOGTAG, authEx.toString());
            } catch (IllegalStateException stateEx){
                LogHelper.log('e',LOGTAG, stateEx.toString());
            }
            LogHelper.log('d',LOGTAG, "Background task finishing....");
            return token;
        }

        @Override
        protected void onPostExecute(String token) {
            LogHelper.log('i',LOGTAG, "Access token retrieved: " + token);
        }

    };
    }
    LogHelper.log('d',LOGTAG, "Task setup successful.");
    if(task.getStatus() != AsyncTask.Status.RUNNING){
        task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); //double safety!
    } else
        LogHelper.log('d',LOGTAG, 
                       "Attempted to restart task while it is running!");
}
catch (UserRecoverableAuthException e) {
  // Requesting an authorization code will always throw
  // UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
  // because the user must consent to offline access to their data.  After
  // consent is granted control is returned to your activity in onActivityResult
  // and the second call to GoogleAuthUtil.getToken will succeed.
  startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
  return;
}
private class GetAuthTokenFromGoogle extends AsyncTask<Void, Integer, Void>{
        @Override  
        protected void onPreExecute()  
        {  

        }
        @Override
        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub

            try {
                accessCode = GoogleAuthUtil.getToken(mContext, Plus.AccountApi.getAccountName(mGoogleApiClient), SCOPE);
                new ValidateTokenWithPhoneOmega().execute();
                Log.d("Token  -- ", accessCode);
            } catch (IOException transientEx) {
                // network or server error, the call is expected to succeed if you try again later.
                // Don't attempt to call again immediately - the request is likely to
                // fail, you'll hit quotas or back-off.

                return null;
            } catch (UserRecoverableAuthException e) {
                // Recover
                startActivityForResult(e.getIntent(), RC_ACCESS_CODE);
                e.printStackTrace();
            } catch (GoogleAuthException authEx) {
                // Failure. The call is not expected to ever succeed so it should not be
                // retried.
                authEx.printStackTrace();
                return null;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return null;  
        }

        @Override  
        protected void onPostExecute(Void result)  
        { 
        }
    }
try {
    ....
} catch (IOException transientEx) {
    ....
} catch (final UserRecoverableAuthException e) {
    ....
    runOnUiThread(new Runnable() {
        public void run() {         
            startActivityForResult(e1.getIntent(), AUTH_CODE_REQUEST);
        }
    });
}