浏览器意图并返回正确的活动(关闭打开的选项卡)

jos*_*son 12 android google-chrome android-intent oauth-2.0

AccountManager在Android中实施自定义帐户类型时,我对登录流程有以下问题:

登录应通过OAuth提供商进行.因此,我创建了一个SignInActivity启动WebView并启动OAuth流程的程序.这工作得很好,当回调接收到my-custom-scheme://callbackWebView检测它,接受code查询字符串参数并完成流程.使用a的缺点WebView是,即使用户可能已经在浏览器中有活动会话,也不会使用此会话,WebView因此用户必须再次登录WebView.

为了解决这个问题,我尝试切换到使用intent-filterin AndroidManifest.xml,如下所示:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="my-custom-scheme" android:path="callback"/>
</intent-filter>
Run Code Online (Sandbox Code Playgroud)

我没有打开a WebView,而是SignInActivity启动浏览器意图并等待浏览器点击my-custom-scheme://callback.

Intent browserIntent = new Intent(Intent.ACTION_VIEW, "http://oauth2provider/authorize");
startActivity(browserIntent);
finish();
Run Code Online (Sandbox Code Playgroud)

在我的SignInActivity我有以下代码来处理回调:

if (intent != null && intent.getData() != null && getString("my-custom-scheme").equals(intent.getData().getScheme())) {
    String code = getIntent().getData().getQueryParameter("code");
    // complete oauth flow
}
Run Code Online (Sandbox Code Playgroud)

这有效.但是,对于这个问题(最后!):

  1. 如果用户未登录,则浏览器意图将显示oauth提供程序的登录页面.用户登录后,Chrome会重定向到my-custom-scheme://回调并SignInActivity启动以处理意图.由于此活动不可见,浏览器将在登录页面上保持打开状态,对于用户来说,它看起来似乎什么也没发生.浏览器永远不会关闭.
  2. 如果用户已登录,则oauth提供程序将直接重定向到my-custom-scheme://回调.在这种情况下,浏览器选项卡会自动关闭,但浏览器本身仍保持打开状态(没有可见的选项卡).

所以我的问题是:无论如何,在重定向到my-custom-scheme://回调之后,浏览器的行为是否有所不同?理想情况下,我希望它在重定向到回调之后简单地关闭,并返回到活动堆栈中的前一个活动(即SignInActivity从开始的活动开始).

小智 5

我使用了下一个方法来解决同样的问题。

假设我们有MainActivitySign In按钮。我开始使用方法,而不是直接单击该按钮启动浏览器。它用于然后我可以处理登录流程的结果。SignInActivitystartActivityForResult

startActivityForResult(new Intent(this, SignInActivity.class), requestCode);

SignInActivity 为...负责:

  • 用登录页面打开浏览器
  • 捕获重定向到 custom-scheme://callback
  • 使用从重定向 url 收到的令牌完成登录流程
  • 返回结果 MainActivity

所以,它的onCreate方法看起来像:

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

    if (intent != null && intent.getData() != null && "custom-scheme".equals(intent.getData().getScheme())) {
        String code = getIntent().getData().getQueryParameter("code");
       // complete oauth flow
    } else {
        Intent browserIntent = new Intent(Intent.ACTION_VIEW, "http://oauth2provider/authorize")
            .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_FROM_BACKGROUND);
        startActivity(browserIntent);
        finish();
    }
}
Run Code Online (Sandbox Code Playgroud)

承认在浏览器意图中设置的标志。

这样,如果SignInActivityMainActivity它打开只会在浏览器中打开登录页面,如果它打开捕获重定向 url,它会完成登录流程发送适当的请求。

完成登录流程后,将代码发送到回调方法中的某个端点,您应该执行以下操作:

setResult(Activity.RESULT_OK);
this.finish();
Run Code Online (Sandbox Code Playgroud)

自然地,您会从该端点收到 access_token。您可以将它存储在此处、成功回调中或将其返回到 以在MainActivity那里处理它。

作为布局,SignInActivity您可以仅ProgressBar在页面中央使用。SignInActivity打开捕获重定向 url ( custom-scheme://callback)后,它将在登录流程完成期间出现。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
>

    <ProgressBar
       android:layout_width="48dp"
       android:layout_height="48dp"
       android:layout_centerVertical="true"
       android:layout_centerHorizontal="true"
    />
</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

这是SignInActivityin 的声明AndroidManifest.xml

<activity android:name=".SignInActivity"
          android:launchMode="singleTask"
          android:noHistory="true"
     >
     <intent-filter>
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.DEFAULT"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <data android:scheme="custom-scheme" android:host="callback"/>
     </intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)