本文转自:http://www.cnblogs.com/hll2008/archive/2011/04/30/2033481.html
前面的文章的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);
4、在WebViewActivity中onCreate方法中获取上面传过来的url进行认证网页显示,代码如下:
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);
}
}
}
5、上面Url参数中我们并没有提供CallBackUrl参数,这个时候当用户输入账号和密码点击授权后会显示pin码(oauth_verifier值)页面,而不在会跳转,页面如下:
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);
添加类JavaScriptInterface
class JavaScriptInterface
{
public void getHTML(String html)
{
String pin = getPin(html);
// 这里就获取到了我们想要的pin码
// 这个pin码就是oauth_verifier值,用来进一步获取Access Token和Access Secret用
Log.e( " pin " , pin);
}
}
7、这样我们就获取到了当前WebView的html代码,接下来就是提取html中的授权码,html代码如下:
< 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 >
提取授权码用正则实现的,java方法代码如下:
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;
}
这样就完成了所有的实现了,这做虽然有点麻烦,但是彻底解决了以前存在的问题。