第三方登录和分享是很常见的功能,现在开发的每个APP基本上都会用到,所以有一套快速集成方案能提高开发效率,我们公司使用的是 ShareSDK,下面记录集成 ShareSDK 和实现最常见的微信、微博、QQ的登录和分享。
注册
首先我们需要注册 ShareSDK 账号并添加一个新应用。
集成SDK
申请 ShareSDK 的 appkey 成功之后,我们就可以把SDK集成到项目中: ShareSDK for Android 快速集成
第一步:下载SDK
目前最新的是 2017-03-27 更新的 v2.8.2 ,选中自己需要的平台点击下载就可以了,右上角可以下载DEMO源码。
使用 ShareSDK 提供的工具可以快速生成我们需要的资源文件:
第二步:集成到项目中
把工具生成的文件都放到我们自己的项目中:
① 添加依赖包,把 res 里面的文件拷贝到项目中
② 在 assets 下添加ShareSDK.xml
这里以微信、微博和QQ第三方登录和分享为例,在 ShareSDK.xml 里面分别改成自己申请的第三方平台 key。ShareSDK 的 AppKey 也可以在这里配置,这样在代码中初始化时就不需要传参数。
<ShareSDK
AppKey="你的ShareSDK AppKey"/> <!-- 修改成你在sharesdk后台注册的应用的appkey"-->
<!-- ShareByAppClient标识是否使用微博客户端分享,默认是false -->
<SinaWeibo
Id="1"
SortId="1"
AppKey="你的新浪微博 AppKey"
AppSecret="你的新浪微博 AppSecret"
RedirectUrl="https://api.weibo.com/oauth2/default.html"
ShareByAppClient="true"
Enable="true" />
<QZone
Id="3"
SortId="3"
AppId="你的腾讯 AppId"
AppKey="你的腾讯 AppKey"
Enable="true" />
<!--
Wechat微信和WechatMoments微信朋友圈的appid是一样的;
注意:开发者不能用我们这两个平台的appid,否则分享不了
微信测试的时候,微信测试需要先签名打包出apk,
sample测试微信,要先签名打包,keystore在sample项目中,密码123456
BypassApproval是绕过审核的标记,设置为true后AppId将被忽略,故不经过
审核的应用也可以执行分享,但是仅限于分享文字和图片,不能分享其他类型,
默认值为false。此外,微信收藏不支持此字段。
-->
<Wechat
Id="4"
SortId="4"
AppId="你的微信 AppId"
AppSecret="你的微信 AppSecret"
BypassApproval="false"
Enable="true" />
<!-- ShareByAppClient标识是否使用微博客户端分享,默认是false -->
<QQ
Id="7"
SortId="7"
AppId="你的腾讯 AppId"
AppKey="你的腾讯 AppKey"
ShareByAppClient="true"
Enable="true" />
③ 配置AndroidManifest
添加权限:
<uses-permission android:name="android.permission.GET_TASKS" />
<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.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- 蓝牙分享所需的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
添加 ShareSDK 必要的 activity :
<!-- 微信 -->
<activity
android:name=".wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity
android:name="com.mob.tools.MobUIShell"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden|adjustResize" >
<!-- QQ和QQ空间分享 QQ登录的回调必须要配置的 -->
<intent-filter>
<data android:scheme="tencent100371282" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<!-- 新浪微博客户端分享回调必须配置 -->
<intent-filter>
<action android:name="com.sina.weibo.sdk.action.ACTION_SDK_REQ_ACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
AndroidManifest 里面的内容都不要改,直接复制就可以,特别是 微信 ,之前就在这里吃过亏。
④ 微信需要注意的地方
要正常使用微信功能,我们还要添加微信的回调 activity,直接把工具生成的文件拷贝进去就可以,WXEntryActivity.java 的路径必须是
包名.wxapi.WXEntryActivity
这里的包名指的是 Application Id 而不是 package。
代码中使用 ShareSDK
第三方登录的代码:
package com.simple.activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import java.util.HashMap;
import butterknife.BindView;
import butterknife.OnClick;
import cn.simple.R;
import cn.sharesdk.framework.Platform;
import cn.sharesdk.framework.PlatformActionListener;
import cn.sharesdk.framework.PlatformDb;
import cn.sharesdk.framework.ShareSDK;
import cn.sharesdk.sina.weibo.SinaWeibo;
import cn.sharesdk.tencent.qq.QQ;
import cn.sharesdk.wechat.friends.Wechat;
/**
* 登录界面
* 作者: JairusTse
* 日期: 17/2/24 14:53
*/
public class LoginActivity extends AppCompatActivity implements PlatformActionListener {
@BindView(R.id.img_qq)
ImageView imgQq;
@BindView(R.id.img_weixin)
ImageView imgWeixin;
@BindView(R.id.img_weibo)
ImageView imgWeibo;
private PlatformDb platDB; //平台授权数据DB
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_login);
//初始化shareSDK,如果没有在ShareSDK.xml中设置appkey,需要在这里传参数
ShareSDK.initSDK(this);
}
//第三方授权登录
private void authorize(Platform plat) {
if (plat == null) {
return;
}
//判断指定平台是否已经完成授权
if(plat.isAuthValid()) {
String token = plat.getDb().getToken();
String userId = plat.getDb().getUserId();
String name = plat.getDb().getUserName();
String gender = plat.getDb().getUserGender();
String headImageUrl = plat.getDb().getUserIcon();
String platformNname = plat.getDb().getPlatformNname();
if (userId != null) {
//已经授权过,直接下一步操作
if(platformNname.equals(SinaWeibo.NAME)) {
//微博授权
} else if(platformNname.equals(QQ.NAME)) {
//QQ授权
} else if(platformNname.equals(Wechat.NAME)) {
//微信授权
}
return;
}
}
// true不使用SSO授权,false使用SSO授权
plat.SSOSetting(false);
plat.setPlatformActionListener(this);
plat.authorize();
//获取用户资料
plat.showUser(null);
}
//授权成功回调
@Override
public void onComplete(Platform platform, int i, HashMap<String, Object> hashMap) {
String headImageUrl = null;//头像
String userId;//userId
String token;//token
String gender;//性别
String name = null;//用户名
if (i == Platform.ACTION_USER_INFOR) {
platDB = platform.getDb(); // 获取平台数据DB
if (platform.getName().equals(Wechat.NAME)) {
//微信登录
// 通过DB获取各种数据
token = platDB.getToken();
userId = platDB.getUserId();
name = platDB.getUserName();
gender = platDB.getUserGender();
headImageUrl = platDB.getUserIcon();
if ("m".equals(gender)) {
gender = "1";
} else {
gender = "2";
}
} else if (platform.getName().equals(SinaWeibo.NAME)) {
// 微博登录
token = platDB.getToken();
userId = platDB.getUserId();
name = hashMap.get("nickname").toString(); // 名字
gender = hashMap.get("gender").toString(); // 年龄
headImageUrl = hashMap.get("figureurl_qq_2").toString(); // 头像figureurl_qq_2 中等图,figureurl_qq_1缩略图
} else if (platform.getName().equals(QQ.NAME)) {
// QQ登录
token = platDB.getToken();
userId = platDB.getUserId();
name = hashMap.get("nickname").toString(); // 名字
gender = hashMap.get("gender").toString(); // 年龄
headImageUrl = hashMap.get("figureurl_qq_2").toString(); // 头像figureurl_qq_2 中等图,figureurl_qq_1缩略图
}
}
}
//授权出错回调
@Override
public void onError(Platform platform, int i, Throwable throwable) {
}
//取消授权回调
@Override
public void onCancel(Platform platform, int i) {
}
@Override
protected void onDestroy() {
ShareSDK.stopSDK(this);
super.onDestroy();
}
@OnClick({R.id.img_qq, R.id.img_weixin, R.id.img_weibo})
public void onClick(View view) {
switch (view.getId()) {
case R.id.img_qq: {
// qq登录
Platform qq = ShareSDK.getPlatform(QQ.NAME);
authorize(qq);
break;
}
case R.id.img_weixin: {
// 微信登录
Platform wechat = ShareSDK.getPlatform(Wechat.NAME);
authorize(wechat);
break;
}
case R.id.img_weibo: {
// 微博登录
Platform weibo = ShareSDK.getPlatform(SinaWeibo.NAME);
authorize(weibo);
break;
}
}
}
}
第三方分享的代码:
package com.simple.activity;
import android.Manifest;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.tbruyelle.rxpermissions.Permission;
import com.tbruyelle.rxpermissions.RxPermissions;
import com.example.util.ShareSDKUtil;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import butterknife.BindView;
import butterknife.OnClick;
import cn.simple.R;
import cn.sharesdk.framework.ShareSDK;
import rx.functions.Action1;
/**
* ShareSDK第三方分享界面
* 作者: JairusTse
* 日期: 17/2/28 15:16
*/
public class AuthShareActivity extends AppCompatActivity {
@BindView(R.id.title)
TextView title;
@BindView(R.id.img_title)
ImageView imgTitle;
@BindView(R.id.tv_left)
TextView tvLeft;
@BindView(R.id.right_btn)
ImageButton rightBtn;
/** 微信 **/
public static final String AUTH_WECHAT = "wechat";
/** QQ **/
public static final String AUTH_QQ = "qq";
/** QQ空间 **/
public static final String AUTH_QQ_ZONE = "qq_zone";
/** 朋友圈 **/
public static final String AUTH_MOMENT = "moment";
private String share_title = "分享标题";
private String share_text = "分享内容";
private String share_url = "https://http://www.jianshu.com/p/36aca90d588d"; //分享链接
private String share_icon = Environment.getDataDirectory().getAbsolutePath() +
File.separator + "myapp" + File.separator + "icon.png"; //分享缩略图在SD卡的路径
private RxPermissions rxPermissions; //检测权限
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setContentView(R.layout.activity_account_center);
rxPermissions = new RxPermissions(this);
ShareSDK.initSDK(this);
}
/**
* 检查分享的缩略图是否存在SD卡中,没有就保存到SD卡
* @param img_id 图片资源id
*/
private void checkImage(int img_id) {
File icon = new File(share_icon);
if(!icon.exists()) {
saveBitmap(share_icon, BitmapFactory.decodeResource(getResources(), img_id));
}
}
/**
* 保存Bitmap到本地
* @param path 保存文件路径
* @param mBitmap 图片Bitmap
*/
public static void saveBitmap(String path, Bitmap mBitmap) {
File f = new File(path);
try {
f.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
FileOutputStream fOut = null;
try {
fOut = new FileOutputStream(f);
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
fOut.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 第三方分享
* @param share_type 分享类型
*/
private void auth_share(final String share_type) {
//保存图片需要访问SD卡权限,分享到QQ和QQ空间也需要访问SD卡权限
rxPermissions.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.subscribe(new Action1<Permission>() {
@Override
public void call(Permission permission) {
if(permission.granted) {
//分享的图片要先保存到sd卡
checkImage(R.drawable.ic_launcher);
switch (share_type) {
case AUTH_WECHAT:
//分享到微信
ShareSDKUtil.shareWX(share_title, URL_SHARE, share_text, share_icon);
break;
case AUTH_QQ:
//分享到QQ好友
ShareSDKUtil.shareQQ(share_title, URL_SHARE, share_text, share_icon);
break;
case AUTH_QQ_ZONE:
//分享到QQ空间
ShareSDKUtil.shareQzone(share_title, URL_SHARE, share_text, share_icon);
break;
case AUTH_MOMENT:
//分享到朋友圈
ShareSDKUtil.shareWXM(share_title, URL_SHARE, share_text, share_icon);
break;
}
} else if(permission.shouldShowRequestPermissionRationale == true){
//禁止授权
} else if(permission.shouldShowRequestPermissionRationale == false){
//禁止授权且不再询问
}
}
});
}
@OnClick({R.id.btn_moment, R.id.btn_qq, R.id.btn_qq_zone, R.id.btn_wechat})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_moment:
auth_share(AUTH_MOMENT);
break;
case R.id.btn_qq:
auth_share(AUTH_QQ);
break;
case R.id.btn_qq_zone:
auth_share(AUTH_QQ_ZONE);
break;
case R.id.btn_wechat:
auth_share(AUTH_WECHAT);
break;
}
}
}
工具类ShareSDKUtil :
package com.example.util;
import android.util.Log;
import java.util.HashMap;
import cn.sharesdk.framework.Platform;
import cn.sharesdk.framework.PlatformActionListener;
import cn.sharesdk.framework.ShareSDK;
import cn.sharesdk.tencent.qq.QQ;
import cn.sharesdk.tencent.qzone.QZone;
import cn.sharesdk.wechat.friends.Wechat;
import cn.sharesdk.wechat.moments.WechatMoments;
/**
* 作者:JairusTse
* 日期: 17/4/11
*/
public class ShareSDKUtil {
private static String type="";
/**
*
* @param title 标题
* @param titleUrl title链接
* @param text 内容
* @param imagePath 图片本地路径
*/
public static void shareQzone(String title, String titleUrl, String text, String imagePath){
type="share";
Platform.ShareParams sp = new Platform.ShareParams();
sp.setTitle(title);
sp.setTitleUrl(titleUrl); // 标题的超链接
sp.setText(text);
sp.setImagePath(imagePath);
Platform qzone = ShareSDK.getPlatform (QZone.NAME);
// 设置分享事件回调(注:回调放在不能保证在主线程调用,不可以在里面直接处理UI操作)
qzone.setPlatformActionListener(mPlatformActionListener);
// 执行图文分享
qzone.share(sp);
}
/**
* QQ
* @param title
* @param titleUrl
* @param text
* @param imagePath
*/
public static void shareQQ(String title, String titleUrl, String text, String imagePath){
type="share";
QQ.ShareParams sp=new QQ.ShareParams();
sp.setTitle(title);
sp.setText(text);
if(titleUrl!=null){
sp.setTitleUrl(titleUrl); // 标题的超链接
}
if(imagePath!=null){
sp.setImageUrl(imagePath);
}
Platform qq = ShareSDK.getPlatform(QQ.NAME);
qq. setPlatformActionListener (mPlatformActionListener); // 设置分享事件回调
// 执行图文分享
qq.share(sp);
}
/**
* 朋友圈
* @param title
* @param titleUrl
* @param text
* @param imagePath
*/
public static void shareWXM(String title, String titleUrl, String text, String imagePath){
type="share";
WechatMoments.ShareParams sp = new WechatMoments.ShareParams();
sp.setTitle(title);
sp.setText(text);
if(titleUrl!=null){
sp.setTitleUrl(titleUrl); // 标题的超链接
}
if(imagePath!=null){
sp.setImagePath(imagePath);
}
sp.setShareType(Platform.SHARE_WEBPAGE);
sp.setUrl(titleUrl);
Platform moments = ShareSDK.getPlatform(WechatMoments.NAME);
moments. setPlatformActionListener (mPlatformActionListener); // 设置分享事件回调
// 执行图文分享
moments.share(sp);
}
/**
* 微信
* @param title
* @param titleUrl
* @param text
* @param imagePath
Platform.SHARE_TEXT(分享文本),
Platform.SHARE_IMAGE(分享图片),
Platform.SHARE_WEBPAGE(分享网页,既图文分享),
Platform.SHARE_MUSIC(分享音频),
Platform.SHARE_VIDEO(分享视频),
Platform.SHARE_APPS(分享应用,仅微信支持),
Platform.SHARE_FILE(分享文件,仅微信支持)
Platform.SHARE_EMOJI(分享表情,仅微信支持)
*/
public static void shareWX(String title, String titleUrl, String text, String imagePath){
type="share";
Wechat.ShareParams sp=new Wechat.ShareParams();
sp.setTitle(title);
sp.setText(text);
if(titleUrl!=null){
sp.setTitleUrl(titleUrl); // 标题的超链接
}
if(imagePath!=null){
sp.setImagePath(imagePath);
}
sp.setShareType(Platform.SHARE_WEBPAGE);
sp.setUrl(titleUrl);
Platform wx = ShareSDK.getPlatform (Wechat.NAME);
wx. setPlatformActionListener (mPlatformActionListener); // 设置分享事件回调
// 执行图文分享
wx.share(sp);
}
public static PlatformActionListener mPlatformActionListener = new PlatformActionListener() {
@Override
public void onComplete(Platform platform, int i, HashMap<String, Object> hashMap) {
if(type.equals("login")){
Log.e("onComplete","登录成功");
Log.e("openid",platform.getDb().getUserId());//拿到登录后的openid
Log.e("username",platform.getDb().getUserName());//拿到登录用户的昵称
}else{
Log.e("onComplete","分享成功");
}
}
@Override
public void onError(Platform platform, int i, Throwable throwable) {
Log.e("onError",throwable.toString()+"");
if(type.equals("login")){
Log.e("onError","登录失败"+throwable.toString());
}else{
Log.e("onError","分享失败"+throwable.toString());
}
}
@Override
public void onCancel(Platform platform, int i) {
if(type.equals("login")){
Log.e("onCancel","登录取消");
}else{
Log.e("onCancel","分享取消");
}
}
};
}
有两个需要注意的地方:
- 分享到QQ好友和QQ空间需要访问存储权限,我用的是RxPermissions,具体用法可以看下我另外一篇博客:Android 6.0 运行时权限
- 设置分享的缩略图要用本地SD卡的图片,如果用图片url分享出去是不能正常显示的,但是我们经常会使用项目里面的资源图片,所以需要先把资源图片保存到SD卡中,上面的例子也提供了把资源图片保存到SD卡的方法,同样要注意权限的判断。