今天弄了下新浪微博SSO登录方式及OAUTH2.0认证和获取我的微博,实现的效果如下图:
//==========================================================================================================================
就这么简单的界面,简单的请求json,我居然弄了一整天,主要是新浪微博的文档写的看不懂,感觉他们的文档跟他们的sdk接不上。
遇到的一个问题是:
sso package or sign error----》
解决方法是:
使用他们提供的MD5签名apk,输入包名,即可生成md5值,输出到开放平台上就可以解决了。(我的QQ:619189810)
全部的代码:
布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:id="@+id/obtain_token_via_sso"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:text="SSO授权(仅客户端)" />
<Button
android:id="@+id/logout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="left|center_vertical"
android:text="用户登出" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textSize="16sp"
android:textStyle="bold"
android:text="Token 信息:" />
<TextView
android:id="@+id/token_text_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="12sp" />
<Button
android:id="@+id/sys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:onClick="click"
android:gravity="left|center_vertical"
android:text="我关注的微博" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:orientation="vertical"
android:id="@+id/word"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</ScrollView>
</LinearLayout>
MainActivity:
package yuan.duo.ustc.sinaclient;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.sina.weibo.sdk.auth.AuthInfo;
import com.sina.weibo.sdk.auth.Oauth2AccessToken;
import com.sina.weibo.sdk.auth.WeiboAuthListener;
import com.sina.weibo.sdk.auth.sso.SsoHandler;
import com.sina.weibo.sdk.exception.WeiboException;
import com.sina.weibo.sdk.net.RequestListener;
import com.sina.weibo.sdk.net.WeiboParameters;
import com.sina.weibo.sdk.openapi.StatusesAPI;
import com.sina.weibo.sdk.openapi.models.ErrorInfo;
import com.sina.weibo.sdk.openapi.models.Status;
import com.sina.weibo.sdk.openapi.models.StatusList;
import com.sina.weibo.sdk.utils.LogUtil;
public class MainActivity extends Activity {
protected static final String TAG = "MainActivity";
private AuthInfo mAuthInfo;
private TextView mTokenText;
private SsoHandler mSsoHandler;
private WeiboParameters parameters;
/** 封装了 "access_token","expires_in","refresh_token",并提供了他们的管理功能 */
private Oauth2AccessToken mAccessToken;
/** 用于获取微博信息流等操作的API */
private StatusesAPI mStatusesAPI;
private LinearLayout word;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
word = (LinearLayout) findViewById(R.id.word);
// 获取当前已保存过的 Token
mAccessToken = AccessTokenKeeper.readAccessToken(this);
// 对statusAPI实例化
mStatusesAPI = new StatusesAPI(this, Constants.APP_KEY, mAccessToken);
mAuthInfo = new AuthInfo(this, Constants.APP_KEY,
Constants.REDIRECT_URL, Constants.SCOPE);
mTokenText = (TextView) findViewById(R.id.token_text_view);
mSsoHandler = new SsoHandler(MainActivity.this, mAuthInfo);
findViewById(R.id.obtain_token_via_sso).setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
mSsoHandler.authorize(new AuthListener());
}
});
findViewById(R.id.logout).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
AccessTokenKeeper.clear(getApplicationContext());
mAccessToken = new Oauth2AccessToken();
updateTokenView(false);
}
});
// 从 SharedPreferences 中读取上次已保存好 AccessToken 等信息,
// 第一次启动本应用,AccessToken 不可用
mAccessToken = AccessTokenKeeper.readAccessToken(this);
if (mAccessToken.isSessionValid()) {
updateTokenView(true);
}
}
/**
* 当 SSO 授权 Activity 退出时,该函数被调用。
*
* @see {@link Activity#onActivityResult}
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// SSO 授权回调
// 重要:发起 SSO 登陆的 Activity 必须重写 onActivityResult
if (mSsoHandler != null) {
mSsoHandler.authorizeCallBack(requestCode, resultCode, data);
}
}
/**
* 微博认证授权回调类。 1. SSO 授权时,需要在 {@link #onActivityResult} 中调用
* {@link SsoHandler#authorizeCallBack} 后, 该回调才会被执行。 2. 非 SSO
* 授权时,当授权结束后,该回调就会被执行。 当授权成功后,请保存该 access_token、expires_in、uid 等信息到
* SharedPreferences 中。
*/
class AuthListener implements WeiboAuthListener {
@Override
public void onCancel() {
Toast.makeText(MainActivity.this, "授权取消", Toast.LENGTH_LONG).show();
}
@Override
public void onComplete(Bundle values) {
// 从 Bundle 中解析 Token
mAccessToken = Oauth2AccessToken.parseAccessToken(values);
if (mAccessToken.isSessionValid()) {
// 显示 Token
updateTokenView(false);
// 保存 Token 到 SharedPreferences
AccessTokenKeeper.writeAccessToken(MainActivity.this,
mAccessToken);
Toast.makeText(MainActivity.this, "授权成功", Toast.LENGTH_SHORT)
.show();
} else {
// 以下几种情况,您会收到 Code:
// 1. 当您未在平台上注册的应用程序的包名与签名时;
// 2. 当您注册的应用程序包名与签名不正确时;
// 3. 当您在平台上注册的包名和签名与您当前测试的应用的包名和签名不匹配时。
String code = values.getString("code");
String message = getString(R.string.weibosdk_demo_toast_auth_failed);
if (!TextUtils.isEmpty(code)) {
message = message + "\nObtained the code: " + code;
}
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG)
.show();
}
}
@Override
public void onWeiboException(WeiboException e) {
Toast.makeText(MainActivity.this,
"Auth exception : " + e.getMessage(), Toast.LENGTH_LONG)
.show();
}
}
/**
* 显示当前 Token 信息。
*
* @param hasExisted
* 配置文件中是否已存在 token 信息并且合法
*/
private void updateTokenView(boolean hasExisted) {
String date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
.format(new java.util.Date(mAccessToken.getExpiresTime()));
String format = getString(R.string.weibosdk_demo_token_to_string_format_1);
mTokenText
.setText(String.format(format, mAccessToken.getToken(), date));
String message = String.format(format, mAccessToken.getToken(), date);
if (hasExisted) {
message = getString(R.string.weibosdk_demo_token_has_existed)
+ "\n" + message;
}
mTokenText.setText(message);
}
public void click(View view) {
if (mAccessToken != null && mAccessToken.isSessionValid()) {
mStatusesAPI.friendsTimeline(0L, 0L, 20, 1, false, 0, false,
mListener);
}
}
/**
* 微博 OpenAPI 回调接口。
*/
private RequestListener mListener = new RequestListener() {
@Override
public void onComplete(String response) {
List<Status> list = new ArrayList<Status>();
if (!TextUtils.isEmpty(response)) {
LogUtil.i(TAG, response);
if (response.startsWith("{\"statuses\"")) {
// 调用 StatusList#parse 解析字符串成微博列表对象
StatusList statuses = StatusList.parse(response);
if (statuses != null && statuses.total_number > 0) {
Toast.makeText(MainActivity.this,
"获取微博信息流成功, 条数: " + statuses.statusList.size(),
Toast.LENGTH_LONG).show();
list = statuses.statusList;
for (Status status : list) {
TextView tv = new TextView(MainActivity.this);
tv.setText(status.text);
System.out.println(status.text);
word.addView(tv);
}
}
}
}
}
@Override
public void onWeiboException(WeiboException e) {
LogUtil.e(TAG, e.getMessage());
ErrorInfo info = ErrorInfo.parse(e.getMessage());
Toast.makeText(MainActivity.this, info.toString(),
Toast.LENGTH_LONG).show();
}
};
}
Constants接口:
package yuan.duo.ustc.sinaclient;
public interface Constants {
public static final String APP_KEY = "313569838"; // 应用的APP_KEY
public static final String REDIRECT_URL = "https://api.weibo.com/oauth2/default.html"; // 应用的回调页
public static final String SCOPE = // 应用申请的高级权限
"email,direct_messages_read,direct_messages_write,"
+ "friendships_groups_read,friendships_groups_write,statuses_to_me_read,"
+ "follow_app_official_microblog," + "invitation_write";
}
AccessTokenKeeper:
package yuan.duo.ustc.sinaclient;
import com.sina.weibo.sdk.auth.Oauth2AccessToken;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class AccessTokenKeeper {
private static final String PREFERENCES_NAME = "com_weibo_sdk_android";
private static final String KEY_UID = "uid";
private static final String KEY_ACCESS_TOKEN = "access_token";
private static final String KEY_EXPIRES_IN = "expires_in";
public static void writeAccessToken(Context context, Oauth2AccessToken token) {
if (null == context || null == token) {
return;
}
SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME,
Context.MODE_PRIVATE);
Editor editor = pref.edit();
editor.putString(KEY_UID, token.getUid());
editor.putString(KEY_ACCESS_TOKEN, token.getToken());
editor.putLong(KEY_EXPIRES_IN, token.getExpiresTime());
editor.commit();
}
public static Oauth2AccessToken readAccessToken(Context context) {
if (null == context) {
return null;
}
Oauth2AccessToken token = new Oauth2AccessToken();
SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME,
Context.MODE_PRIVATE);
token.setUid(pref.getString(KEY_UID, ""));
token.setToken(pref.getString(KEY_ACCESS_TOKEN, ""));
token.setExpiresTime(pref.getLong(KEY_EXPIRES_IN, 0));
return token;
}
public static void clear(Context context) {
if (null == context) {
return;
}
SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME,
Context.MODE_APPEND);
Editor editor = pref.edit();
editor.clear();
editor.commit();
}
}
清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="yuan.duo.ustc.sinaclient"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="21" />
<!-- sdk对应的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 用于调用 JNI -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- sdk对应的权限 -->
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
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:theme="@android:style/Theme.NoTitleBar"
android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"
android:configChanges="keyboardHidden|orientation"
android:exported="false"
android:windowSoftInputMode="adjustResize" >
</activity>
<activity
android:name=".AuthorizeActivity"
android:label="@string/title_activity_authorize" >
</activity>
<service android:name="com.sina.weibo.sdk.net.DownloadService"
android:exported="false">
</service>
</application>
</manifest>