一、 分享吐槽
分享真的是做一次就要重新看一次文档,慢慢整理一份,微信QQ的文档还好说,微博文档我都怀疑自己穿越了。所以打算整理一份分享框架,只写最后一次。
二、 分享到哪
微信/QQ/抖音/微博/快手(快手暂时还不支持)
三、 分享类型
文本分享/图片分享/视频分享/网页分享
四、 一台没有感情的分享机器
就我列举出来的分享方法,两两组合已经有20个方法了,还不包括后续扩展的。当然可以整理一个下面的工具类:
public class ShareUtils {
public static void shareWxText(Activity activity, String title, String description, String linkUrl, String imageUrl){
}
public static void shareWxImage(){
}
public static void shareQQText(){
}
public static void shareQQImage(){
}
}
但是这种工具类根本就不是最后一次写啊。
1.首先每个方法的入参都很多,文本分享就有5个参数了,还不加上回调;
2.微博的sdk接入简直反人类,需要在每个唤起的页面增加onActivityResult()特殊代码。
针对问题1,可以利用构建者模式,按需构建需要的入参;
针对问题2,可以利用一个透明的activity,在分享的时候作为接收回调的过渡页面。
五、 具体实现
定义分享渠道和分享类型:
public class ShareChannel {
public static final int DOUYIN = 0x100; //抖音
public static final int WECHAT = 0x200; //微信
public static final int WECHAT_FRIENDS = 0x201; //微信朋友圈
public static final int QQ = 0x300; //QQ
public static final int QQ_ZONE = 0x301; //QQ空间
public static final int WEIBO = 0x400; //微博
}
public class ShareType {
public static final int SHARE_TYPE_TEXT = 0x1000; //文本
public static final int SHARE_TYPE_IMAGE = 0x2000; //图片
public static final int SHARE_TYPE_MUSIC = 0x3000;
public static final int SHARE_TYPE_APP = 0x4000;
public static final int SHARE_TYPE_VIDEO = 0x5000;
public static final int SHARE_TYPE_WEBPAGE = 0x6000;
}
构建入参:
public class ShareData implements Serializable {
private ArrayList<String> uris;
private String title = "标题";
private String description = "描述";
private String linkUrl;
private String imageUrl;
private String musicUrl;
private String videoUrl;
private String defaultText;
private String appName;
private int shareChannel;
private int shareType;
private ShareData() {
}
public static ShareData.Builder builder() {
return new Builder();
}
public static class Builder {
private ArrayList<String> uris;
private String title;
private String description;
private String linkUrl;
private String imageUrl;
private String musicUrl;
private String videoUrl;
private String appName;
private String defaultText;
private int shareChannel;
private int shareType;
public ShareData build() {
ShareData shareData = new ShareData();
return shareData;
}
}
/**
* 分享调用
*
* @param activity
*/
public void share(Activity activity) {
}
}
定义接口,描述分享的能力:
public interface IShare {
void shareText(ShareData shareData);
void shareImages(ShareData shareData);
void shareMusic(ShareData shareData);
void shareApp(ShareData shareData);
void shareVideos(ShareData shareData);
void shareWebPage(ShareData shareData);
}
微信分享直接定义类实现IShare方法,接入api就行。重点说微博,一言难尽,微博需要借助中间页,才能按照接口标准来调用。新建中间页:
public class WeiBoEntryActivity extends AppCompatActivity implements WbShareCallback, IShare {
private static final int THUMB_SIZE = 150;
public static final String KEY_SHARE_DATA = "shareData";
public static final String KEY_SHARE_TYPE = "shareType";
private WbShareHandler wbApi;
private ShareData shareData;
public static void start(Context context, ShareData shareData, int shareType) {
Intent starter = new Intent(context, WeiBoEntryActivity.class);
starter.putExtra(KEY_SHARE_DATA, shareData);
starter.putExtra(KEY_SHARE_TYPE, shareType);
context.startActivity(starter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wei_bo_entry);
wbApi = new WbShareHandler(this);
wbApi.registerApp();
Intent intent = getIntent();
if (intent != null && intent.hasExtra(KEY_SHARE_DATA)) {
shareData = (ShareData) intent.getSerializableExtra(KEY_SHARE_DATA);
int shareType = intent.getIntExtra(KEY_SHARE_TYPE, SHARE_TYPE_TEXT);
switch (shareType){
case SHARE_TYPE_TEXT:
shareText(shareData);
break;
case SHARE_TYPE_IMAGE:
shareImages(shareData);
break;
}
}
}
@Override
public void onWbShareSuccess() {
Toast.makeText(this, "微博分享成功", Toast.LENGTH_SHORT).show();
finish();
}
@Override
public void onWbShareCancel() {
Toast.makeText(this, "微博分享取消", Toast.LENGTH_SHORT).show();
finish();
}
@Override
public void onWbShareFail() {
Toast.makeText(this, "微博分享失败", Toast.LENGTH_SHORT).show();
finish();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if(wbApi != null){
wbApi.doResultIntent(intent, this);
}else{
finish();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (wbApi != null) {
wbApi.doResultIntent(data, this);
}
}
}
@Override
public void shareText(ShareData shareData) {
WeiboMultiMessage weiboMessage = new WeiboMultiMessage();
TextObject textObject = new TextObject();
textObject.text = shareData.getDescription();
weiboMessage.textObject = textObject;
wbApi.shareMessage(weiboMessage, false);
}
@Override
public void shareImages(ShareData shareData) {
}
public void shareMusic(ShareData shareData) {
}
public void shareApp(ShareData shareData) {
}
@Override
public void shareVideos(ShareData shareData) {
}
@Override
public void shareWebPage(ShareData shareData) {
}
}
这个页面什么时候唤起呢?新建WeiBoShare类:
public class WeiBoShare implements IShare {
private Activity activity;
public WeiBoShare(Activity activity) {
this.activity = activity;
}
@Override
public void shareText(ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_TEXT);
}
@Override
public void shareImages(ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_IMAGE);
}
@Override
public void shareMusic(ShareData shareData) {
}
@Override
public void shareApp(ShareData shareData) {
}
@Override
public void shareVideos(ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_VIDEO);
}
@Override
public void shareWebPage(ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_WEBPAGE);
}
}
这样我们在构建完参数调用share()方法的时候会先判断shareChannel去初始化对应的分享实体,例如微博分享就初始化WeiBoShare对象,然后调用shareText()方法的时候会开启中间页,完成分享。
当完成所有渠道的代码之后,ShareData类的share()可以完善为:
public class ShareData{
//省略上面已有代码
public void share(Activity activity) {
//根据shareChannel执行对应的渠道分享
switch (shareChannel) {
case ShareChannel.DOUYIN:
shareDouYin(activity);
break;
case ShareChannel.WECHAT:
case ShareChannel.WECHAT_FRIENDS:
shareWeChat(activity);
break;
case ShareChannel.QQ:
case ShareChannel.QQ_ZONE:
QqEntryActivity.start(activity, this, shareType);
break;
case ShareChannel.WEIBO:
WeiBoEntryActivity.start(activity, this, shareType);
break;
}
}
private void shareDouYin(Activity activity) {
switch (shareType) {
case ShareType.SHARE_TYPE_IMAGE:
new DouYinShare(activity).shareImages(this);
break;
case ShareType.SHARE_TYPE_VIDEO:
new DouYinShare(activity).shareVideos(this);
break;
}
}
private void shareWeChat(Activity activity) {
//根据对应的shareType执行对应的类型分享
switch (shareType) {
case ShareType.SHARE_TYPE_TEXT:
new WechatShare(activity).shareText(this);
break;
case ShareType.SHARE_TYPE_IMAGE:
new WechatShare(activity).shareImages(this);
break;
case ShareType.SHARE_TYPE_VIDEO:
new WechatShare(activity).shareVideos(this);
break;
case ShareType.SHARE_TYPE_WEBPAGE:
new WechatShare(activity).shareWebPage(this);
break;
}
}
}
到这我测试了一下,整体没有问题,但是还是开篇讲的,要是再来一个渠道和类型,我还是要case一下啊。如果能改为插件式的那种,尽可能增加少的代码,入侵更少的类。
六、 插件式
既然是插件式的,就需要一个插件管理类:
public class SharePluginsManager {
private SharePluginsManager() {
}
private static SharePluginsManager instance = null;
public static SharePluginsManager getInstance() {
if (instance == null) {
synchronized (SharePluginsManager.class) {
if (instance == null) {
instance = new SharePluginsManager();
}
}
}
return instance;
}
/**
* 缓存分享实体
*/
private ArrayMap<String, IShare> shareMap = new ArrayMap<>();
/**
* 初始化分享类集合
*/
private List<String> shareClazzs = new ArrayList<>();
/**
* 添加share插件
* @param shareClazz
*/
public void addSharePlugin(String shareClazz){
if(!shareClazzs.contains(shareClazz)){
shareClazzs.add(shareClazz);
}
}
/**
* 通过渠道获取插件实体,过滤方法在这里使用到
* @param shareChannel
* @return
*/
public IShare getShareEntity(int shareChannel) {
try {
int size = shareClazzs.size();
for (int i = 0; i < size; i++) {
String shareClazz = shareClazzs.get(i);
IShare iShare = shareMap.get(shareClazz);
if (iShare == null) {
Class<?> clazz = Class.forName(shareClazz);
iShare = (IShare) clazz.newInstance();
shareMap.put(shareClazz, iShare);
}
if (iShare != null && iShare.filter(shareChannel)) {
return iShare;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
需要增加一个ShareFilter接口,对分享的插件进行过滤,因为SharePluginsManager肯定是一个集合,每一次分享需要从集合过滤出需要的插件。为减少代码量,直接让插件自身具有过滤的能力了。
更改IShare接口:
public interface IShare {
//过滤
boolean filter(int shareChannel);
//分享派发
void share(Activity activity, ShareData shareData);
//分享文本
void shareText(Activity activity, ShareData shareData);
//分享图片
void shareImages(Activity activity, ShareData shareData);
//分享音乐
void shareMusic(Activity activity, ShareData shareData);
//分享应用
void shareApp(Activity activity, ShareData shareData);
//分享视频
void shareVideos(Activity activity, ShareData shareData);
//分享网页
void shareWebPage(Activity activity, ShareData shareData);
}
还拿上面的WeiBoShare举例,修改类名为WeiBoSharePlugin,看起来像那么回事:
public class WeiBoSharePlugin implements IShare {
public WeiBoSharePlugin() {
}
@Override
public boolean filter(int shareChannel) {
return shareChannel == ShareChannel.WEIBO;
}
@Override
public void share(Activity activity, ShareData shareData) {
int shareType = shareData.getShareType();
switch (shareType) {
case SHARE_TYPE_TEXT:
shareText(activity, shareData);
break;
case SHARE_TYPE_IMAGE:
shareImages(activity, shareData);
break;
case SHARE_TYPE_VIDEO:
shareVideos(activity, shareData);
break;
case SHARE_TYPE_WEBPAGE:
shareWebPage(activity, shareData);
break;
}
}
@Override
public void shareText(Activity activity, ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_TEXT);
}
@Override
public void shareImages(Activity activity, ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_IMAGE);
}
@Override
public void shareMusic(Activity activity, ShareData shareData) {
}
@Override
public void shareApp(Activity activity, ShareData shareData) {
}
@Override
public void shareVideos(Activity activity, ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_VIDEO);
}
@Override
public void shareWebPage(Activity activity, ShareData shareData) {
WeiBoEntryActivity.start(activity, shareData, SHARE_TYPE_WEBPAGE);
}
}
这样修改之后,ShareData下的share()方法就变得非常简单了:
public class ShareData implements Serializable {
//其他代码省略...
public void share(Activity activity) {
IShare iShare = SharePluginsManager.getInstance().getShareEntity(shareChannel);
if (iShare != null) {
iShare.share(activity, this);
} else {
Toast.makeText(activity, "没有找到分享渠道", Toast.LENGTH_SHORT).show();
}
}
}
七、 分享示例
最终调用:
ShareData.builder()
.shareChannel(ShareChannel.WEIBO)
.shareType(ShareType.SHARE_TYPE_TEXT)
.build()
.share((Activity) mContext);
扩展的话也很方便,只需要新建一个类实现IShare接口,然后在App启动的时候,注册一下插件:
SharePluginsManager.getInstance().addSharePlugin(QqSharePlugin.class.getName());
SharePluginsManager.getInstance().addSharePlugin(WechatSharePlugin.class.getName());
SharePluginsManager.getInstance().addSharePlugin(WeiBoSharePlugin.class.getName());
SharePluginsManager.getInstance().addSharePlugin(DouYinSharePlugin.class.getName());
唯一不和谐的就是ShareData的share()方法入参,需要传入一个Activity。这个Activity可以在ShareData参数时构建吗?不可以,主要原因就是微博这种需要传递ShareData到中间页,Activity又没有继承自Serializable,传递会失败。微博,西八... ...
网友评论