您的位置:首页 > 其它

一步步实现三方操作功能模块封装(二),三方分享

2017-09-27 15:20 766 查看
在上一篇文章, 我们封装了三方登录的功能,三方分享需要依赖腾讯的 SDK ,可参考上一篇文章 前期准备 部分,还没看过上一篇的朋友,建议先去阅读 一步步实现三方操作功能模块封装(一),三方登录

在多数情况下,我们希望在分享一则消息到 QQ 或者 微信时,只需要调用一行代码就能实现,如下所示:

//分享默认方法
public static void shareDefault(Activity context,String shareTitle, String shareContent,String shareUrl,String imageUrl, DataListener callback) {

}


或者想要指定分享的平台,例如只分享到微信,如下所示:

//指定某个平台分享
public static void assignSharePlatform(Activity context,String shareTitle, String shareContent,String shareUrl,String imageUrl, String platformName,DataListener callback){

}


按照这样的要求,我们一步一步来搭建自己三方分享模块。

实现思路

按照以往套路,先看分享操作结构图

QQ 分享

QQ 分享结构图,如下所示



QQ 分享结构图分析

ShareUtil 工具类提供各种类型的分享方法,例如上面说到的 shareDefault ( ) 默认分享方法 或者 assignSharePlatform( ) 指定平台分享方法,亦可根据项目需要定义新的方法。这是对我们封装的分享模块方法的再次封装,它可以起到隔离底层实现的作用,也方便使用者的调用。

ThirdPlatformShareUtil 是我们自己的三方分享模块对外提供分享接口的工具类,它对外提供统一 share() 分享方法,根据分享平台和分享的内容选择 ThirdPlatformShareHandler 不同分享请求方法,这样做的目的是让我们三方分享模块根据入参匹配调用相应的分享方法,对外层提供统一的接口,这就是 门面模式 的思想。

ThirdPlatformShareHandler 负责检查分享的参数和按照 QQ 文档接口要求填写分享内容,QQ 分享细分为分享图文、分享纯图片、分享音乐等类型,每个类型都有自己填写格式和必填参数,填写不规范导致分享失败或者程序奔溃,我们当然希望提高自身分享的成功率,若分享参数有误,还能够提前暴露问题,不至于整个程序奔溃,影响用户体验。还有 QQ 分享需要依赖界面,否则无法收到 QQ 回调信息,发送分享请求放在 UiControlActivity 操作(按照分析,QQ 分享是不需要依赖 UI ,这里还没研究出来,暂时先这样处理)。

UiControlActivity 根据分享类型发送 QQ 分享请求(还记得我们 QQ 登录发送请求嘛,没错,也是调用同样的方法,只是换了请求类型)。

QQ 处理请求后,通过回调通知 UiControlActivity 分享结果,UiControlActivity 再回调给 ThirdPlatformShareUtil ,若是不依赖界面,就不用经过 UiControlActivity 这一层了。

微信分享

微信分享结构图



微信分享结构图解析

微信分享结构与 QQ 分享结构很相似。因为微信分享不依赖 UI ,我们使用 WxHandleRequest 统一发送分享请求,上一篇文章微信登录请求也是在这里发送的。

微信处理分享请求后回调 WXEntryActivity onResp( ) 方法,我们再回调通知 ThirdPlatformShareUtil 。

代码实现

QQ 分享

ThirdPlatformShareHandler 类

分析 QQ 分享接口

点击查看 分享消息到 QQ 接口文档

以分享图文消息到 QQ 为例子,代码如下所示:

final Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);
params.putString(QQShare.SHARE_TO_QQ_TITLE, "要分享的标题");
params.putString(QQShare.SHARE_TO_QQ_SUMMARY, "要分享的摘要");
params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, "http://www.qq.com/news/1.html";);
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL,"http://imgcache.qq.com/qzone/space_item/pre/0/66768.gif";);
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, "测试应用222222");
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, "其他附加功能");
mTencent.shareToQQ(MainActivity.this, params, new BaseUiListener());


代码相对简单,先准备 Bundle 类型 的分享数据,按照 key-value 形式填入数据,如标题、跳转链接。然后调用 shareToQQ( ) 方法,第二个入参是分享数据,第三个入参是分享结果的回调。

分享接口的 params 参数说明,如下所示:



说明规定哪些参数是必填,哪些参数可选。若是必填参数为 null ,导致分享失败,有时还会导致程序奔溃,那我们很有必要在调用分享接口前检查分享参数,提高分享成功率。

分享 QQ 消息还有 分享到纯图片,分享音乐等类型,使用规则和分享图文消息类似,那么这些类型都可以分装成同一个方法,变化的只有 Bundle 类型的分享内容。

分享到 QQ 空间接口,代码如下:

private void shareToQzone () {
  //分享类型
params.putString(QzoneShare.SHARE_TO_QQ_KEY_TYPE,SHARE_TO_QZONE_TYPE_IMAGE_TEXT );
params.putString(QzoneShare.SHARE_TO_QQ_TITLE, "标题");//必填
params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, "摘要");//选填
params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL, "跳转URL");//必填
params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, "图片链接ArrayList");
mTencent.shareToQzone(activity, params, new BaseUiListener());
}


使用规则和分享到 QQ 类似,只是调用分享方法改为 shareToQzone( )。看到这里就很清楚了,我们需要提供两个分享类型公共方法,分别是:分享消息到 QQ 和分享到 QQ 空间,继续往下看吧。

封装分享方法

三方分享内容常用有 title、content、imageUrl ,musicUrl 等等,我们先定义一个分享入参实体类 ShareParams,字段由自己定义。

public class ShareParams {

/** title 标题 */
public String title;

/** content是分享文本,所有平台都需要这个字段. */
public String content;

/** 点击跳转链接 */
public String targetUrl;

/** 音乐 url */
public String musicUrl;

/** imagePath是本地的图片路径*/
public String imagePath;

/** imageUrl 是图片 url*/
public String imageUrl;

/** QQ 空间图片分享专用 以ArrayList<String>的类型传入,以便支持多张图片(注:图片最多支持9张图片,多余的图片会被丢弃)*/
public ArrayList<String> imageUrlList;

/**
* 分享或收藏的目标场景
*
* 参考 Constant WX_SHARE_SCENE 三种类型
*/
public int wxShareScene;
}


编写分享到 QQ 公共方法,代码如下:

private void shareQQMsg(Bundle bundle, Context context, DataListener listener){

boolean checkAppPackage = CheckAppUtils.checkHasInstallPackage(context,
CheckAppUtils.qq_package_name);
if(checkAppPackage){
Platform platform = Platform.instance();

platform.setDataListener(listener);
platform.setRequestType(Constant.QQ_SHARE_MSG);
platform.setBundle(bundle);

Intent intent = new Intent();
intent.setClass(context,UiControlActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(intent);
}else {
Log.i(TAG,"shareQQMsg no install QQ");
AlertUtil.toast(context, "分享失败,请下载安装QQ客户端");
}

}


代码很简单,使用 Platform 单例对象保存分享回调、分享的内容和分享类型,通过 Intent 打开 UiControlActivity 发送分享到 QQ 请求。


编写具体分享方法,以分享图文消息为例子,代码如下:

public void shareDefaultMsgToQQ(ShareParams params, Context context, DataListener listener){

if(null == context){
Log.i(TAG, "shareDefaultMsgToQQ context is null");
return;
}

if(!checkShareDefaultMsgQQParams(params,context)){
Log.i(TAG,"shareDefaultMsgToQQ  param no legal");
return;
}

Bundle bundle = new Bundle();
//必填参数
bundle.putString(QQShare.SHARE_TO_QQ_TITLE, params.title);
bundle.putString(QQShare.SHARE_TO_QQ_TARGET_URL,params.targetUrl);
bundle.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);

//可选参数
String imagePath = params.imagePath;
String imageUrl = params.imageUrl;
if(!StringUtils.isEmpty(imageUrl)){
bundle.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUrl);
}else if(!StringUtils.isEmpty(imagePath)){
bundle.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imagePath);
}else {
bundle.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, Constant.TT_ICON_URL);
}

String content = params.content;
if(!StringUtils.isEmpty(content)){
bundle.putString(QQShare.SHARE_TO_QQ_SUMMARY, content);
}

Log.i(TAG, "shareDefaultMsgToQQ");
shareQQMsg(bundle, context, listener);
}


首先使用 checkShareDefaultMsgQQParams( ) 方法检查分享参数,若参数不合法直接返回。接着实例化 Bundle 对象,填入分享内容,最后调用 shareQQMsg( ) 分享到 QQ 的公共方法。分享纯图片、分享音乐与此类似,这里就不累赘了。

编写 UiControlActivity 发送请求方法,如下所示:

private void dealRequest(Platform platform) {

Bundle bundle = platform.getBundle();
//请求类型
int type = platform.getRequestType();
//微信分享的目标场景:聊天界面、朋友圈、收藏
Log.i(TAG, "doThirdPlatformWork type: " + type);
switch (type){
case Constant.QQ_LOGIN:
mTencent.login(this, "all", weakReferenceLoginListener);
break;

case Constant.QQ_SHARE_MSG:
mTencent.shareToQQ(this, bundle, shareListener);
break;

case Constant.QQ_SHARE_ZONE:
mTencent.shareToQzone(this,bundle, shareListener);
break;

default:
Log.i(TAG,"send Request
d613
no match type");
finish();
break;
}

}


ThirdPlatformShareUtil 类

由 QQ 分享结构图可知 ThirdPlatformShareUtil 类有两大任务,第一,代表分享模块对外提供统一分享接口;第二,接收分享回调信息,通知使用者分享结果。

前期分析

如何做到对外提供统一分享接口呢,对于分享调用者来说,他们只关心自己想要分享的内容和调用分享的结果,至于具体使用哪种分享类型方法,它是不在乎的。按照这种思路,我们可以根据分享内容匹配选择对应类型的分享方法。

至于接收分享回调信息,那就相对简单了,让 ThirdPlatformShareUtil 类 继承 BaseDataListener (继承 DataListener 接口的抽象类,增加释放资源方法),调用分享方法时把自己传进去,还记得上面分享图文消息到 QQ 方法吗?第二个参数就是 ThirdPlatformShareUtil 对象。

编写对外分享方法

对外提供 share( ) 方法,代码如下所示:

public void share(ShareParams params, String platformName){

if(params == null){
Log.i(TAG, "share: params is null");
return;
}

if(!OneStepShare.isSupportShare(platformName)){
Log.i(TAG, "share: platformName is not support");
return;
}

switch (platformName){
case Constant.PLATFORM_NAME_QQ:
matchShareMsgToQQ(params);
break;

case Constant.PLATFORM_NAME_QZONE:
handler.shareMsgToQZone(params,context,this);
break;

//匹配分享场景,默认分享到微信聊天界面
case Constant.PLATFORM_NAME_WX_LINE:
params.wxShareScene = Constant.WXSceneTimeline;
matchWxShare(params);
break;
case Constant.PLATFORM_NAME_WX_FAVORITE:
params.wxShareScene = Constant.WXSceneFavorite;
matchWxShare(params);
break;
default:
matchWxShare(params);
break;

}

}


params 是分享的内容,platformName 是分享平台名称。其中,OneStepShare 是三方分享初始化类,初始化支持分享平台列表、分享平台图标资源、显示名称等,isSupportShare( ) 判断是否支持某个平台的分享,若不支持直接返回,否则按照平台名称 platformName 匹配分享方法。


匹配 ThirdPlatformShareHandler 分享方法

private void matchShareMsgToQQ(ShareParams params){
if(params == null){
Log.i(TAG,"matchShareMsgToQQ params is null");
return;
}

if(isShareMusic(params)){
handler.shareMusicToQQ(params,context,this);
return;
}

if(isShareMsgToQQDefault(params)){
handler.shareDefaultMsgToQQ(params,context,this);
}else {
handler.shareOnlyImageToQQ(params,context,this);
}
}


根据分享内容,匹配 ThirdPlatformShareHandler 分享方法。例如若有音乐 url ,优先调用分享分享音乐方法;若有分享标题和跳转 url,则调用分享图文信息方法。


处理分享回调信息

由分享结构图可以知道,UiControlActivity 发出分享请求等待 QQ 处理请求和结果回调,在 UiControlActivity 收到回调信息后,通过 Platform 单例对象获取回调 dataListener ,回调给 ThirdPlatformShareUtil。

ThirdPlatformShareUtil 继承 BaseDataListener ,实现它的方法,若分享成功,则回调 onComplete( ) 方法,如下所示:

@Override
public void onComplete(Object response) {
super.onComplete(response);
Log.i(TAG,"onComplete");
if(null != response){
Log.i(TAG,"onComplete response " + response.toString());
}
}


若分享失败,则回调 onError( ) 方法,我们根据分享类型统一处理错误信息,如下所示:

@Override
public void onError(Object response) {
super.onError(response);
if(response != null){
Log.i(TAG,"onError response " + response.toString());

//同一处理三方分享错误信息
int requestType = Platform.instance().getRequestType();
switch (requestType) {
case Constant.QQ_SHARE_MSG:
case Constant.QQ_SHARE_ZONE:
ErrorHandler.handlerQQResponseError(context,(UiError) response);

break;
case Constant.WX_SHARE_TEXT_MSG:
case Constant.WX_SHARE_IMAGE_MSG:
case Constant.WX_SHARE_URL_MSG:
case Constant.WX_SHARE_MUSIC_MSG:
ErrorHandler.handlerWXResponseError(context, (BaseResp) response);
break;
default:
Log.i(TAG, "onError: no match request type");
break;
}

}else {
AlertUtil.alertShareFail(context);
Log.i(TAG,"onError response is null");
}
}


分享错误处理可以参考上一篇文章 错误处理 部分

若取消分享,则回调 onCancel( ) 方法,如下所示:

@Override
public void onCancel() {
super.onCancel();
Log.i(TAG,"onCancel");
}


无论是分享成功、失败或者取消分享,我们都会触发清除资源方法,如下所示:

@Override
public void clearResource() {
super.clearResource();
Log.i(TAG,"clearResource");
Platform.instance().clearPlatformResource();
}


代码相对简单,先准备 Bundle 类型 的分享数据,按照 key-value 形式填入数据,如标题、跳转链接。然后调用 shareToQQ( ) 方法,第二个入参是分享数据,第三个入参是分享结果的回调。

微信登录

微信分享结构和 QQ 分享很相似,这里只需说明 WxHandleRequest 类,其他参考上边QQ 分享部分。

WxHandleRequest 类

发送分享微信请求

由微信登录结构图可以知道,发送微信分享请求不需要依赖 UI ,看过上一篇文章的朋友会知道,我们使用 WxHandleRequest 类管理微信操作的请求,包括微信三方登录和分享。代码如下:

public void sendWxHandleRequest() {

if(null == api){
Log.i(TAG, "sendWxHandleRequest api is null");
return;
}
//请求类型
int type = Platform.instance().getRequestType();
Log.i(TAG, "sendWxHandleRequest type: " + type);

Bundle bundle = Platform.instance().getBundle();

//微信分享的目标场景:聊天界面、朋友圈、收藏
int shareScene;

switch (type){

case Constant.WX_LOGIN:
SendAuth.Req req_get_wx_token = WxRequestUtils.getWxCode();
api.sendReq(req_get_wx_token);
break;

case Constant.WX_SHARE_TEXT_MSG:

String content = bundle.getString(Constant.WX_SHARE_MSG_TEXT);
shareScene = bundle.getInt(Constant.WX_SHARE_SCENE);
SendMessageToWX.Req req_share_text_msg = WxRequestUtils.sendMsgToWX(content,shareScene);
api.sendReq(req_share_text_msg);

break;

case Constant.WX_SHARE_IMAGE_MSG:

String imagePath = bundle.getString(Constant.WX_SHARE_MSG_IMAGE_PATH);
shareScene = bundle.getInt(Constant.WX_SHARE_SCENE);
SendMessageToWX.Req req_share_img_msg =
WxRequestUtils.sendImageToWX(imagePath,shareScene);
api.sendReq(req_share_img_msg);

break;

case Constant.WX_SHARE_URL_MSG:

String wxTargetUrl = bundle.getString(Constant.WX_SHARE_URL);
String wxUrlTitle = bundle.getString(Constant.WX_SHARE_URL_TITLE);
String wxUrlContent = bundle.getString(Constant.WX_SHARE_URL_CONTENT);

shareScene = bundle.getInt(Constant.WX_SHARE_SCENE);
SendMessageToWX.Req req_share_url = WxRequestUtils.sendUrlToWX(context,
wxTargetUrl, wxUrlTitle, wxUrlContent, shareScene);
api.sendReq(req_share_url);
break;

case Constant.WX_SHARE_MUSIC_MSG:
String wxMusicUrl = bundle.getString(Constant.WX_SHARE_MUSIC_URL);
String wxMusicTitle = bundle.getString(Constant.WX_SHARE_MUSIC_TITLE);
String wxMusicContent = bundle.getString(Constant.WX_SHARE_MUSIC_CONTENT);
shareScene = bundle.getInt(Constant.WX_SHARE_SCENE);
SendMessageToWX.Req req_share_music = WxRequestUtils.sendMusicToWX(context,
wxMusicUrl, wxMusicTitle, wxMusicContent, shareScene);
api.sendReq(req_share_music);
break;

default:
Log.i(TAG,"sendWxHandleRequest no match type");
break;
}

}


其中,WxRequestUtils 是根据分享参数和类型生成 SendMessageToWX.Req 对象的工具类,以分享图片到微信为例子,代码如下:

public static SendMessageToWX.Req sendImageToWX(String imagePath,int shareScene) {

File file = new File(imagePath);
if (!file.exists()) {
Log.i(TAG,"sendImageToWX file is no exist");
return null;
}

WXImageObject imgObj = new WXImageObject();
imgObj.setImagePath(imagePath);

WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;

Bitmap bmp = BitmapFactory.decodeFile(imagePath);
Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
bmp.recycle();
msg.thumbData = Util.bmpToByteArray(thumbBmp, true);

SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("sendImageToWX");
req.message = msg;
req.scene = shareScene;

return req;
}


在这里需要注意的是,微信限制分享图片的缩略图(即预览图片)大小不超过 32Kb,否则发送的分享请求将被微信 sdk 拦截掉。

微信处理分享请求

微信通过回调 WXEntryActivity onResp( ) 方法,我们再回调给 ThirdPlatformShareUtil ,回调信息处理和 QQ 回调信息处理一致,这里不再累赘。

总结

异常情况

无法调起 QQ 或者 微信

保证 APP ID 填写正确。

保证包名正确,在 debug 包是无法调用微信分享。

分享成功,QQ 总是回调 onCancel( ) 方法。开始以为是 QQ 分享 bug ,后来想了想,觉得若是 QQ 分享的 bug ,这种必现的问题应该很快就发现并且修复,应该是自身调用代码问题,重新检查代码发现自己的 APP Id 没有写对,修改后发现分享成功能够回调 onComplete( ) 方法。



能够调起微信到选择好友列表,但是点击发送后无响应。检查proguard配置是否对微信SDK代码进行了混淆,建议不要对SDK对混淆,参考以下proguard配置:



分享图片到微信无反应

检查发送时的缩略图大小是否超过32k,微信 SDK demo 提供一个压缩图片 Util 工具类,若项目没有处理图片工具类,可以复用 微信 SDK demo 处理方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐