本文原创http://blog.csdn.net/yanbin1079415046,转载请注明出处。
从事android工作也有段时间了,碍于肚子里料不多,一直也没写过什么东西。最近刚好项目中要接入新浪微博,就顺便研究了一下android客户端接入腾讯微博和人人网。由于是第一次写东西,加上本人小菜鸟一个,请高手勿喷,觉得文章没用的飘过,当然啦,觉得还有点用的就看看吧。好了,废话不多说了,进入我们的正题吧。
一:这是个什么东西?
说白了,接入微博就是让你的应用程序可以调用新浪微博,腾讯微博和人人网的api,实现微博发送,分享给好友等等的功能啦。当然也可以实现让你的客户端使用微博账号进行登录。我们这篇文章要讲的就是访问这些社交平台提供的api的时候比较关键的一步,获取调用api接口的token,token可以理解为我们的客户端程序与社交平台api交互的令牌。
二:官方教程在哪里?
学习东西,当然是官方的东西最好了。下面我们就简单说说接入新浪,腾讯微博以及人人网的官方教程吧。同学们也可以自行去看官方的教程,那么我下面写的东西就可以忽略不计了。
新浪微博 api:http://open.weibo.com/wiki/%E9%A6%96%E9%A1%B5
首先,当然你得有一个新浪微博的账号啦。然后就是注册应用啊等等一代堆东西,自己去 开发指南--新手引导 中看吧。然后,就要填写我们的信息了。这里要注意授权页的填写,在 我的应用--应用信息--高级信息--授权回调页 这里,如下图1。最后,就是如何对我们的客户端程序进行授权了。新浪微博的授权机制说明如下:大部分API的访问如发表微博、获取私信,关注都需要用户身份。目前新浪微博开放平台用户身份鉴权有OAuth2.0和Basic Auth(仅用于应用所属开发者调试接口)两种方式。我们这里采用的是OAuth2.0的授权机制。
如何获取token,我们将在下面的文章中结合代码进行讲解。
图1 设置授权回调页
腾讯微博 api:http://dev.t.qq.com/
腾讯微博的应用申请和新浪微博的类似,它也有一个授权回调页。不过它不是这个名字,它的名字是:应用网址。为简单起见,我们这里也使用默认的地址,即:http://www.tencent.com/zh-cn/index.shtml 其他的和腾讯微博差不多,就不赘述了。腾讯微博提供了OAuth 1.0a,OAuth2.0和OpenId&OpenKey授权方式,本人中采用的是OAuth2.0授权方式,其他的方式同学们自行研究。
人人网 api:http://dev.renren.com/ 人人网使用OAuth 2.0作为验证与授权协议。
2012.10月编辑:
人人网目前有一个移动开发者平台,专门为移动应用和HTML5应用提供更简洁的授权接口,简单易用,称为人人移动开发者中心。地址如下:
http://dev.mobile.renren.com/home/show
三:关于OAuth2.0
本人比较懒,就不把概念贴在这里了。自己百度去吧,百度百科中有这样的一句概括:OAuth 2.0关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。这里我们稍微说一下OAuth2.0的认证流程。文章请看这里:http://blog.unvs.cn/archives/oauth-qq2.0-developer.html。首先感谢这位哥们,然后不想点开链接的同学就直接看下面的吧。
在OAuth2.0的处理流程,主要分为以下四个步骤:
上面是流程的大概四个步骤,在下面的流程示意图中会得到体现,这是我制作的一个幻灯片的流程图(文章最后会附上制作的OAuth幻灯片分享给大家),这里就直接截图下来进行讲解:
第一步:首先直接跳转至用户授权地址,即图示 Request User Url ,提示用户进行登录,并给予相关资源授权,得到唯一的Auth code,这里注意的是code只有10分钟的有效期,对于安全考虑,相对于OAuth1.0省了一步获取临时的Token,并且有效期也进行了控制,比1.0认证简化了很多,并安全一些;
第二步:得到授权code后,这一步就是请求access token,通过 图示 Request access url ,生成得到数据Token;
第三步:通过Access Token请求OpenID,openid是用户在此平台的唯一标识,通过 图示 Request info url 请求,然后得到OpenID;
第四步:通过第二步得到的数据Token、第三步得到的OpenID及相关API,进行请求,获取用户授权资源信息。(我喜欢简洁明了,OAuth2.0认证流程就是这样,相信通过图示及讲解都能明白,若有不明白之处请留言)
四:让你的应用程序访问社交平台api(获取token)。注意要加相应的权限,文章后面会贴出清单文件中所需的权限。
新浪微博授权:
详细内容请参见新浪微博SDK中自带的文档:Android平台微博SDK说明文档.docx。它在SDK的工程目录下, 所以你要导入SDK工程的时候主要把它去了。由于新浪微博给我们提供的SDK是以工程的方式给出的,所以我们需要引用它的工程才可以使用它提供的api。当然啦,这样放到实际环境中是不行的。所以我们可以将SDK下的相关文件拷贝到我们的自己的工程目录下即可,注意修改相应的东西。本人是这样做的,不知道还有没有更好的方式。具体的请看文章后面给出的demo。值得一提的是,人人网也是以这种方式提供SDK的,但是腾讯微博给我们提供的是JAR,这个看起来就简洁多了。这里顺便说一下覆盖的方法吧,就是将新浪微博给我们提供的SDK工程文件下的src和res文件夹拷贝到你自己的工程中覆盖原有的文件即可。
环境准备好了,我们就可以开始进行代码的编写了。还是那句话,有官方教程在呢,同学们可以对着教程来练习,我下面只是结合代码简单的说一下。
//sina CONSUMER_KEY、CONSUMER_SECRET替换成你自己应用的key和secret private static final String CONSUMER_KEY = "913917729"; private static final String CONSUMER_SECRET = "32c47f37e4727ce9c0db1ceee12bf765"; private String redirectUriSina="http://www.sina.com"; //授权回调页 与 我的应用--应用信息--高级信息 中一致 OAuthV2 authV2 = null;//腾讯微博Oauth Renren renren = null;//renren File file = null; String basepath = ""; //tencent CLINETID、CLIENTSECRET替换成你自己应用的key和secret private static final String CLINETID = "801208558"; private static final String CLIENTSECRET = "da6d09bb537559c37cb36561fd825346"; //认证成功后浏览器会被重定向到这个url中 必须与注册时填写的一致 private String redirectUriTen="http://www.tencent.com/zh-cn/index.shtml"; //renren API_KEY、SECRET_KEY替换成你自己应用的key和secret private static final String API_KEY = "b6f9602ab3714023b794d34b51639a99"; private static final String SECRET_KEY = "f51ce08118014784a0579ba88730b6bd"; private static final String APP_ID = "206681";//人人网还需要app_id private static final int RENREN_REQUEST_CODE = 123; String accessToken;
//新浪微博认证 Weibo weibo = Weibo.getInstance(); if(!isOauthSina(weibo)){ weibo.setupConsumerConfig(CONSUMER_KEY, CONSUMER_SECRET);//设置你的key和secret weibo.setRedirectUrl(redirectUriSina); weibo.authorize(this, new OauthDialogListener()); }else{ tv.setText("access_token : " + accessToken); Toast.makeText(getApplicationContext(), "该用户已经授权", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(); intent.putExtra("accessToken", accessToken); intent.putExtra("flag", MyContent.SINA); intent.setClass(InsertWeiboActivity.this, TestActivity.class); startActivity(intent); }
isOauthSina方法如下,它的作用是判断用户是否已经对我们的应用进行了授权。
/** * 新浪微博 用户是否已经授权 * @param weibo * @return */ private boolean isOauthSina(Weibo weibo){ boolean b = false; accessToken = getSharedPreferences("token", Context.MODE_PRIVATE).getString("access_token", ""); if(weibo != null && !accessToken.equals("")){ b = true; } return b; }
上面的两段代码中, 值得注意的地方是redirectUriSina,它是一个String类型的参数,值就是我们在之前提到过得那个授权回调页的地址。接着新浪微博将弹出一个授权页面的对话框,供用户输入用户名和密码(此处就不截图,自己跑demo看吧)。在用户输入用户名和密码之后,它将被我们的OauthDialogListener类监听到,它的实现如下:
/** * 弹出新浪微博的授权页面 * @author yanbin * */ private class OauthDialogListener implements WeiboDialogListener{ @Override public void onComplete(Bundle values) { String token = values.getString("access_token"); String expires_in = values.getString("expires_in"); tv.setText("access_token : " + token + " expires_in: " + expires_in); AccessToken accessToken = new AccessToken(token, CONSUMER_SECRET); SharedPreferences sf = getSharedPreferences("token", Context.MODE_PRIVATE); sf.edit().putString("access_token", accessToken != null ? accessToken.getToken() : "") .commit(); // accessToken.setExpiresIn(expires_in); // Weibo.getInstance().setAccessToken(accessToken); Intent intent = new Intent(); intent.putExtra("accessToken",accessToken.getToken()); intent.putExtra("flag", MyContent.SINA); intent.setClass(InsertWeiboActivity.this, TestActivity.class); startActivity(intent); } @Override public void onWeiboException(WeiboException e) { //未作处理 } @Override public void onError(DialogError e) { //未作处理 } @Override public void onCancel() { Toast.makeText(InsertWeiboActivity.this, "您已经取消授权", 1).show(); } }
WeiboDialogListener中有一个回调方法,它会在用户输入正确的用户名和密码之后返回给我们的客户端程序获取新浪微博提供的api的令牌(这个东西很重要的,你调用新浪微博api的时候每次都必须把它带上)。接下来的工作就是保存此token供下次使用了。这里我们存储在SharedPreference中。至此,我们就获取了新浪微博的token,接下来就可以操作新浪微博api了,比如发布一条微博,可以试试哦。
腾讯微博授权:
腾讯微博授权的官方实例请看这里,http://wiki.open.t.qq.com/index.php/%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8%E6%8E%A5%E5%85%A5/Android_SDK_V1.2。下面我们结合代码说说我们的实现。
首先第一步就是得到腾讯给我们提供的授权回调页,代码如下,由于要弹出OAuthV2AuthorizeWebView这个页面,所以要在清单文件中声明。
//判断用户是否已经授权 if(!isOauchTen()){ //使用回调url来创建授权页面 authV2 = new OAuthV2(redirectUriTen); authV2.setClientId(CLINETID); authV2.setClientSecret(CLIENTSECRET); //关闭OAuthV2Client中的默认开启的QHttpClient。 OAuthV2Client.getQHttpClient().shutdownConnection(); Intent intent = new Intent(InsertWeiboActivity.this, OAuthV2AuthorizeWebView.class);//创建Intent,使用WebView让用户授权 intent.putExtra("oauth", authV2); startActivityForResult(intent,2); }else{ Toast.makeText(getApplicationContext(), "该用户已经授权", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(); intent.putExtra("oauth", authV2); intent.putExtra("flag", MyContent.TENCENT); intent.setClass(InsertWeiboActivity.this, TestActivity.class); startActivity(intent); }
这里我们看到了startActivityForResult,它会在用户输入完用户名和密码后执行OnActivityResult方法(包括了人人的实现),isOauthTen()方法的作用是判断用户是否已经授权过该应用。它们的代码如下:
OnActivityResult()方法:
/** * 新浪微博和人人网的授权 * 通过读取OAuthV2AuthorizeWebView返回的Intent,获取用户授权信息 */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode==2) { //腾讯微博授权 if (resultCode==OAuthV2AuthorizeWebView.RESULT_CODE) { OAuthV2 oAuth=(OAuthV2) data.getExtras().getSerializable("oauth"); if(oAuth != null && oAuth.getStatus()==0){ Toast.makeText(getApplicationContext(), "登陆成功", Toast.LENGTH_SHORT).show(); //跳转到发微博的界面 Intent intent = new Intent(); intent.putExtra("accessToken", oAuth.getAccessToken()); intent.putExtra("oauth", oAuth); intent.putExtra("flag", MyContent.TENCENT); //将认证保存起来,使用对象流 FileOutputStream fos = null; ObjectOutputStream oos = null; try { fos = new FileOutputStream(file); oos = new ObjectOutputStream(fos); oos.writeObject(oAuth); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ if(oos != null){ try { oos.close(); oos = null; } catch (IOException e) { e.printStackTrace(); } if(fos != null){ try { fos.close(); fos = null; } catch (IOException e) { e.printStackTrace(); } } } } intent.setClass(InsertWeiboActivity.this, TestActivity.class); startActivity(intent); } else Toast.makeText(getApplicationContext(), "登陆失败", Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(getApplicationContext(), "授权失败", Toast.LENGTH_SHORT).show(); } }else if(requestCode == RENREN_REQUEST_CODE){ //人人网授权 if (renren != null) { renren.authorizeCallback(requestCode, resultCode, data); }else{ Toast.makeText(getApplicationContext(), "授权失败", Toast.LENGTH_SHORT).show(); } } }
isOauchTen()方法:
/** * 腾讯微博接入是否已经验证 * @return */ private boolean isOauchTen() { boolean b = false; FileInputStream fis = null; ObjectInputStream ois = null; try { openFileOutput("aaa", Context.MODE_PRIVATE); persistTenOauth(); fis = new FileInputStream(file); ois = new ObjectInputStream(fis);//此处抛出EOFException,原因是独到了流的末尾还是返回空,我们这里直接在异常中将标志位记为false即可。 authV2 = (OAuthV2) ois.readObject(); if(authV2 != null){ b = true; } } catch (Exception e) { b = false; } finally{ if(ois != null){ try { ois.close(); ois = null; } catch (Exception e2) { e2.printStackTrace(); } } if(fis != null){ try { fis.close(); fis = null; } catch (Exception e2) { e2.printStackTrace(); } } } return b; }
persistTenOauth()方法的作用是将我们获取到的token存储起来,由于调用腾讯微博api需要Token对象,没有办法所以我们只有将Token对象存起来,这里使用对象流的方式,具体实现如下:
/** * 将腾讯微博的oauth持久化到文件中 */ private void persistTenOauth(){ //加这一句的作用是防止 /data/data/package-name这个目录不存在 String s = getFileStreamPath("aaa").getAbsolutePath(); for(String ss : fileList()){ System.out.println("ss==" + ss); } String x = ""; try{ x = s.substring(0,s.lastIndexOf("/")); }catch(Exception e){ e.printStackTrace(); x = "/data/data/yanbin.insertweibo"; } //将文件存放在 /data/data/package-name目录下,当然你也可以存储在别的地方 try { file = new File(x + "/oauth_ten.data"); if(!file.exists()){ new File(x).mkdirs(); file.createNewFile(); } } catch (Exception e) { e.printStackTrace(); } }
至此,我们已经成功的获取到了访问腾讯微博必须的令牌,接下来我们就可以使用这个令牌操纵api了。
人人网授权:
人人网并没有实现发心情的功能,只是简单的获取了它的token。
实现的代码如下:
if(!isOauthRenren()){ renren = new Renren(API_KEY, SECRET_KEY, APP_ID, this); renren.authorize(this, null, new MyRenrenListener(), RENREN_REQUEST_CODE); }else{ Toast.makeText(getApplicationContext(), "该用户已经授权", Toast.LENGTH_SHORT).show(); }
isOauthRenren用来判断用户是否对本客户端进行了授权。MyRenrenListener类会在用户在输入框中输入用户名和密码后回调。它们的具体实现如下:
isOauthRenren()方法:
/** * renren 判断用户是否已经授权 * @return */ private boolean isOauthRenren(){ boolean b = false; String token = getSharedPreferences("oauth_renren", Context.MODE_PRIVATE).getString("access_token", ""); if(!"".equals(token)){ b = true; } return b; }
MyRenrenListener类的实现:
/** * 人人请求用户授权返回界面 * @author yanbin * */ private class MyRenrenListener implements RenrenAuthListener{ @Override public void onComplete(Bundle values) { //服务器端返回的数据 // { // "access_token": "10000|5.a6b7dbd428f731035f771b8d15063f61.86400.1292922000-222209506", // "expires_in": 87063, // "refresh_token": "10000|0.385d55f8615fdfd9edb7c4b5ebdc3e39-222209506", // "scope": "read_user_album read_user_feed" // } Bundle bundle = values; String access_token = bundle.getString("access_token"); int expires_in = bundle.getInt("expires_in"); String refresh_token = bundle.getString("refresh_token"); String scope = bundle.getString("scope"); System.out.println("验证服务器端返回的数据-->" + "access_token-->" + access_token + ",expires_in-->" + expires_in + ",refresh_token-->" + refresh_token + ",scope-->" + scope); SharedPreferences sp = getSharedPreferences("oauth_renren", Context.MODE_PRIVATE); sp.edit().putString("access_token", access_token).commit(); Toast.makeText(getApplicationContext(), "用户授权成功", Toast.LENGTH_SHORT).show(); //结果: //验证服务器端返回的数据-->access_token-->206681|6.725b8c8b3457a7d2953868d63aaf4486.2592000.1346828400-473945629 //,expires_in-->0,refresh_token-->null, //scope-->publish_feed create_album photo_upload read_user_album status_update } @Override public void onRenrenAuthError(RenrenAuthError renrenAuthError) { Toast.makeText(getApplicationContext(), "异常", Toast.LENGTH_SHORT).show(); } @Override public void onCancelLogin() { //未作处理 } @Override public void onCancelAuth(Bundle values) { //未作处理 } }
至此,我们也成功的获取到了访问人人网api的token,接下来就是对api的操作了。下面是一些相关的类(TestActivity.java)和AndroidManifest.xml文件。
TestActivity.java:
package yanbin.insertWeibo; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import com.tencent.weibo.api.TAPI; import com.tencent.weibo.constants.OAuthConstants; import com.tencent.weibo.oauthv2.OAuthV2; import com.weibo.net.Utility; import com.weibo.net.Weibo; import com.weibo.net.WeiboException; import com.weibo.net.WeiboParameters; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; /** * 腾讯微博,新浪微博 简单的发送一条微博,可以进你自己的微博查看是否发送成功 * @author yanbin */ public class TestActivity extends Activity { Button btnSend ; EditText et; String accessToken; OAuthV2 oAuthV2,oAuthV2_2; int flag ;//flag用来标记是来自新浪,腾讯微博还是人人 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.send_weibo); accessToken = getIntent().getStringExtra("accessToken"); flag = getIntent().getIntExtra("flag", -1); oAuthV2 = (OAuthV2) getIntent().getSerializableExtra("oauth"); btnSend = (Button) findViewById(R.id.btnSend); et = (EditText) findViewById(R.id.et); } public void click(View view){ int id = view.getId(); switch (id) { case R.id.btnSend: switch (flag) { case MyContent.SINA: Weibo weibo = Weibo.getInstance(); WeiboParameters parameters = new WeiboParameters(); parameters.add("access_token", accessToken); parameters.add("status", et.getText().toString()); //发送一条微博 url https://api.weibo.com/2/statuses/update.json try { String flag = weibo.request(this, Weibo.SERVER + "statuses/update.json", parameters, Utility.HTTPMETHOD_POST, weibo.getAccessToken()); System.out.println("flag==" + flag); Toast.makeText(this, "发送微博成功", 1).show(); } catch (WeiboException e) { e.printStackTrace(); Toast.makeText(this, "发送微博失败", 1).show(); } finish(); break; case MyContent.TENCENT: TAPI tapi = new TAPI(OAuthConstants.OAUTH_VERSION_2_A); try { String response=tapi.add(oAuthV2, "json", et.getText().toString(), getHostIp()); System.out.println("response==" + response); tapi.shutdownConnection(); System.out.println("发送微博成功"); Toast.makeText(this, "发送微博成功", 1).show(); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "发送微博失败", 1).show(); } finish(); break; } break; } } /** * 获取用户ip * @return */ public static String getHostIp() { try { for (Enumeration<NetworkInterface> en = NetworkInterface .getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration<InetAddress> ipAddr = intf.getInetAddresses(); ipAddr .hasMoreElements();) { InetAddress inetAddress = ipAddr.nextElement(); if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress(); } } } } catch (SocketException ex) { } catch (Exception e) { } return null; } }
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="yanbin.insertWeibo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".InsertWeiboActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".TestActivity"></activity> <!-- OAuth Version 2. 使用 WebView 辅助进行ImplicitGrant方式授权必须 --> <activity android:name="com.tencent.weibo.webview.OAuthV2AuthorizeWebView" android:label="@string/app_name" > </activity> </application> <uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission> <uses-permission android:name="android.permission.WRITE_APN_SETTINGS"></uses-permission> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission> <!-- 在SDCard中创建与删除文件权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!-- 往SDCard写入数据权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> </manifest>
六:结束语
接入社交平台本就是一个比价简单的功能,但是由于本人能力有限,组织语言能力也有限,所以整出了这么长一个篇幅,而且感觉还讲的不是很清楚,大部分篇幅都在贴代码。第一次发文章,感觉吧,特累。不说了,有需要的朋友直接去下demo自己捉摸捉摸吧。
DEMO下载地址:http://download.csdn.net/detail/yanbin1079415046/4497659