最后一次寫Android分享

一、 分享吐槽

分享真的是做一次就要重新看一次文檔,慢慢整理一份,微信QQ的文檔還好說,微博文檔我都懷疑自己穿越了。所以打算整理一份分享框架,只寫最后一次。

二、 分享到哪

微信/QQ/抖音/微博/快手(快手暫時還不支持)

三、 分享類型

文本分享/圖片分享/視頻分享/網(wǎng)頁分享

四、 一臺沒有感情的分享機器

就我列舉出來的分享方法,兩兩組合已經(jīng)有20個方法了,還不包括后續(xù)擴展的。當然可以整理一個下面的工具類:

    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.首先每個方法的入?yún)⒍己芏?,文本分享就?個參數(shù)了,還不加上回調(diào);
2.微博的sdk接入簡直反人類,需要在每個喚起的頁面增加onActivityResult()特殊代碼。

針對問題1,可以利用構(gòu)建者模式,按需構(gòu)建需要的入?yún)ⅲ?針對問題2,可以利用一個透明的activity,在分享的時候作為接收回調(diào)的過渡頁面。

五、 具體實現(xiàn)

定義分享渠道和分享類型:

    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;
    }

構(gòu)建入?yún)ⅲ?/p>

    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;
            }
        }
    
        /**
         * 分享調(diào)用
         *
         * @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);
    }

微信分享直接定義類實現(xiàn)IShare方法,接入api就行。重點說微博,一言難盡,微博需要借助中間頁,才能按照接口標準來調(diào)用。新建中間頁:

    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);
        }
    }

這樣我們在構(gòu)建完參數(shù)調(diào)用share()方法的時候會先判斷shareChannel去初始化對應的分享實體,例如微博分享就初始化WeiBoShare對象,然后調(diào)用shareText()方法的時候會開啟中間頁,完成分享。

當完成所有渠道的代碼之后,ShareData類的share()可以完善為:

    public class ShareData{
    
        //省略上面已有代碼
    
        public void share(Activity activity) {
            //根據(jù)shareChannel執(zhí)行對應的渠道分享
                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) {
                //根據(jù)對應的shareType執(zhí)行對應的類型分享
                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);
        
        //分享派發(fā)
        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);
    
        //分享網(wǎng)頁
        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();
            }
        }
    }

七、 分享示例

最終調(diào)用:

    ShareData.builder()
             .shareChannel(ShareChannel.WEIBO)
             .shareType(ShareType.SHARE_TYPE_TEXT)
             .build()
             .share((Activity) mContext);

擴展的話也很方便,只需要新建一個類實現(xiàn)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()方法入?yún)ⅲ枰獋魅胍粋€Activity。這個Activity可以在ShareData參數(shù)時構(gòu)建嗎?不可以,主要原因就是微博這種需要傳遞ShareData到中間頁,Activity又沒有繼承自Serializable,傳遞會失敗。微博,西八... ...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容