17

我正在开发一个使用 OAuth 进行身份验证的应用程序,但我在处理 OAuth 回调时遇到了一点问题。

认证

我的应用程序有一个webview作为登录屏幕,我得到一个 url 来在我的 webview中加载身份验证表单。假设网址是:

https://myoauthhost.com/oauth/auth?response_type=code&client_id=XXXXXXX&redirect_uri=YYYYYYYY&scope=ZZZZZZZZZZ

在身份验证活动(AuthActivity.java)中,我有以下内容:

    String authURL = https://myoauthhost.com/oauth/auth?response_type=code&client_id=XXXXXXX&redirect_uri=YYYYYYYY&scope=ZZZZZZZZZZ
    myWebView.loadUrl(authURL);

在 manifest.xml 中,我有以下 oauth 回调处理:

<activity
            android:name=".AuthActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >

            <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:host="authprovider"
                    android:scheme="auth" />
            </intent-filter>
</activity>

问题

此 url 在 webview 中使用时(使用 loadURL() 方法)重定向到另一个包含REAL OAUTH WEB FROM的 url (应该在 webview 中加载)。问题是这种重定向会自动启动 Android 中的意图选择:由于 URL 应该由 Web 浏览器处理,Android 允许您选择手机上可用的 Web 浏览器之一来打开 URL。

由于这不是我想要的,我必须包含以下代码,以便在 webview 中处理重定向但不启动 web 浏览器(或其他):

myWebView.setWebViewClient(new WebViewClient());

因此,使用此代码,重定向是“在 webview 内”处理的,并且我显示了登录屏幕。

然后我可以输入凭据(例如:通过 Twitter 的 oauth),但是当身份验证完成时,会收到回调,但是应该处理回调的活动(配置为在清单中接收回调的 AuthActivity)没有启动。相反,我让 webview 显示一条消息,指出无法找到 url 回调(在我们的例子中: authprovider://auth/XXX?xxx=yyy 在清单中配置)。

原因可能是以下代码:

myWebView.setWebViewClient(new WebViewClient());

前面介绍过,告诉Android webview 处理一切。所以现在,由于回调 url 不是 web url,它处理起来很麻烦,甚至无法启动可以处理它的意图。

问题

我怎么解决这个问题 ?我应该能够让活动处理回调,但不能让 webview 尝试加载它。

任何帮助,将不胜感激

提前致谢

4

3 回答 3

26

首先在您的清单中,将这些属性设置为启动 WebView 的活动

android:launchMode="singleInstance" 

并为其添加一个意图过滤器

<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="oauth-testing" />
</intent-filter>

然后在用户单击登录按钮时在您的代码中

mReqToken = mTwitter.getOAuthRequestToken(CALLBACK_URL);
WebView webView = new WebView(this);
webView.requestFocus(View.FOCUS_DOWN);
webView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
            if (!v.hasFocus()) {
                v.requestFocus();
            }
            break;
        }
        return false;
    }
});
webView.loadUrl(mReqToken.getAuthenticationURL());
mainLayout.removeAllViews();
mainLayout.addView(webView);

这里是回调 url
private static final String CALLBACK_URL = "oauth-testing:///";
,您正在创建一个动态 webview 并向用户显示。登录后,webview 关闭,代码进入onNewIntent(). 您需要在登录后实现您的功能。

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    dealWithTwitterResponse(intent);
}  
private void dealWithTwitterResponse(Intent intent) {
    Uri uri = intent.getData();
    System.out.println("URI=" + uri);
    if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
        String oauthVerifier = uri.getQueryParameter("oauth_verifier");
        authoriseNewUser(oauthVerifier);
    }
}

我知道我已经添加了很多代码片段,其中一些可能不相关,但我希望有一天它会对某人有所帮助。

于 2012-10-01T13:19:29.173 回答
0

好吧,首先您可能需要调用您的服务提供商提供的 URL,如果存在任何重定向,您将获得 HTTP 状态代码 3xx。接下来,如果存在任何重定向,您可以尝试调用实际 URL。对于正常的 HTTP 响应,您将获得 HTTP 2xx 状态码。

于 2012-10-01T13:15:05.400 回答
0

由于您拥有 WebView 的对象,因此您可以重载它,然后以这两种方式处理您想要导航到 Activity 的 url。

private  class MyWebView extends WebViewClient{   
            @TargetApi(Build.VERSION_CODES.N)
            @Override
            public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request)
            {
                Uri uri = request.getUrl();
                return shouldOverrideUrlLoading(uri.toString());
            }

            private boolean shouldOverrideUrlLoading(final String url)
            {
                Log.i(TAG, "shouldOverrideUrlLoading() URL : " + url);
                   //your code to handle the url for navigation will go here
                try{
                      if(url.contains("yourcondition")){
                        //1st way to handle 
                        Intent intent = new Intent(Intent.ACTION_VIEW);
                        intent.setData(Uri.parse(url));
                        YourActivity.this.startActivity(intent);
                       }else{
                           //2nd way 
                        Intent intent = new Intent(YourActivity.this,NewActivity.class);
                        //you can set the data 
                        intent.setData(Uri.parse(url));
                        YourActivity.this.startActivity(intent);
                       }
                     }catch(ActivityNotFoundException e) {    
                       Log.e(LOGTAG,"Could not load url"+url);
                    }                    
               return false;
               // return true; // this True means that application wants to leave the WebView and try to go to browser and handle the url itself, otherwise return false.
             } 
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) 
    {


        try {
              if(url.contains("yourcondition")){
                //1st way to handle 
              Intent intent = new Intent(Intent.ACTION_VIEW);
              intent.setData(Uri.parse(url));
              YourActivity.this.startActivity(intent);
            }else{
           //2nd way 
            Intent intent = new Intent(YourActivity.this,NewActivity.class);
           //you can set the data 
            intent.setData(Uri.parse(url));
            YourActivity.this.startActivity(intent);
            }

        }   catch(ActivityNotFoundException e) {

            Log.e(LOGTAG,"Could not load url"+url);
        }

        return false;     
    }
}

您可以设置 mWebView.setWebViewClient(new WebViewClient());默认设置,但只需添加默认自定义 WebViewClient 将仅允许 WebView 处理任何已加载的 url 本身,即在 webView 而不是浏览器中。

但是如果你通过上面的传递来重载,class MyWebView那么mWebView.setWebViewClient(new MyWebView());你可以控制 url 的加载,你可以实现同样的事情

myWebView.setWebViewClient(new WebViewClient(){ 

                @TargetApi(Build.VERSION_CODES.N)
                @Override
                public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request)
                {
                    Uri uri = request.getUrl();
                    return shouldOverrideUrlLoading(uri.toString());
                }

                private boolean shouldOverrideUrlLoading(final String url)
                {
                    Log.i(TAG, "shouldOverrideUrlLoading() URL : " + url);
                       //your code to handle the url for navigation will go here
                    try{
                          if(url.contains("yourcondition")){
                            //1st way to handle 
                            Intent intent = new Intent(Intent.ACTION_VIEW);
                            intent.setData(Uri.parse(url));
                            YourActivity.this.startActivity(intent);
                           }else{
                               //2nd way 
                            Intent intent = new Intent(YourActivity.this,NewActivity.class);
                            //you can set the data 
                            intent.setData(Uri.parse(url));
                            YourActivity.this.startActivity(intent);
                           }
                         }catch(ActivityNotFoundException e) {    
                           Log.e(LOGTAG,"Could not load url"+url);
                        }                    
                   return false;
                   // return true; // this True means that application wants to leave the WebView and try to go to browser and handle the url itself, otherwise return false.
                 } 

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) 
    {

        try {
             if(url.contains("yourcondition")){
             //1st way to handle
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(url));
            YourActivity.this.startActivity(intent);
            }else{
             //2nd way 
                Intent intent = new Intent(YourActivity.this,NewActivity.class);
           //you can set the data 
            intent.setData(Uri.parse(url));
            YourActivity.this.startActivity(intent);
           }    
        }   catch(ActivityNotFoundException e) {

            Log.e(LOGTAG,"Could not load url"+url);
        }

        return false;      

    }});

如果您无法控制 webview 对象,那么这不是我将在解决此问题后更新的解决方案。

于 2017-08-09T09:31:06.630 回答