今天学习的是OSC客户端的微博分享模块,界面如下
这个功能是我们在很多app上都需要实现的功能,这里涵盖了OAuthV2 OAuthV3 以及调用Webview进行分享三种方式 希望通过这个功能的学习可以举一反三.
首先是新浪微博.
osc使用的是新浪微博V2的分享模块,并对V2的sdk做了裁剪和改造,限于篇幅,这里不sdk的说明,请自行参考com.weibo.net包
新浪微博,授权过程的时序图如下
1- 2 在分享的activity: ScreenShotShare,点击按钮后将调用shareToSinaWeibo函数开始发送微博.这是执行getAccessInfo函数会获取在本地存储的有新浪微博认证的token 如果本地没有存储将返回null
代码如下
/** * 分享到新浪微博 */ private void shareToSinaWeibo(String content, final String imagePath) { AppConfig cfgHelper = AppConfig.getAppConfig(this); final AccessInfo access = cfgHelper.getAccessInfo(); final String shareMsg = content; // 初始化微博 if (SinaWeiboHelper.isWeiboNull()) { SinaWeiboHelper.initWeibo(); } // 判断之前是否登陆过 if (access != null) { SinaWeiboHelper.progressDialog = new ProgressDialog(this); SinaWeiboHelper.progressDialog .setProgressStyle(ProgressDialog.STYLE_SPINNER); SinaWeiboHelper.progressDialog.setMessage(this .getString(R.string.sharing)); SinaWeiboHelper.progressDialog.setCancelable(true); SinaWeiboHelper.progressDialog.show(); new Thread() { public void run() { SinaWeiboHelper.setAccessToken(access.getAccessToken(), access.getAccessSecret(), access.getExpiresIn()); SinaWeiboHelper.shareMessage(ScreenShotShare.this, shareMsg, imagePath); } }.start(); } else { SinaWeiboHelper .authorize(ScreenShotShare.this, shareMsg, imagePath); } }
3.使用 SinaWeiboHelper 的 initWeibo()函数初始化微博对象
weibo = Weibo.getInstance(); weibo.setupConsumerConfig(CONSUMER_KEY, CONSUMER_SECRET); weibo.setRedirectUrl(REDIRECT_URL);这段代码对于做个微博开发的同学应该并不陌生
4.在第二步 .如果没有存储token 那么拿到的access为空,那么就开始调用SinaWeiboHelper的authorize函数进行授权的过程了.这时候就会弹出那个新新浪授权的webview了.
SinaWeiboHelper的authorize函数代码如下
/** * 微博授权 并 分享(文本、图片) */ public static void authorize(final Activity cont,final String shareMsg,final String shareImg) { context = cont; if(isWeiboNull()) { initWeibo(); } weibo.authorize(cont, new WeiboDialogListener() { @Override public void onComplete(Bundle values) { try { String token = values.getString(Weibo.TOKEN); String expires_in = values.getString(Weibo.EXPIRES); accessToken = new AccessToken(token, CONSUMER_SECRET); accessToken.setExpiresIn(expires_in); //保存AccessToken AppConfig.getAppConfig(cont).setAccessInfo(accessToken.getToken(), accessToken.getSecret(), accessToken.getExpiresIn()); //微博分享 shareMessage(cont, shareMsg, shareImg); } catch (Exception e) { e.printStackTrace(); } } @Override public void onError(DialogError e) { Toast.makeText(context,"授权失败 : " + e.getMessage(), Toast.LENGTH_LONG).show(); } @Override public void onCancel() { //Toast.makeText(context, "取消授权", Toast.LENGTH_LONG).show(); } @Override public void onWeiboException(WeiboException e) { Toast.makeText(context,"授权异常 : " + e.getMessage(), Toast.LENGTH_LONG).show(); } }); }5 系统会再次检查一下weibo对象是否为空,如果是那么再次初始化一下weibo对象,
6. 然后就真正打开sdk中那个带有webview的activity进行授权了.这个动作在weibo.authorize()函数中执行
7. sdk中weibview的处理我们不做介绍了,下面看授权之后的回调,如果成功,就会执行inComplete函数:使用AppConfig保存token供下次使用 AppConfig可能会在以后的学习中介绍到.
@Override public void onComplete(Bundle values) { try { String token = values.getString(Weibo.TOKEN); String expires_in = values.getString(Weibo.EXPIRES); accessToken = new AccessToken(token, CONSUMER_SECRET); accessToken.setExpiresIn(expires_in); //保存AccessToken AppConfig.getAppConfig(cont).setAccessInfo(accessToken.getToken(), accessToken.getSecret(), accessToken.getExpiresIn()); //微博分享 shareMessage(cont, shareMsg, shareImg); } catch (Exception e) { e.printStackTrace(); } }9.拿到了token就调用获得的token发送微博了
这样,在下次再次进行发送的时候,执行到第三个步骤的时候, 就会使用从本地获取的token进行发送微博了.
这里有一点需要注意:根据自己以前的实践和对osc的测试,发现新浪token获取后会有些延时,在获取了token荣国立即使用者token很有可能导致失败.故此我的建议是授权后回到shareactivity 让用户点击发送 完成对文字的发送
然后是QQ微博.,QQ微博使用的是V1的接口,这里作者也是做sdk进行了改造和裁剪,时序图如下:
1-2在ShareScreenActivity中执行的代码很简单就是调用QQWeiboHelper2 的send函数
/** * 分享到QQ微博 */ @SuppressLint("NewApi") private void shareToQQWeibo(String content, String imagePath) { helper = new QQWeiboHelper2(this, content, imagePath); helper.send(); }3.send函数如下,我们看到,对于QQ微博的保存使用的是AppContext读取 序列化 到本地的Oauth对象,读取过程请参考介绍序列化缓存的文章.
/** * 发送 * @throws NotCallBackException */ public void send() { ac = (AppContext) context.getApplication(); // 获取凭证流程优先级: 内存 ->外存 ->网络 if (OAuthV1Cache == null) { OAuthV1 oa = (OAuthV1) ac.readObject(OAUTH_CACHE_FILE); if (oa == null) { authenticate(); } else { oAuth = OAuthV1Cache = oa; sendMessage(); } } else { oAuth = OAuthV1Cache; sendMessage(); } }4.如果为空就去打开Weiview进行授权了:
/** * 认证 * * @throws Exception */ private void authenticate() { oAuth = new OAuthV1(oauthCallback); oAuth.setOauthConsumerKey(APP_KEY); oAuth.setOauthConsumerSecret(APP_SECRET); OAuthV1Client.getQHttpClient().shutdownConnection(); OAuthV1Client.setQHttpClient(new QHttpClient()); new Thread() { @Override public void run() { Message msg = mHandler.obtainMessage(REQUEST); try { msg.obj = OAuthV1Client.requestToken(oAuth); mHandler.sendMessage(msg); } catch (Exception e) { e.printStackTrace(); } }; }.start(); }5-11 经过一系列的初始化后, 应用想QQ服务器发送异步请求获取未授权的Request Token ,并发送消息
msg.obj = OAuthV1Client.requestToken(oAuth);
mHandler.sendMessage(msg);
12 如果成功拿到了request token机会 跳转到一个含有WebView的Activity进行授权:
case REQUEST: oAuth = (OAuthV1) msg.obj; if (oAuth.getStatus() == 1) { UIHelper.ToastMessage(context, "Request Token 授权不通过"); } else { Intent intent = new Intent(context, OAuthV1AuthorizeWebView.class); intent.putExtra("oauth", oAuth); context.startActivityForResult(intent, AUTH_VIEW_REQUEST_CODE); } break;13 其实V1的授权处理比较简单,就是使用WebViewClient对象处理一下webview载入的url
WebViewClient client = new WebViewClient() { /** * 回调方法,当页面开始加载时执行 */ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { Log.i(TAG, "WebView onPageStarted..."); Log.i(TAG, "URL = " + url); if (url.indexOf("checkType=verifycode") != -1) { int start=url.indexOf("checkType=verifycode&v=")+23; String verifyCode=url.substring(start, start+6); oAuth.setOauthVerifier(verifyCode); Intent intent = new Intent(); intent.putExtra("oauth", oAuth); setResult(RESULT_CODE, intent); view.destroyDrawingCache(); finish(); } super.onPageStarted(view, url, favicon); } }; webView.setWebViewClient(client); }14.我们知道,在授权的Activity finish后会调用ScreenShareActivity的onActivityResult回调,代码如下
/** * 认证页回调 */ protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (helper != null) { helper.onAuthorizeWebViewReturn(requestCode, resultCode, data); } }
原理来时又调用进入了QQAuthHelper2的onAuthorizeWebViewReturn函数进行处理,主要功能是
使用授权后的Request Token换取Access Token
public void onAuthorizeWebViewReturn(int requestCode, int resultCode, Intent data) { isCallBack = true; if (requestCode == AUTH_VIEW_REQUEST_CODE) { if (resultCode == OAuthV1AuthorizeWebView.RESULT_CODE) { oAuth = (OAuthV1) data.getExtras().getSerializable("oauth"); if (oAuth.getStatus() == 2) { UIHelper.ToastMessage(context, "获取验证码失败"); } else { new Thread() { @Override public void run() { Message msg = mHandler.obtainMessage(ACCESS); try { msg.obj = OAuthV1Client.accessToken(oAuth); mHandler.sendMessage(msg); } catch (Exception e) { e.printStackTrace(); } }; }.start(); } } } }
成功拿到accesstoken,就会发送消息通知AppContext把获取到的oauth保存到本地
case ACCESS: oAuth = (OAuthV1) msg.obj; if (oAuth.getStatus() == 3) { UIHelper.ToastMessage(context, "Access失败"); } else { OAuthV1Cache = oAuth; ac.saveObject(oAuth, OAUTH_CACHE_FILE); QQWeiboHelper2.this.sendMessage(); } break;
下一次发送QQ微博,就可以直接读取Oauth对象发送啦!
最后是使用网页形式发表QQ微博
这个最简单,其实就是拼接新闻标题和地址,然后调用浏览器,代码如下 这个也有它的优点,开发成本低,稳定性高
public class QQWeiboHelper { private static final String Share_URL = "http://share.v.t.qq.com/index.php?c=share&a=index"; private static final String Share_Source = "OSChina"; private static final String Share_Site = "OSChina.net"; private static final String Share_AppKey = "96f54f97c4de46e393c4835a266207f4"; /** * 分享到腾讯微博 * @param activity * @param title * @param url */ public static void shareToQQ(Activity activity,String title,String url){ String URL = Share_URL; try { URL += "&title=" + URLEncoder.encode(title, HTTP.UTF_8) + "&url=" + URLEncoder.encode(url, HTTP.UTF_8) + "&appkey=" + Share_AppKey + "&source=" + Share_Source + "&site=" + Share_Site; } catch (Exception e) { e.printStackTrace(); } Uri uri = Uri.parse(URL); activity.startActivity(new Intent(Intent.ACTION_VIEW, uri)); } }