android - 浏览器 Intent 并返回正确的 Activity (关闭打开的选项卡)

标签 android google-chrome android-intent oauth-2.0

在 Android 的 AccountManager 中实现自定义帐户类型时,我在登录流程中遇到以下问题:

登录应该通过 OAuth 提供商进行。因此,我创建了一个 SignInActivity,它启动一个 WebView 并启动一个 OAuth 流程。这工作正常,当接收到 my-custom-scheme://callback 的回调时,WebView 检测到它,接收 code querystring 参数并完成流程。使用 WebView 的缺点是,即使用户可能已经在浏览器中有一个 Activity session ,但该 session 不会在 WebView 中使用,因此用户将不得不在 WebView 中再次登录。

为了解决这个问题,我尝试改用 AndroidManifest.xml 中的 intent-filter,如下所示:

<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>

我没有在 SignInActivity 中打开 WebView,而是启动浏览器 Intent 并等待浏览器点击 my-custom-scheme://回调.

Intent browserIntent = new Intent(Intent.ACTION_VIEW, "http://oauth2provider/authorize");
startActivity(browserIntent);
finish();

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

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

这行得通。但是,问题(终于!):

  1. 如果用户未登录,浏览器 Intent 将显示 oauth 提供商的登录页面。用户登录后,Chrome 将重定向到 my-custom-scheme://callback 并且 SignInActivity 将启动以处理 Intent 。由于此 Activity 是不可见的,因此浏览器将在登录页面上保持打开状态,并且对用户而言,它看起来就像什么也没发生过一样。浏览器永远不会关闭。
  2. 如果用户已经登录,oauth 提供商将直接重定向到 my-custom-scheme://callback。在这种情况下,浏览器选项卡会自动关闭,但浏览器本身保持打开状态(没有可见的选项卡)。

所以我的问题是:在重定向到 my-custom-scheme://callback 之后,有没有办法让浏览器的行为有所不同?理想情况下,我希望它在重定向到回调后简单地关闭,并返回到 Activity 堆栈中的前一个 Activity (即返回到从头开始启动 SignInActivity 的 Activity )。

最佳答案

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

假设我们有带有 Sign In 按钮的 MainActivity 不是直接单击该按钮启动浏览器,而是使用 startActivityForResult 方法启动 SignInActivity。它用于我可以处理登录流程的结果。

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

SignInActivity 负责:

  • 打开浏览器登录页面
  • 捕获重定向到 custom-scheme://callback
  • 使用从重定向 url 接收到的 token 完成登录流程
  • 返回结果给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();
    }
}

将标志设置为浏览器 Intent 。

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

p>

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

setResult(Activity.RESULT_OK);
this.finish();

自然地,您会从该端点收到 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>

这是 AndroidManifest.xmlSignInActivity 的声明

<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>

关于android - 浏览器 Intent 并返回正确的 Activity (关闭打开的选项卡),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25831981/

相关文章:

javascript - Chrome 扩展程序通过 tabId 进行 WebRequest 过滤不起作用?

java - 使用 Intent 标志和 androidmanifest

android - 找不到与给定名称匹配的资源(在 'layout_toRightOf' 处,值为 '@id/right_item_menu_fragment' )

Android:使用查找键管理联系人

Chrome 中的 CSS3 过渡变换 rotateX

javascript - Chrome 扩展 ajax 发送格式错误的重音字符

android - 从 Activity 向服务发送 "share intent"(ACTION_SEND)

Android Intent 打开图库在 KitKat (4.4) 上不起作用

android - 我应该在 Fragment 中的什么生命周期状态下执行异步任务?

android - 包 android.support.v4.content 不存在 flutter