关于QQ授权登录的实现,官网有详细描述
这里根据自己的实现过程简单介绍一下整个过程:
1. 注册成为开发者,创建应用,获取appid,这个appid后面要用到。
2. 在你的Android工程中导入SDK库文件 open_sdk.jar 和mta-sdk.jar
3. 配置AndroidManifest
申请权限,加入appid,声明SDK中的activity
4. 创建Tencent类实例,实现回调接口IUiListener,IRequestListener
5. 调用QQ登录接口
scope参数官网上竟然没有给说明是什么,官方demo中指定的是"all"
调用Tencent.login(this, Scope, listener)
其中listener是IUiListener接口,在登录成功后会调用onComplete回调,返回类似下面格式的JSONObject对象:
{
"ret":0, //表示登录成功
"pay_token":"xxxxxxxxxxxxxxxx",
"pf":"openmobile_android",
"expires_in":"7776000",
"openid":"xxxxxxxxxxxxxxxxxxx",
"pfkey":"xxxxxxxxxxxxxxxxxxx",
"msg":"sucess",
"access_token":"xxxxxxxxxxxxxxxxxxxxx"
}
6. 获取用户信息
在登录成功后,调用如下接口获取用户信息,此时的listener是IUiListener接口
// 获得用户的详细信息,返回的是一个json字符串
public void getUserInfo() {
/*
* qq官方api中使用的这种方法,不过Constants.GRAPH_SIMPLE_USER_INFO参数找不到表示很蛋疼
* 然后去看官方的demo,得知demo中使用的是userinfo的对象..下面是获取信息的代码,返回的是json字符串
* tencent.requestAsync(Constants.GRAPH_SIMPLE_USER_INFO, null,
* Constants.HTTP_GET, new BaseApiListener("get_simple_userinfo",
* false), null);
*/
//官方的demo中new BaseIuiListener(Main.this,"get_simple_userinfo")第二个参数也没有用到
//好吧..这个就算没有第二个参数也是可以的...表示很不理解啊..官方个坑货
UserInfo userInfo = new UserInfo(Main.this, tencent.getQQToken());
userInfo.getUserInfo(new BaseIuiListener(Main.this));
ValueTextView.setText(userInfo.toString());
}
{
"is_yellow_year_vip": "0",
"ret": 0,
"figureurl_qq_1":
"http://q.qlogo.cn/qqapp/222222/8C75BBE3DC6B0E9A64BD31449A3C8CB0/40",
"figureurl_qq_2":
"http://q.qlogo.cn/qqapp/222222/8C75BBE3DC6B0E9A64BD31449A3C8CB0/100",
"nickname": "小罗",
"yellow_vip_level": "0",
"msg": "",
"figureurl_1":
"http://qzapp.qlogo.cn/qzapp/222222/8C75BBE3DC6B0E9A64BD31449A3C8CB0/50",
"vip": "0",
"level": "0",
"figureurl_2":
"http://qzapp.qlogo.cn/qzapp/222222/8C75BBE3DC6B0E9A64BD31449A3C8CB0/100",
"is_yellow_vip": "0",
"gender": "男",
"figureurl":
"http://qzapp.qlogo.cn/qzapp/222222/8C75BBE3DC6B0E9A64BD31449A3C8CB0/30"
}
7.分享到qq
//分享...这个腾讯给提供的也不是正确的...或者时过境迁了...
//方法里面本来有一个view类型的参数
public void share() {
Bundle bundle = new Bundle();
// 这条分享消息被好友点击后的跳转URL。
bundle.putString(QQShare.SHARE_TO_QQ_TARGET_URL, "http://connect.qq.com/");
// 分享的标题。注:PARAM_TITLE、PARAM_IMAGE_URL、PARAM_ SUMMARY不能全为空,最少必须有一个是有值的。
bundle.putString(QQShare.SHARE_TO_QQ_TITLE, "我在测试");
// 分享的图片URL
bundle.putString(QQShare.SHARE_TO_QQ_IMAGE_URL,
"http://img3.cache.netease.com/photo/0005/2013-03-07/8PBKS8G400BV0005.jpg");
// 分享的消息摘要,最长50个字
bundle.putString(QQShare.SHARE_TO_QQ_SUMMARY, "测试_我是摘要");
// 手Q客户端顶部,替换“返回”按钮文字,如果为空,用返回代替
bundle.putString(QQShare.SHARE_TO_QQ_APP_NAME, "我在测试_appname");
// 标识该消息的来源应用,值为应用名称+AppId。
bundle.putString(QQShare.SHARE_TO_QQ_KEY_TYPE, "星期几" + idString);
tencent.shareToQQ(this, bundle, new BaseIuiListener(Main.this));
}
到这里已经基本完成了QQ授权登录。
有几个问题还需要注意:
1.appid的有效性
应用要上线并且通过审核后,使用的appid才可以正常进行QQ授权,否则只有你注册的QQ号可以成功授权登录,换其他QQ号登录时授权会失败。
解决办法:
a.应用申请上线,不过有的应用需要提供软件著作权
b.设置协作者账号(点击官网说明,默认情况是注册的QQ为协作者帐号,可以添加多个)
c.使用官网给的测试用的appid(222222)
2.没有调用回调
如果发生这种情况,检查一下这一条:
应用调用Andriod_SDK接口时,如果要成功接收到回调,需要在调用接口的Activity的onActivityResult方法中增加如下代码:
下面是我自己的demo的代码
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mTencent.onActivityResult(requestCode, resultCode, data);
}
package com.example.testQQloginshare;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import org.apache.http.conn.ConnectTimeoutException;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.testQQloginshare.R.id;
import com.tencent.connect.UserInfo;
import com.tencent.connect.auth.QQToken;
import com.tencent.connect.common.Constants;
import com.tencent.connect.share.QQShare;
import com.tencent.open.utils.HttpUtils.HttpStatusException;
import com.tencent.open.utils.HttpUtils.NetworkUnavailableException;
import com.tencent.tauth.IRequestListener;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
public class Main extends Activity {
private Button qqloginButton, qqlogoutButton, qqgetuserinfo, btn_share;
private TextView ValueTextView;
private Tencent tencent;
// 现在使用的appid是腾讯提供的..因为我们的id需要项目上线之后才可以正常使用
private String idString = "222222";
private String idStringmy = "1104296989 ";
private static String tag = "testqq";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tencent = Tencent
.createInstance(idString, this.getApplicationContext());
initView();
}
private void initView() {
Btnlistener btnlistener = new Btnlistener();
// 登录按钮
qqloginButton = (Button) findViewById(R.id.btn_qqlogin);
qqloginButton.setOnClickListener(btnlistener);
// 注销按钮
qqlogoutButton = (Button) findViewById(R.id.btn_qqlogout);
qqlogoutButton.setOnClickListener(btnlistener);
// 获得用户信息
qqgetuserinfo = (Button) findViewById(R.id.btn_getuserinfo);
qqgetuserinfo.setOnClickListener(btnlistener);
// 分享按钮
btn_share = (Button) findViewById(R.id.btn_share);
btn_share.setOnClickListener(btnlistener);
ValueTextView = (TextView) findViewById(R.id.tv_value);
}
// 登录函数
public void login() {
// 我擦..前面的感叹号很重要,,,天哪...竟然在这里出问题..浪费了很多时间,而且官方文档里面竟然没有对
// login的第二个参数进行说明.这个还是去看demo才知道要写什么的
if (!tencent.isSessionValid()) {
tencent.login(Main.this, "all", new BaseIuiListener(Main.this));
}
}
// 注销函数
public void logout() {
tencent.logout(this);
}
// 获得用户的详细信息,返回的是一个json字符串
public void getUserInfo() {
/*
* qq官方api中使用的这种方法,不过Constants.GRAPH_SIMPLE_USER_INFO参数找不到表示很蛋疼
* 然后去看官方的demo,得知demo中使用的是userinfo的对象..下面是获取信息的代码,返回的是json字符串
* tencent.requestAsync(Constants.GRAPH_SIMPLE_USER_INFO, null,
* Constants.HTTP_GET, new BaseApiListener("get_simple_userinfo",
* false), null);
*/
//官方的demo中new BaseIuiListener(Main.this,"get_simple_userinfo")第二个参数也没有用到
//好吧..这个就算没有第二个参数也是可以的...表示很不理解啊..官方个坑货
UserInfo userInfo = new UserInfo(Main.this, tencent.getQQToken());
userInfo.getUserInfo(new BaseIuiListener(Main.this));
ValueTextView.setText(userInfo.toString());
}
//分享...这个腾讯给提供的也不是正确的...或者时过境迁了...
//方法里面本来有一个view类型的参数
public void share() {
Bundle bundle = new Bundle();
// 这条分享消息被好友点击后的跳转URL。
bundle.putString(QQShare.SHARE_TO_QQ_TARGET_URL, "http://connect.qq.com/");
// 分享的标题。注:PARAM_TITLE、PARAM_IMAGE_URL、PARAM_ SUMMARY不能全为空,最少必须有一个是有值的。
bundle.putString(QQShare.SHARE_TO_QQ_TITLE, "我在测试");
// 分享的图片URL
bundle.putString(QQShare.SHARE_TO_QQ_IMAGE_URL,
"http://img3.cache.netease.com/photo/0005/2013-03-07/8PBKS8G400BV0005.jpg");
// 分享的消息摘要,最长50个字
bundle.putString(QQShare.SHARE_TO_QQ_SUMMARY, "测试_我是摘要");
// 手Q客户端顶部,替换“返回”按钮文字,如果为空,用返回代替
bundle.putString(QQShare.SHARE_TO_QQ_APP_NAME, "我在测试_appname");
// 标识该消息的来源应用,值为应用名称+AppId。
bundle.putString(QQShare.SHARE_TO_QQ_KEY_TYPE, "星期几" + idString);
tencent.shareToQQ(this, bundle, new BaseIuiListener(Main.this));
}
// 即使没有这个依然是可以实现登录的啊
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
tencent.onActivityResult(requestCode, resultCode, data);
}
private class Btnlistener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_qqlogin:
Toast.makeText(Main.this, "点击了登录按钮", Toast.LENGTH_LONG).show();
login();
break;
case R.id.btn_qqlogout:
logout();
break;
case R.id.btn_getuserinfo:
getUserInfo();
break;
case R.id.btn_share:
share();
break;
default:
break;
}
}
}
// 登录的时候是使用的这个回调,获取用户详细信息的时候还是这个回调,分享的时候也是使用的这个监听
//调用SDK已经封装好的接口时,例如:登录、快速支付登录、应用分享、应用邀请等接口,需传入该回调的实例。
//IUiListener的实现示例代码如下:
private class BaseIuiListener implements IUiListener {
private Context mContext;
private String mScope;
public BaseIuiListener(Context mContext) {
super();
this.mContext = mContext;
}
public BaseIuiListener(Context mContext, String mScope) {
super();
this.mContext = mContext;
this.mScope = mScope;
}
@Override
public void onCancel() {
Toast.makeText(Main.this, "onCancel", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete(Object arg0) {
Toast.makeText(Main.this, "onComplete:" + arg0.toString(),
Toast.LENGTH_SHORT).show();
ValueTextView.setText(arg0.toString());
}
@Override
public void onError(UiError arg0) {
Toast.makeText(Main.this, "onError", Toast.LENGTH_SHORT).show();
}
}
//使用requestAsync、request等通用方法调用sdk未封装的接口时,例如上传图片、查看相册等,需传入该回调的实例。
//本工程没有使用到这个监听
//IRequestListener的实现示例代码如下:
public class BaseApiListener implements IRequestListener {
@Override
public void onComplete(JSONObject arg0) {
Toast.makeText(Main.this,
"BaseApiListener onComplete:" + arg0.toString(),
Toast.LENGTH_SHORT).show();
ValueTextView.setText(arg0.toString());
}
@Override
public void onConnectTimeoutException(ConnectTimeoutException arg0) {
Toast.makeText(Main.this, "onConnectTimeoutException",
Toast.LENGTH_SHORT).show();
}
@Override
public void onHttpStatusException(HttpStatusException arg0) {
Toast.makeText(Main.this, "onHttpStatusException",
Toast.LENGTH_SHORT).show();
}
@Override
public void onIOException(IOException arg0) {
Toast.makeText(Main.this, "onIOException", Toast.LENGTH_SHORT)
.show();
}
@Override
public void onJSONException(JSONException arg0) {
Toast.makeText(Main.this, "onJSONException", Toast.LENGTH_SHORT)
.show();
}
@Override
public void onMalformedURLException(MalformedURLException arg0) {
Toast.makeText(Main.this, "onMalformedURLException",
Toast.LENGTH_SHORT).show();
}
@Override
public void onNetworkUnavailableException(
NetworkUnavailableException arg0) {
Toast.makeText(Main.this, "onNetworkUnavailableException",
Toast.LENGTH_SHORT).show();
}
@Override
public void onSocketTimeoutException(SocketTimeoutException arg0) {
Toast.makeText(Main.this, "onSocketTimeoutException",
Toast.LENGTH_SHORT).show();
}
@Override
public void onUnknowException(Exception arg0) {
Toast.makeText(Main.this, "onUnknowException", Toast.LENGTH_SHORT)
.show();
}
}
}