最后一次写Android分享

一、 分享吐槽

分享真的是做一次就要重新看一次文档,慢慢整理一份,微信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,传递会失败。微博,西八... ...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268