SDK下载 (最新3.1):http://connect.qq.com/intro/login
1.自己创建应用
首先我们打开腾讯开发平台这个网页,点击—->移动应用—->创建应用,成功创建应用后,可以产生我们需要的App ID和App Key,如下图所示:
2.运行官方Demo(官方Demo比较全,可以根据自己需求使用,我们在这里只分析登入的代码)
下面是主要的登录代码,在Demo的MainActivity里面
/**
*
* 通过调用Tencent类的login函数发起登录/校验登录态。
*
* 该API具有两个作用:
* (1)如果开发者没有调用mTencent实例的setOpenId,setAccessToken API,则该API执行正常的登录操作;
* (2)如果开发者先调用mTencent实例的setOpenId、setAccessToken
* API,则该API执行校验登录态的操作。如果登录态有效,则返回成功给应用,
* 如果登录态失效,则会自动进入登录流程,将最新的登录态数据返回给应用
*
* @author super bear
*
*/
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getName();
public static String mAppid;
private Button mNewLoginButton;
private Button mServerSideLoginBtn;
private TextView mUserInfo;
private ImageView mUserLogo;
private UserInfo mInfo;
private EditText mEtAppid = null;
public static Tencent mTencent;
private static Intent mPrizeIntent = null;
private static boolean isServerSideLogin = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "-->onCreate");
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//
// 固定竖屏
setContentView(R.layout.activity_main_new);
initViews();
//setBarTitle("demo菜单");
if (TextUtils.isEmpty(mAppid)) {
mAppid = "222222";
mEtAppid = new EditText(this);
mEtAppid.setText(mAppid);
try {
new AlertDialog.Builder(this).setTitle("请输入APP_ID")
.setCancelable(false)
.setIcon(android.R.drawable.ic_dialog_info)
.setView(mEtAppid)
.setPositiveButton("Commit", mAppidCommitListener)
.setNegativeButton("Use Default", mAppidCommitListener)
.show();
} catch (Exception e) {
}
} else {
if (mTencent == null) {
mTencent = Tencent.createInstance(mAppid, this);
}
}
// 获取有奖分享的intent信息
if (null != getIntent()) {
mPrizeIntent = getIntent();
}
}
/**
* 有奖分享处理,未接入有奖分享可以不考虑
*/
private void handlePrizeShare() {
// -----------------------------------
// 下面的注释请勿删除,编译lite版的时候需要删除, 注意//[不要有空格。
//[liteexludestartmeta]
if (null == mPrizeIntent || null == mTencent) {
return;
}
// 有奖分享处理
boolean hasPrize = mTencent.checkPrizeByIntent(this, mPrizeIntent);
if (hasPrize) {
Util.showConfirmCancelDialog(this, "有奖品领取", "请使用QQ登录后,领取奖品!", prizeShareConfirmListener);
}
//[liteexludeendmeta]
}
// -----------------------------------
// 下面的注释请勿删除,编译lite版的时候需要删除, 注意//[不要有空格。
//[liteexludestart_flag_one]
private DialogInterface.OnClickListener prizeShareConfirmListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
boolean isLogin = mTencent.isSessionValid();
if (isLogin) {
// 本地已经有保存openid和accesstoken的情况下,先调用mTencent.setAccesstoken().
// 也可在奖品列表页,主动调用此接口获取未领取的奖品
if (null != mPrizeIntent) {
mTencent.queryUnexchangePrize(MainActivity.this, mPrizeIntent.getExtras(),
prizeQueryUnexchangeListener);
}
} else {
// 未登陆提示用户使用QQ号登陆
onClickLogin();
}
break;
default:
break;
}
}
};
private IUiListener prizeQueryUnexchangeListener = new IUiListener() {
@Override
public void onError(UiError e) {
Util.toastMessage(MainActivity.this, "onError: " + e.errorDetail);
Util.dismissDialog();
}
@Override
public void onCancel() {
Util.toastMessage(MainActivity.this, "onCancel: ");
Util.dismissDialog();
}
@Override
public void onComplete(Object response) {
Util.showConfirmCancelDialog(MainActivity.this, "兑换奖品", response.toString(),
new PrizeClickExchangeListener(response.toString()));
// 兑换奖品后,mPrizeIntent 置为空
mPrizeIntent = null;
}
};
private IUiListener prizeExchangeListener = new IUiListener() {
@Override
public void onError(UiError e) {
Util.toastMessage(MainActivity.this, "onError: " + e.errorDetail);
Util.dismissDialog();
}
@Override
public void onCancel() {
Util.toastMessage(MainActivity.this, "onCancel: ");
Util.dismissDialog();
}
@Override
public void onComplete(Object response) {
Util.showResultDialog(MainActivity.this, response.toString(), "兑换信息");
}
};
private class PrizeClickExchangeListener implements DialogInterface.OnClickListener {
String response = "";
PrizeClickExchangeListener(String strResponse) {
response = strResponse;
}
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
if (null != mTencent) {
Bundle params = new Bundle();
ArrayList<String> shareIdList = handlePrizeResponse(response);
if (null != shareIdList) {
ArrayList<String> list = new ArrayList<String>();
// 后台测试环境目前只支持一个shareid的兑换,正式环境会支持多个shareid兑换。
list.add(shareIdList.get(0));
params.putStringArrayList("shareid_list", list);
mTencent.exchangePrize(MainActivity.this, params, prizeExchangeListener);
}
}
break;
default:
break;
}
}
};
private ArrayList<String> handlePrizeResponse(String response) {
ArrayList<String> shareIdList = new ArrayList<String>();
if (TextUtils.isEmpty(response)) {
return null;
}
try {
JSONObject obj = new JSONObject(response);
int code = obj.getInt("ret");
int subCode = obj.getInt("subCode");
if (code == 0 && subCode == 0) {
JSONObject data = obj.getJSONObject("data");
JSONArray prizeList = data.getJSONArray("prizeList");
int size = prizeList.length();
JSONObject prize = null;
for (int i = 0; i < size; i++) {
prize = prizeList.getJSONObject(i);
if (null != prize) {
shareIdList.add(prize.getString("shareId"));
}
}
} else {
return null;
}
} catch (Exception e) {
return null;
}
return shareIdList;
}
//[liteexludeend_flag_one]
@Override
protected void onStart() {
Log.d(TAG, "-->onStart");
super.onStart();
}
@Override
protected void onResume() {
Log.d(TAG, "-->onResume");
// 有奖分享处理
handlePrizeShare();
super.onResume();
}
@Override
protected void onPause() {
Log.d(TAG, "-->onPause");
super.onPause();
}
@Override
protected void onStop() {
Log.d(TAG, "-->onStop");
super.onStop();
}
@Override
protected void onDestroy() {
Log.d(TAG, "-->onDestroy");
super.onDestroy();
}
private void initViews() {
mNewLoginButton = (Button) findViewById(R.id.new_login_btn);
mServerSideLoginBtn = (Button) findViewById(R.id.server_side_login_btn);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.main_container);
OnClickListener listener = new NewClickListener();
for (int i = 0; i < linearLayout.getChildCount(); i++) {
View view = linearLayout.getChildAt(i);
if (view instanceof Button) {
view.setOnClickListener(listener);
}
}
mUserInfo = (TextView) findViewById(R.id.user_nickname);
mUserLogo = (ImageView) findViewById(R.id.user_logo);
updateLoginButton();
}
private void updateLoginButton() {
if (mTencent != null && mTencent.isSessionValid()) {
if (isServerSideLogin) {
mNewLoginButton.setTextColor(Color.BLUE);
mNewLoginButton.setText("登录");
mServerSideLoginBtn.setTextColor(Color.RED);
mServerSideLoginBtn.setText("退出Server-Side账号");
} else {
mNewLoginButton.setTextColor(Color.RED);
mNewLoginButton.setText("退出帐号");
mServerSideLoginBtn.setTextColor(Color.BLUE);
mServerSideLoginBtn.setText("Server-Side登陆");
}
} else {
mNewLoginButton.setTextColor(Color.BLUE);
mNewLoginButton.setText("登录");
mServerSideLoginBtn.setTextColor(Color.BLUE);
mServerSideLoginBtn.setText("Server-Side登陆");
}
}
private void updateUserInfo() {
if (mTencent != null && mTencent.isSessionValid()) {
IUiListener listener = new IUiListener() {
@Override
public void onError(UiError e) {
}
@Override
public void onComplete(final Object response) {
Message msg = new Message();
msg.obj = response;
msg.what = 0;
mHandler.sendMessage(msg);
new Thread(){
@Override
public void run() {
JSONObject json = (JSONObject)response;
if(json.has("figureurl")){
Bitmap bitmap = null;
try {
bitmap = Util.getbitmap(json.getString("figureurl_qq_2"));
} catch (JSONException e) {
}
Message msg = new Message();
msg.obj = bitmap;
msg.what = 1;
mHandler.sendMessage(msg);
}
}
}.start();
}
@Override
public void onCancel() {
}
};
mInfo = new UserInfo(this, mTencent.getQQToken());
mInfo.getUserInfo(listener);
} else {
mUserInfo.setText("");
mUserInfo.setVisibility(android.view.View.GONE);
mUserLogo.setVisibility(android.view.View.GONE);
}
}
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
JSONObject response = (JSONObject) msg.obj;
if (response.has("nickname")) {
try {
mUserInfo.setVisibility(android.view.View.VISIBLE);
mUserInfo.setText(response.getString("nickname"));
} catch (JSONException e) {
e.printStackTrace();
}
}
}else if(msg.what == 1){
Bitmap bitmap = (Bitmap)msg.obj;
mUserLogo.setImageBitmap(bitmap);
mUserLogo.setVisibility(android.view.View.VISIBLE);
}
}
};
private void onClickLogin() {
if (!mTencent.isSessionValid()) {
mTencent.login(this, "all", loginListener);
isServerSideLogin = false;
Log.d("SDKQQAgentPref", "FirstLaunch_SDK:" + SystemClock.elapsedRealtime());
} else {
if (isServerSideLogin) { // Server-Side 模式的登陆, 先退出,再进行SSO登陆
mTencent.logout(this);
mTencent.login(this, "all", loginListener);
isServerSideLogin = false;
Log.d("SDKQQAgentPref", "FirstLaunch_SDK:" + SystemClock.elapsedRealtime());
return;
}
mTencent.logout(this);
updateUserInfo();
updateLoginButton();
}
}
private void onClickServerSideLogin() {
if (!mTencent.isSessionValid()) {
mTencent.loginServerSide(this, "all", loginListener);
isServerSideLogin = true;
Log.d("SDKQQAgentPref", "FirstLaunch_SDK:" + SystemClock.elapsedRealtime());
} else {
if (!isServerSideLogin) { // SSO模式的登陆,先退出,再进行Server-Side模式登陆
mTencent.logout(this);
mTencent.loginServerSide(this, "all", loginListener);
isServerSideLogin = true;
Log.d("SDKQQAgentPref", "FirstLaunch_SDK:" + SystemClock.elapsedRealtime());
return;
}
mTencent.logout(this);
isServerSideLogin = false;
updateUserInfo();
updateLoginButton();
}
}
public static String getAppid() {
if (TextUtils.isEmpty(mAppid)) {
mAppid = "222222";
}
return mAppid;
}
public static boolean ready(Context context) {
if (mTencent == null) {
return false;
}
boolean ready = mTencent.isSessionValid()
&& mTencent.getQQToken().getOpenId() != null;
if (!ready) {
Toast.makeText(context, "login and get openId first, please!",
Toast.LENGTH_SHORT).show();
}
return ready;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "-->onActivityResult " + requestCode + " resultCode=" + resultCode);
if (requestCode == Constants.REQUEST_LOGIN ||
requestCode == Constants.REQUEST_APPBAR) {
Tencent.onActivityResultData(requestCode,resultCode,data,loginListener);
}
super.onActivityResult(requestCode, resultCode, data);
}
public static void initOpenidAndToken(JSONObject jsonObject) {
try {
String token = jsonObject.getString(Constants.PARAM_ACCESS_TOKEN);
String expires = jsonObject.getString(Constants.PARAM_EXPIRES_IN);
String openId = jsonObject.getString(Constants.PARAM_OPEN_ID);
System.out.println("token"+token+"-------------"+openId);
if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(expires)
&& !TextUtils.isEmpty(openId)) {
mTencent.setAccessToken(token, expires);
mTencent.setOpenId(openId);
}
} catch(Exception e) {
}
}
IUiListener loginListener = new BaseUiListener() {
@Override
protected void doComplete(JSONObject values) {
Log.d("SDKQQAgentPref", "AuthorSwitch_SDK:" + SystemClock.elapsedRealtime());
initOpenidAndToken(values);
updateUserInfo();
updateLoginButton();
}
};
private class BaseUiListener implements IUiListener {
@Override
public void onComplete(Object response) {
if (null == response) {
Util.showResultDialog(MainActivity.this, "返回为空", "登录失败");
return;
}
JSONObject jsonResponse = (JSONObject) response;
if (null != jsonResponse && jsonResponse.length() == 0) {
Util.showResultDialog(MainActivity.this, "返回为空", "登录失败");
return;
}
Util.showResultDialog(MainActivity.this, response.toString(), "登录成功");
// 有奖分享处理
handlePrizeShare();
doComplete((JSONObject)response);
}
protected void doComplete(JSONObject values) {
}
@Override
public void onError(UiError e) {
Util.toastMessage(MainActivity.this, "onError: " + e.errorDetail);
Util.dismissDialog();
}
@Override
public void onCancel() {
Util.toastMessage(MainActivity.this, "onCancel: ");
Util.dismissDialog();
if (isServerSideLogin) {
isServerSideLogin = false;
}
}
}
private DialogInterface.OnClickListener mAppidCommitListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mAppid = AppConstants.APP_ID;
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
// 用输入的appid
String editTextContent = mEtAppid.getText().toString().trim();
if (!TextUtils.isEmpty(editTextContent)) {
mAppid = editTextContent;
}
break;
case DialogInterface.BUTTON_NEGATIVE:
// 默认appid
break;
}
mTencent = Tencent.createInstance(mAppid, MainActivity.this);
// 有奖分享处理
handlePrizeShare();
}
};
private void onClickIsSupportSSOLogin() {
if (mTencent.isSupportSSOLogin(MainActivity.this)) {
Toast.makeText(MainActivity.this, "支持SSO登陆", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "不支持SSO登陆", Toast.LENGTH_SHORT).show();
}
}
class NewClickListener implements OnClickListener {
@Override
public void onClick(View v) {
Context context = v.getContext();
Animation shake = AnimationUtils.loadAnimation(context,
R.anim.shake);
Class<?> cls = null;
boolean isAppbar = false;
switch (v.getId()) {
case R.id.new_login_btn:
onClickLogin();
v.startAnimation(shake);
return;
case R.id.server_side_login_btn:
onClickServerSideLogin();
v.startAnimation(shake);
return;
case R.id.main_sso_btn:
onClickIsSupportSSOLogin();
return;
case R.id.main_getInfo_btn:
cls = AccountInfoActivity.class;
break;
case R.id.main_qqShare_btn:
cls = QQShareActivity.class;
break;
case R.id.main_qzoneShare_btn:
cls = QZoneShareActivity.class;
break;
case R.id.main_social_api_btn:
cls = SocialApiActivity.class;
break;
//-----------------------------------
// 下面的注释请勿删除,编译lite版的时候需要删除, 注意//[不要有空格。
//[liteexludestart]
case R.id.game_add_friend:
cls = GameLogicActivity.class;
break;
case R.id.main_qzonePic_btn:
cls = QzonePicturesActivity.class;
break;
case R.id.main_tqqInfo_btn:
cls = TQQInfoActivity.class;
break;
case R.id.main_wap_btn:
cls = WPAActivity.class;
break;
case R.id.main_others_btn:
cls = OtherApiActivity.class;
break;
case R.id.main_avatar_btn:
cls = AvatarActivity.class;
break;
case R.id.main_appbar_btn:
cls = SocialAppbarActivity.class;
isAppbar = true;
break;
case R.id.main_qqgroup_btn:
cls = QQGroupActivity.class;
break;
//[liteexludeend]
}
v.startAnimation(shake);
if (cls != null) {
Intent intent = new Intent(context, cls);
if (isAppbar) { //APP内应用吧登录需接收登录结果
startActivityForResult(intent, Constants.REQUEST_APPBAR);
} else {
context.startActivity(intent);
}
}
}
}
}
在主程序里面实现登录和获取用户信息,主要起作用的语句:
mTencent.login(MainActivity.this, scope, loginListener); //登录
userInfo = new UserInfo(MainActivity.this, mTencent.getQQToken()); //获取用户信息
userInfo.getUserInfo(userInfoListener);
3.配置AndroidManifest
在应用的AndroidManifest.xml增加配置的<application>节点下增加以下配置(注:不配置将会导致无法调用API);
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application>
<activity
android:name="com.tencent.tauth.AuthActivity"
android:noHistory="true"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tencent你的AppId" />
</intent-filter>
</activity>
<application>
其中,如果你已经添加了"android.permission.INTERNET"和"android.permission.ACCESS_NETWORK_STATE"权限,则无需重复添加。
而"你的AppId"则要替换成具体应用的AppId,例如你的AppId是"222222",则<data>标签应该是这样的:
<data android:scheme="tencent222222" />
4.初始化实例
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Tencent类是SDK的主要实现类,开发者可通过Tencent类访问腾讯开放的OpenAPI。
// 其中APP_ID是分配给第三方应用的appid,类型为String。
mTencent = Tencent.createInstance(APP_ID, this.getApplicationContext());
// 1.4版本:此处需新增参数,传入应用程序的全局context,可通过activity的getApplicationContext方法获取
// 初始化视图
initViews();
}
5.登录按钮被点击的代码
private void onClickLogin() {
if (!mTencent.isSessionValid()) {
mTencent.login(this, "all", loginListener);
isServerSideLogin = false;
Log.d("SDKQQAgentPref", "FirstLaunch_SDK:" + SystemClock.elapsedRealtime());
} else {
if (isServerSideLogin) { // Server-Side 模式的登陆, 先退出,再进行SSO登陆
mTencent.logout(this);
mTencent.login(this, "all", loginListener);
isServerSideLogin = false;
Log.d("SDKQQAgentPref", "FirstLaunch_SDK:" + SystemClock.elapsedRealtime());
return;
}
mTencent.logout(this);
updateUserInfo();
updateLoginButton();
}
}
6.实现回调
//这个是登录时传递进去的接口
IUiListener loginListener = new BaseUiListener() {
@Override
protected void doComplete(JSONObject values) {
Log.d("SDKQQAgentPref", "AuthorSwitch_SDK:" + SystemClock.elapsedRealtime());
//去获取Token与OpenId
initOpenidAndToken(values);
}
};
--------------------华丽的分割线--------------------------------
private class BaseUiListener implements IUiListener {
@Override
public void onComplete(Object response) {
if (null == response) {
Util.showResultDialog(MainActivity.this, "返回为空", "登录失败");
return;
}
JSONObject jsonResponse = (JSONObject) response;
if (null != jsonResponse && jsonResponse.length() == 0) {
Util.showResultDialog(MainActivity.this, "返回为空", "登录失败");
return;
}
Util.showResultDialog(MainActivity.this, response.toString(), "登录成功");
// 有奖分享处理
handlePrizeShare();
doComplete((JSONObject)response);
}
protected void doComplete(JSONObject values) {
}
@Override
public void onError(UiError e) {
Util.toastMessage(MainActivity.this, "onError: " + e.errorDetail);
Util.dismissDialog();
}
@Override
public void onCancel() {
Util.toastMessage(MainActivity.this, "onCancel: ");
Util.dismissDialog();
if (isServerSideLogin) {
isServerSideLogin = false;
}
}
}
--------------------华丽的分割线--------------------------------
//去拿到ACCESS_TOKEN与PARAM_OPEN_ID与EXPIRES_IN(有效时间)
public static void initOpenidAndToken(JSONObject jsonObject) {
try {
String token = jsonObject.getString(Constants.PARAM_ACCESS_TOKEN);
String expires = jsonObject.getString(Constants.PARAM_EXPIRES_IN);
String openId = jsonObject.getString(Constants.PARAM_OPEN_ID);
System.out.println("token"+token+"-------------"+openId);
if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(expires)
&& !TextUtils.isEmpty(openId)) {
mTencent.setAccessToken(token, expires);
mTencent.setOpenId(openId);
}
} catch(Exception e) {
}
}
7.使用access_token和openid
应用在每次登录之后,都会获取到openid、access_token和expires_in,在调用SDK提供的接口时,后台会根据这三个参数来验证请求的合法性。
(1)如果应用已经走过登录流程,调用应用分享、邀请等接口,是不需要再将这三个参数传入到请求参数中去的,这是因为在登录成功后,SDK会自动将这几个参数保存在SDK的上下文中,在发送请求时,会自动为请求加上这些参数。
(2)如果应用不希望每次都走登录流程来使用SDK的功能,可以通过以下步骤来实现:
Step1:在首次登录成功后,将返回的openid、access_token、expires_in三个参数保存在本地(比如保存在sharedPreferrence)。其中expires_in参数在存储前需进行如下计算:
1.System.currentTimeMillis() + Long.parseLong(expires_in) * 1000;
这样得出的就是token的失效日期。
Step2:在用户下次进入应用,发起应用分享等SDK调用之前,首先创建Tencent实例,然后取出之前保存的openid、access_token、expires_in(前面计算出来的值)的值。
Step3:调用Tencent类的setOpenId和setAccessToken方法。其中setOpenId的参数传入上一步取出的openid,setAccessToken的第一个参数传入上一步取出的access_token,第二个参数传入(上一步保存的token失效日期-当前系统时间)/1000。这里计算出的结果是当前保存的token的有效时间,如果结果小于或等于0,表示token已经过期,应该提示用户重新走登录流程。
免登录流程调用SDK接口的示例代码如下(省去了获取存储的变量的过程):
String openid = "1234567896ASDFGHJKLLIUYT";
String access_token = "2C0884DC4B930010D852D8D504FC9F4D";
String expires_in = "7776000"; // 实际值需要通过上面介绍的方法来计算
mTencent = Tencent.createInstance(APP_ID);
mTencent.setOpenId(openid);
mTencent.setAccessToken(access_token, expires_in);
8.混淆
-keep class com.tencent.open.TDialog$*
-keep class com.tencent.open.TDialog$* {*;}
-keep class com.tencent.open.PKDialog
-keep class com.tencent.open.PKDialog {*;}
-keep class com.tencent.open.PKDialog$*
-keep class com.tencent.open.PKDialog$* {*;}
微信授权登录可以参考下面博客
http://blog.youkuaiyun.com/qq247890212/article/details/40822481