前面的文章的OAuth认证过程在获取oauth_verifier码是是通过调用android系统带的浏览器进行用户授权认证的, 具体见:android开发我的新浪微博客户端-用户授权页面功能篇(3.2)。
当初的实现是这样:
1、首先在AndroidManifest.xml中配置给AuthorizeActivity添加如下配置<data android:scheme="myapp" android:host="AuthorizeActivity" /> ,这样在浏览器中通过地址myapp://AuthorizeActivity启动AuthorizeActivity这个Activity.
2、在用android系统带的浏览器显示用户授权页面的时候,把"myapp://AuthorizeActivity"作为url参数CallBackUrl=myapp://AuthorizeActivity,这样当用户输入完账号和密码会请求myapp://AuthorizeActivity?oauth_verifier=123456这个地址,这个时候就自然启动了AuthorizeActivity这个Activity.
3、当AuthorizeActivity被启动的时候,在onNewIntent方法中通过Uri uri = intent.getData();获取oauth_verifier值123456。
这样的实现有个弊端:
就是当用户认证是选择用uc等第三方的浏览器进行用户认证时,当用户输入账号密码后点击授权按钮后不会跳转到AuthorizeActivity这个Activity,只有用android自带的浏览器才没有问题。其实这个是个比较严重的问题了大多数的用户都会用uc等第三方的浏览器了,这样导致认证不能正常进行。
最近在尝试iphone下的oauth认证的时候发现一个很好的思路,那就是不要用系统带的浏览器而且在自己的程序中嵌入一个WebView在这个WebView控件中完成用户授权认证而不再使用额外的浏览器。今天抽了空把在iphone下的实现思路搬到了android下,做了如下的尝试。
现在的实现是这样:
1、首先上面的那3点都可以不需要了,该删除的删除。
2、新建一个名为WebViewActivity的ViewActivity,在这个ViewActivity就只有一个WebView控件
Layout文件如下:
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <WebView android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/web"> </WebView> </ScrollView>
3、修改OAuth过程在获取(Request Token和Request Secret)后,启动WebViewActivity,在这个WebViewActivity的WebView控件显示用户认证的网页,代码实现如下:
//Url类似:http://api.t.sina.com.cn/oauth/authenticate?oauth_token=71c6df7fd0b4e1e5c491faa90b654fdf&from=xweibo String Url=getAuthenticationURL(); Intent intent = new Intent(MainActivity.this, WebViewActivity.class); Bundle b=new Bundle(); b.putString("url", url); intent.putExtras(b); startActivity(intent);
super.onCreate(savedInstanceState); setContentView(R.layout.webview); WebView wv =(WebView) findViewById(R.id.web); Intent i=this.getIntent(); if(!i.equals(null)){ Bundle b=i.getExtras(); if(b!=null){ if(b.containsKey("url")){ String url = b.getString("url"); //这行很重要一点要有,不然网页的认证按钮会无效 wv.getSettings().setJavaScriptEnabled(true); wv.getSettings().setSupportZoom(true); //wv.getSettings().setDefaultZoom(WebSettings.ZoomDensity.FAR); wv.getSettings().setBuiltInZoomControls(true); wv.loadUrl(url); } } }
6、上一步中已经在WebView显示出了授权码,我们接下来要做的就是获取这个授权码176048,这个既然是显示在WebView中的网页,那么我们获取当前的这个WebView显示的html代码然后从中提取出授权码不就可以了。获取html代码是通过调用javascript实现的,不难就解释了看具体代码,在onCreate方法添加如下代码:
wv.addJavascriptInterface(new JavaScriptInterface(), "Methods"); WebViewClient wvc=new WebViewClient() { @Override public void onPageFinished(WebView view,String url) { view.loadUrl("javascript:window.Methods.getHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');"); super.onPageFinished(view, url); } }; wv.setWebViewClient(wvc);
class JavaScriptInterface { public void getHTML(String html) { String pin= getPin(html); //这里就获取到了我们想要的pin码 //这个pin码就是oauth_verifier值,用来进一步获取Access Token和Access Secret用 Log.e("pin", pin); } }
<head><head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width"> <title>应用授权 - 新浪微博</title> <link href="http://timg.sjs.sinajs.cn/t35/style/css/open/open_third.css" rel="stylesheet" type="text/css"> </head><body> <div class="opthBg"> <div class="opthTopBg"><div class="opthHead"><a href="http://weibo.com" class="newlogo"></a></div></div> <div class="opthBox"> <div class="opthCen"> <br><br> <font size="4"><b>获取到授权码:176048</b></font> <br><br> <div class="opthBottom"> <div class="lf"></div> <div class="rt"> </div> </div> </div> </div> </div> <script type="text/javascript"> function canchange() { document.forms['authZForm'].from.value='turnuser'; document.forms['authZForm'].action.value=''; document.forms['authZForm'].submit(); } </script> </body></head>
public String getPin(String html) { String ret=""; String regEx="[0-9]{6}"; Pattern p=Pattern.compile(regEx); Matcher m=p.matcher(html); boolean result=m.find(); if(result) { ret= m.group(0); } return ret; }