Android 輕量級分享封裝

前言

提到分享喻旷,幾乎所有應(yīng)用都會有的功能蝙茶,雖然說不是難點(diǎn)何缓,但是還是要有稻薇。最近公司也在做分享功能乾戏,以前也做過很多次分享懦铺,基本都是集成第三方分享SDK白粉,然后按照開發(fā)文檔步驟完成割卖。隔一段時間就會忘記來龍去脈壁畸,再次做分享贼急,還要去查看官方文檔茅茂。因此,本次準(zhǔn)備花點(diǎn)時間封裝第三方分享SDK太抓,這樣做的好處是方便以后使用空闲,另一方面也可以自己學(xué)習(xí)到一些新的東西。分享有兩種方式走敌,一種是第三方分享SDK碴倾,第二種是隱士跳轉(zhuǎn)方式,用于隱士跳轉(zhuǎn)方式有某些局限掉丽,一方面是QQ空間分享不對外開放跌榔,另一方面是第三方分享SDK額分享監(jiān)聽做的比較全面,不需要再次自己去封裝捶障。因此本文主要介紹關(guān)于第三方分享SDK的封裝僧须,,后面也會把原生的封裝帶上项炼。本文同樣采用建造者模式創(chuàng)建担平,結(jié)構(gòu)簡單清晰,本文省略申請賬號過程锭部≡萋郏基本使用如下:

測試分享.png
ShareKeeper.getInstance()
                .builder(this)
                .setPlatform(ShareKeeper.PLATFORM_QZONE)
                .setShareType(ShareKeeper.TYPE_DEFAULT)
                .setTitle(title)
                .setDesc(desc)
                .setImageUrl(imageUrl)
                .setImagePath(localPicPath)
                .setWebUrl(webUrl)
                .setAVdioUrl(videoUrl)
                .setAVdioPath(localVideoPath)
                .setOnShareListener(this)
                .share();

屬性介紹

可能看到上面的使用可能會覺得那么多屬性,肯定很復(fù)雜拌禾,其實(shí)不然取胎。上面舉例是把所有的屬性都列舉出來了,但是實(shí)際用不到那么多屬性湃窍。下面就來介紹所有的屬性闻蛀。

builder(this) :構(gòu)建建造者模式
setPlatform(): 設(shè)置分享平臺,例如:QQ坝咐、微信循榆、QQ空間等 (可以不填,默認(rèn)QQ分享)
setShareType():設(shè)置分享的類型墨坚,根據(jù)形式分為,圖文映挂、純圖片泽篮、音視頻、純文本(此分類不已第三方分享SDK分類)柑船,可以不設(shè)置帽撑,默認(rèn)為圖文類型
setTitle(title):設(shè)置標(biāo)題,可以不設(shè)置(內(nèi)部已經(jīng)做了防止空指針鞍时,但是建議設(shè)置亏拉,或者設(shè)置appname亦可)
setDesc(desc):設(shè)置簡介扣蜻,設(shè)置同上
setImageUrl(imageUrl):設(shè)置網(wǎng)絡(luò)圖片路徑
.setImagePath(localPicPath):設(shè)置本地圖片路徑
setAVdioUrl(videoUrl):設(shè)置網(wǎng)絡(luò)音視頻鏈接
setAVdioPath(localVideoPath):設(shè)置本地音視頻地址
setWebUrl(webUrl):設(shè)置分享的鏈接(除了分享圖片之外,都是必備的屬性)
setOnShareListener(this):設(shè)置分享監(jiān)聽回調(diào)(建議回調(diào))

微信分享

檢測客戶端
/**
     * 手機(jī)是否安裝微信客戶端
     *
     * @param context
     * @return
     */
    public static boolean isWeixinAvilible(Context context) {
        final PackageManager packageManager = context.getPackageManager();// 獲取packagemanager
        List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);// 獲取所有已安裝程序的包信息
        if (pinfo != null) {
            for (int i = 0; i < pinfo.size(); i++) {
                String pn = pinfo.get(i).packageName;
                if (pn.equals("com.tencent.mm")) {
                    return true;
                }
            }
        }
        return false;
    }
微信屬性介紹
WXMediaMessage.IMediaObject :微信分享SDK內(nèi)部做了分享的封裝類,包括文本及塘、圖片莽使、視頻等
WXMediaMessage :攜帶IMediaObject 以及標(biāo)題、描述笙僚、縮略圖信息
msg.title :標(biāo)題
msg.description :描述
msg.thumbData :縮略數(shù)據(jù)(圖片內(nèi)容)
SendMessageToWX.Req:攜帶WXMediaMessage 和分享數(shù)據(jù)
transaction    :分享攜帶數(shù)據(jù)芳肌,相當(dāng)于類型,回調(diào)到WXEntryActivity為BaseResp resp中的參數(shù)肋层,可以做過濾作用
message :攜帶WXMediaMessage 
scene :場景亿笤,即分享平臺
創(chuàng)建不同的類型

由于微信分享和朋友圈分享沒有區(qū)別,所以在一起統(tǒng)一封裝如下:

/**
     * 創(chuàng)建分享的IMediaObject
     *
     * @param builder
     * @param bitmap
     * @return
     */
    private static WXMediaMessage.IMediaObject createIMediaObject(ShareKeeper.Builder builder, Bitmap bitmap) {

        int mPlatform = builder.mPlatform;
        int mShareType = builder.mShareType;
        WXMediaMessage.IMediaObject mediaObject = null;
        OnShareListener mOnShareListener = builder.mOnShareListener;

        if (mShareType == ShareKeeper.TYPE_DEFAULT) {
            WXWebpageObject webpageObject = new WXWebpageObject();
            String mWebUrl = builder.mWebUrl;
            if (!TextUtils.isEmpty(mWebUrl)) {
                webpageObject.webpageUrl = mWebUrl;
                mediaObject = webpageObject;
            } else {
                if (mOnShareListener != null) {
                    mOnShareListener.onShareFailed(mPlatform, "分享的鏈接不能為空!");
                }
            }
        } else if (mShareType == ShareKeeper.TYPE_PICTURE) {
            if (bitmap != null) {
                WXImageObject imgObj = new WXImageObject(bitmap);
                mediaObject = imgObj;
            } else {
                if (mOnShareListener != null) {
                    mOnShareListener.onShareFailed(mPlatform, "分享的圖片不能為空!");
                }
            }
        } else if (mShareType == ShareKeeper.TYPE_AVDIO) {
            String videoUrl = builder.mAVdioUrl;
            if (!TextUtils.isEmpty(videoUrl)) {
                WXVideoObject videoObject = new WXVideoObject();
                videoObject.videoUrl = videoUrl;
                mediaObject = videoObject;
            } else {
                if (mOnShareListener != null) {
                    mOnShareListener.onShareFailed(mPlatform, "分享的視頻鏈接不能為空!");
                }
            }
        } else if (mShareType == ShareKeeper.TYPE_TXT) {
            String desc = builder.mDesc;
            if (!TextUtils.isEmpty(desc)) {
                WXTextObject textObj = new WXTextObject();
                textObj.text = desc;
                mediaObject = textObj;
            } else {
                if (mOnShareListener != null) {
                    mOnShareListener.onShareFailed(mPlatform, "分享的文本不能為空!");
                }
            }
        }
        return mediaObject;
    }

說明:WXMediaMessage.IMediaObject封裝了微信分享不同栋猖,所以在此根據(jù)分享類型創(chuàng)建不同的IMediaObject净薛,有些必不可缺的屬性都做了分享回調(diào)失敗,當(dāng)然也可以做拋異常的形式(不建議蒲拉,程序會崩潰)罕拂。

微信分享
/**
     * 執(zhí)行
     *
     * @param bitmap
     * @param iwxapi
     * @param builder
     */
    private static void performShare(Bitmap bitmap, IWXAPI iwxapi, ShareKeeper.Builder builder) {
        OnShareListener mOnShareListener = builder.mOnShareListener;
        WXMediaMessage.IMediaObject iMediaObject = createIMediaObject(builder, bitmap);

        if (iMediaObject != null) {
            //檢測參數(shù)可以分享
            boolean checkArgs = iMediaObject.checkArgs();
            if (checkArgs) {
                //共同的部分
                WXMediaMessage msg = new WXMediaMessage(iMediaObject);
                msg.title = builder.mTitle;//標(biāo)題
                msg.description = builder.mDesc;//描述
               //縮略圖
                if (bitmap != null) {
                    byte[] thumbData = BitmpUtils.compressBitmapSpecifySize(bitmap, IMAGE_MAX_SIZE);
                    if (thumbData.length > IMAGE_MAX_SIZE) {
                        if (mOnShareListener != null) {
                            mOnShareListener.onShareFailed(builder.mPlatform, "分享的縮略圖過大");
                        }
                        return;
                    }
                    msg.thumbData = thumbData;//縮略數(shù)據(jù)(圖片內(nèi)容)
                }
                //共同的部分
                SendMessageToWX.Req req = new SendMessageToWX.Req();
                req.transaction = buildDiffTransaction(builder.mShareType);
                req.message = msg;
                int mScene = builder.mPlatform == ShareKeeper.PLATFORM_WECHAT ? WXSceneSession : WXSceneTimeline;
                req.scene = mScene;
                //攜帶監(jiān)聽
                Bundle bundle = new Bundle();
                bundle.putSerializable("builder", builder);
                req.toBundle(bundle);
                iwxapi.sendReq(req);
            } else {
                if (mOnShareListener != null) {
                    mOnShareListener.onShareFailed(builder.mPlatform, "分享參數(shù)異常");
                }
            }
        }
    }

說明:1、boolean checkArgs = iMediaObject.checkArgs()全陨,微信分享SDK內(nèi)部檢測參數(shù)爆班,判斷參數(shù)是否正確
2、byte[] thumbData = BitmpUtils.compressToBitmapLast(bitmap, IMAGE_MAX_SIZE)為縮略圖辱姨,除了分享圖片 必備之外柿菩,其他情況都可以沒有。

壓縮圖片

關(guān)于微信分享最容易出錯的就是分享的圖片過大雨涛,微信規(guī)定分享的縮略圖大小不能超過32768K枢舶,所以分享之前必須做壓縮處理,本文主要采用先質(zhì)量壓縮至10%替久,如果還超過規(guī)定分享縮略圖大小再采取尺寸壓縮凉泄,如果尺寸壓縮之后依舊不行,可以采用第三方壓縮工具或者替換圖片蚯根。

 /**
     * 圖片壓縮到指定大小
     *
     * @param bmp
     * @param maxByteSize
     * @return
     */
    public static byte[] compressBitmapSpecifySize(final Bitmap bmp, final long maxByteSize) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] bytes = null;
        int options = 100;
        int outSize = baos.size();

        if (outSize <= maxByteSize) {
            bytes = baos.toByteArray();
        } else {
            while (outSize > maxByteSize && options > 0) {
                baos.reset(); //清空baos
                bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);//這里壓縮options%后众,把壓縮后的數(shù)據(jù)存放到baos中
                outSize = baos.size();
                options -= 10;
            }

            if (outSize > maxByteSize) {
                bytes = compressBitmapSize(bmp, options, maxByteSize);
            } else {
                bytes = baos.toByteArray();
            }
        }
        if (!bmp.isRecycled()) bmp.recycle();
        return bytes;
    }

    /**
     * 需要壓縮
     *
     * @param bmp
     */
    private static byte[] compressBitmapSize(Bitmap bmp, int options, final long maxByteSize) {
        //繼續(xù)在當(dāng)前的質(zhì)量下壓縮
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
        int outSize = baos.size();
        int orginOpi = options;

        while (outSize > maxByteSize && options > 0) {
            baos.reset(); //清空baos
            Bitmap bitmap = BitmpUtils.scaleBitmap(bmp, options * 0.1f);
            bitmap.compress(Bitmap.CompressFormat.JPEG, orginOpi, baos);//這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中
            options--;
        }

        byte[] bytes = baos.toByteArray();
        return bytes;
    }

微信分享結(jié)果處理

微信分享的結(jié)果處理是在WXEntryActivity的onResp(BaseResp resp)方法中處理各種分享返回結(jié)果

if (shareBuilder != null) {
            OnShareListener onShareListener = shareBuilder.mOnShareListener;
            if (onShareListener != null) {
                int errCode = resp.errCode;
                if (errCode == BaseResp.ErrCode.ERR_OK) {
                    onShareListener.onShareSuccess(shareBuilder.mPlatform);
                } else if (errCode == BaseResp.ErrCode.ERR_SENT_FAILED) {
                    onShareListener.onShareFailed(shareBuilder.mPlatform, "發(fā)送失敗");
                } else if (errCode == BaseResp.ErrCode.ERR_AUTH_DENIED) {
                    onShareListener.onShareFailed(shareBuilder.mPlatform, "認(rèn)證被否決");
                } else if (errCode == BaseResp.ErrCode.ERR_UNSUPPORT) {
                    onShareListener.onShareFailed(shareBuilder.mPlatform, "版本不支持");
                } else if (errCode == BaseResp.ErrCode.ERR_COMM) {
                    onShareListener.onShareFailed(shareBuilder.mPlatform, "一般錯誤");
                } else if (errCode == BaseResp.ErrCode.ERR_USER_CANCEL) {
                    onShareListener.onCancleShare(shareBuilder.mPlatform, "取消分享");
                } else {
                    onShareListener.onShareFailed(shareBuilder.mPlatform, "未知錯誤");
                }
            }
        }

說明:關(guān)于微信分享結(jié)果需要注意一點(diǎn)颅拦,由于微信分享SDK升級蒂誉,分享取消和分享成功都會返回分享成功。
新版微信分享取消與成功合并

QQ分享

檢測QQ客戶端
/**
     * 手機(jī)是否安裝QQ客戶端
     *
     * @param context
     * @return
     */
    public static boolean isQQClientAvailable(Context context) {
        final PackageManager packageManager = context.getPackageManager();
        List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
        if (pinfo != null) {
            for (int i = 0; i < pinfo.size(); i++) {
                String pn = pinfo.get(i).packageName;
                if (pn.equals("com.tencent.mobileqq")) {
                    return true;
                }
            }
        }
        return false;
    }
QQ分享屬性介紹

qq分享屬性全部封裝在一個Bundle里面

QQShare.SHARE_TO_QQ_KEY_TYPE:分享類型
QQShare.SHARE_TO_QQ_TITLE:分享標(biāo)題(默認(rèn)不可以為空距帅,內(nèi)部做了防止空指針)
QQShare.SHARE_TO_QQ_SUMMARY:分享簡介(設(shè)置同上)
QQShare.SHARE_TO_QQ_TARGET_URL:weburl(除了分享圖片以外必須參數(shù))
QQShare.SHARE_TO_QQ_IMAGE_URL:網(wǎng)絡(luò)圖片(縮略圖右锨,但不是單純分享圖片的地址,沒有也不影響)
QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL:本地圖片路徑(單純的本地圖片碌秸,必要參數(shù)绍移,一定要本地路徑)
QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN):分享qq空間特有(權(quán)限)

注意:1悄窃、qq空間的屬性需要把QQ替換成QZONE
2、網(wǎng)絡(luò)圖片鏈接在qq分享和qq空間分享的數(shù)據(jù)裝載形式不一樣蹂窖,qq分享直接存在Bundle中轧抗,qq空間在先存放在集合中,然后添加集合方式恼策,具體看下面代碼鸦致。

QQ分享

由于QQ不能單獨(dú)分享文本,因此需要單獨(dú)處理涣楷,另外QQ空間不對外開放且QQ空間不能單獨(dú)分享圖片和視頻分唾,因此QQ空間分享只做默認(rèn)的圖文分享。因此下面僅介紹QQ分享狮斗。

文本分享
//純文本分享
Intent intent = new Intent("android.intent.action.SEND");
intent.setType(NetiveShareTask.TYPE_TXT);
intent.putExtra(Intent.EXTRA_SUBJECT,"分享");
intent.putExtra(Intent.EXTRA_TEXT,builder.mDesc+"");//不能為空
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(QQ_PACKAGE_NAME,QQ_SHARE_COMPONENT_NAME));
activity.startActivityForResult(intent,TEXT_REQUEST_CODE);

圖片分享

QQ分享SDK默認(rèn)只支持本地圖片路徑分享绽乔,因此如果是網(wǎng)絡(luò)圖片,需要先下載到本地然后再去分享碳褒,本地圖片分享跟其他分享區(qū)別不大折砸,只有一點(diǎn)就是純圖片分享,圖片不能為空沙峻,但是鏈接是唯一可以為空的類型睦授,因此這里主要講解網(wǎng)絡(luò)圖片的分享。

/**
     * 分享網(wǎng)絡(luò)圖片
     * 需要先下載到本地
     * 然后設(shè)置到本地路徑去分享
     *
     * @param activity
     * @param builder
     */
    private static void performShareNetPic(final Activity activity, final Tencent mTencent, final ShareKeeper.Builder builder) {
        new Thread() {
            public void run() {
                OnShareListener mOnShareListener = builder.mOnShareListener;
                try {
                    String mImageUrl = builder.mImageUrl;
                    //先獲取圖片然后保存到本地分享
                    Bitmap urlBitmap = BitmpUtils.getUrlBitmap(mImageUrl);
                    //檢測生成的圖片是否存在
                    if (urlBitmap == null && mOnShareListener != null) {
                        mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享圖片為空!");
                        return;
                    }
                    //SDK分享網(wǎng)絡(luò)圖片
                    final String saveBitmapToLocal = BitmpUtils.saveBitmapToLocal(activity, urlBitmap);
                    builder.setImagePath(saveBitmapToLocal);
                    //最后轉(zhuǎn)為本地分享
                    performShareLocalPic(activity, mTencent, builder);
                } catch (IOException e) {
                    e.printStackTrace();
                    if (mOnShareListener != null) {
                        mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享異常:" + e.getMessage());
                    }
                }
            }
        }.start();
    }

音視頻分享

QQ分享SDK是支持音視頻分享的摔寨,不過是分享的鏈接去枷,因此如果要分享本地音視頻,要特殊處理是复。因此此處單獨(dú)做QQ本地音視頻的分享講解删顶。此處采用系統(tǒng)的分享方式,通過隱士跳轉(zhuǎn)分享淑廊。

 /**
     * QQ分享本地視頻
     *
     * @param activity
     * @param builder
     */
    private static void performQQShareAVideoNative(Activity activity, ShareKeeper.Builder builder) {
        String mAVdioPath = builder.mAVdioPath;
        OnShareListener mOnShareListener = builder.mOnShareListener;
        Uri uri = UriUtils.getUri(activity, mAVdioPath);
        if (uri == null) {
            if (mOnShareListener != null) {
                mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享本地視頻地址異常!");
            }
            return;
        }
        Intent intent = new Intent("android.intent.action.SEND");
        intent.setType(NetiveShareTask.TYPE_VIDEO);
        intent.putExtra(Intent.EXTRA_TEXT, builder.mTitle + "");//不能為空
        intent.putExtra(Intent.EXTRA_SUBJECT, builder.mDesc + "");
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setComponent(new ComponentName(QQ_PACKAGE_NAME, QQ_SHARE_COMPONENT_NAME));
        activity.startActivityForResult(intent, VIDEO_REQUEST_CODE);
    }
其他類型分享
/**
     * 分享網(wǎng)頁  默認(rèn)類型
     *
     * @param activity
     * @param mTencent
     * @param builder
     */
    private static void performQQShareWeb(Activity activity, Tencent mTencent, ShareKeeper.Builder builder) {
        Bundle params = new Bundle();
        params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);//默認(rèn)分享類型
        params.putString(QQShare.SHARE_TO_QQ_TITLE, builder.mTitle + "");//分享標(biāo)題(默認(rèn)不可以為空逗余,防止空指針)
        params.putString(QQShare.SHARE_TO_QQ_SUMMARY, builder.mDesc + "");//分享簡介(默認(rèn)可以為空防止空指針)
        params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, builder.mWebUrl);//weburl(除了圖片以外都需要)
        params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, builder.mImageUrl);//網(wǎng)絡(luò)圖片(縮略圖,沒有也不影響)
        params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, builder.mImagePath);//本地圖片路徑(單純的本地圖片分享使用)
        //創(chuàng)建監(jiān)聽器
        mQQShareListener = new QQShareListener(builder);
        mTencent.shareToQQ(activity, params, mQQShareListener);
    }

說明:
1季惩、由于文本分享沒用SDK录粱,所以監(jiān)聽只以跳轉(zhuǎn)成功為分享成功,無取消分享監(jiān)聽
2蜀备、QQ空間無法進(jìn)行圖片分享(建議QQ空間只做圖文分享)
3关摇、QQ分享如果單獨(dú)分享圖片,只能分享本地圖片
4碾阁、由于SDK做了判斷,因此performShare()不再做一些基本的參數(shù)判斷

QQ分享結(jié)果處理

QQ分享一定要處理當(dāng)前activity的onActivityResult()些楣,否則無法監(jiān)聽到QQ內(nèi)部的分享回調(diào)脂凶。

/**
     * 處理QQ分享
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void performQQShareResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != Activity.RESULT_OK) {
            return;
        }

        if (mShareBuilder != null) {
            OnShareListener mOnShareListener = mShareBuilder.mOnShareListener;
            //需要判斷是否是QQ分享
            if (requestCode == Constants.REQUEST_QQ_SHARE
                    || requestCode == Constants.REQUEST_QZONE_SHARE
                    || requestCode == Constants.REQUEST_OLD_SHARE) {
                IUiListener mIUiListener = QQShareTask.getIUiListener();
                if (mOnShareListener != null && mIUiListener != null) {
                    Tencent.onActivityResultData(requestCode, resultCode, data, mIUiListener);
                }
            } else if (requestCode == QQShareTask.TEXT_REQUEST_CODE
                    || requestCode == QQShareTask.PIC_REQUEST_CODE
                    || requestCode == QQShareTask.VIDEO_REQUEST_CODE) {
                //說明是QQ原生方式分享
                if (mOnShareListener != null) {
                    mOnShareListener.onShareSuccess(mShareBuilder.mPlatform, mShareBuilder.mShareType);
                }
            }
        }
    }

原生分享

利用原生的分享也是可以的宪睹,但是無法監(jiān)聽分享的結(jié)果,暫且以跳轉(zhuǎn)到目標(biāo)頁面為分享成功蚕钦,異常情況為分享失敗亭病。

原生分享文本
/**
     * 分享文本
     *
     * @param activity
     * @param builder
     */
    private static void performNativeShareTxt(Activity activity, ShareKeeper.Builder builder) {
        OnShareListener mOnShareListener = builder.mOnShareListener;
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType(NetiveShareTask.TYPE_TXT);
        intent.putExtra(Intent.EXTRA_TEXT, builder.mDesc + "");//不能為空
        Intent chooser = Intent.createChooser(intent, builder.mTitle);
        if (intent.resolveActivity(activity.getPackageManager()) != null) {
            activity.startActivityForResult(chooser, SHARE_REQUEST_CODE);
        } else {
            if (mOnShareListener != null) {
                mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享所在Activity異常!");
            }
        }
    }
原生分享圖片

原生分享還是分享本地圖片,網(wǎng)絡(luò)圖片要下載到本地再做分享嘶居。

/**
     * 原生本地圖片分享
     *
     * @param activity
     * @param builder
     */
    private static void performNativeShareLocalPic(Activity activity, ShareKeeper.Builder builder) {
        String mImagePath = builder.mImagePath;
        OnShareListener mOnShareListener = builder.mOnShareListener;
        Uri uri = UriUtils.getUri(activity, mImagePath);
        if (uri == null) {
            if (mOnShareListener != null) {
                mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享本地視頻地址異常!");
            }
            return;
        }
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType(NetiveShareTask.TYPE_IMAGE);
        intent.putExtra(Intent.EXTRA_TEXT, builder.mTitle + "");//不能為空
        intent.putExtra(Intent.EXTRA_SUBJECT, builder.mDesc + "");
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Intent chooser = Intent.createChooser(intent, builder.mTitle);
        if (intent.resolveActivity(activity.getPackageManager()) != null) {
            activity.startActivityForResult(chooser, SHARE_REQUEST_CODE);
        } else {
            if (mOnShareListener != null) {
                mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享所在Activity異常!");
            }
        }
    }
原生分享視頻
/**
     * 原生分享本地視頻
     *
     * @param activity
     * @param builder
     */
    private static void performNativeShareVideo(Activity activity, ShareKeeper.Builder builder) {
        String mAVdioPath = builder.mAVdioPath;
        OnShareListener mOnShareListener = builder.mOnShareListener;
        Uri uri = UriUtils.getUri(activity, mAVdioPath);
        if (uri == null) {
            if (mOnShareListener != null) {
                mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享本地視頻地址異常!");
            }
            return;
        }
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType(NetiveShareTask.TYPE_VIDEO);
        intent.putExtra(Intent.EXTRA_TEXT, builder.mTitle + "");//不能為空
        intent.putExtra(Intent.EXTRA_SUBJECT, builder.mDesc + "");
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Intent chooser = Intent.createChooser(intent, builder.mTitle);
        if (intent.resolveActivity(activity.getPackageManager()) != null) {
            activity.startActivityForResult(chooser, SHARE_REQUEST_CODE);
        } else {
            if (mOnShareListener != null) {
                mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享所在Activity異常!");
            }
        }
    }

微博分享

微博分享跟微信分享是非常相似的罪帖,所以很多細(xì)節(jié),具體細(xì)節(jié)可以參考代碼邮屁。

檢測微博客戶端
/**
     * 判斷 用戶是否安裝微博客戶端
     */
    public static boolean isWeiboClientAvailable(Context context) {
        final PackageManager packageManager = context.getPackageManager();
        List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
        if (pinfo != null) {
            for (int i = 0; i < pinfo.size(); i++) {
                String pn = pinfo.get(i).packageName;
                if (pn.equalsIgnoreCase("com.sina.weibo")) {
                    return true;
                }
            }
        }
        return false;
    }

檢測參數(shù)是否異常

微博分享每個類型的都有特有的檢測參數(shù)是否正常的方法整袁,所以還是要單獨(dú)檢測的。具體如下:

 /**
     * 檢測參數(shù)是否可以分享
     *
     * @param mShareType
     * @param baseMediaObject
     * @return
     */
    private static boolean checkShareArgs(int mShareType, BaseMediaObject baseMediaObject) {
        if (mShareType == ShareKeeper.TYPE_TXT) {
            TextObject textObject = (TextObject) baseMediaObject;
            return textObject.checkArgs();
        } else if (mShareType == ShareKeeper.TYPE_PICTURE) {
            ImageObject imageObject = (ImageObject) baseMediaObject;
            return imageObject.checkArgs();
        } else if (mShareType == ShareKeeper.TYPE_AVDIO || mShareType == ShareKeeper.TYPE_DEFAULT) {
            WebpageObject webpageObject = (WebpageObject) baseMediaObject;
            return webpageObject.checkArgs();
        }
        return false;
    }

微博分享特殊處

1佑吝、既有web分享也有客戶端分享坐昙,暫時項目中只支持客戶端分享,如想支持web分享芋忿,需要在manifest添加

<!--sina-->
<activity android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"
          android:configChanges="keyboardHidden|orientation"
          android:windowSoftInputMode="adjustResize"
          android:exported="false" >
</activity>

2炸客、結(jié)果回調(diào)需要用到當(dāng)前分享activity的onNewIntent(Intent intent)方法

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        ShareKeeper.getInstance().performWBShareResult(intent);
    }

wbShareHandler.doResultIntent即是微博分享的回調(diào),處理如下:

/**
     * 處理微博的分享監(jiān)聽
     *
     * @param intent
     */
    public void performWBShareResult(Intent intent) {
        WbShareHandler wbShareHandler = WBShareTask.getWbShareHandler();
        if (wbShareHandler != null) {
            if (mShareBuilder != null) {
                final int mPlatform = mShareBuilder.mPlatform;
                final int mShareType = mShareBuilder.mShareType;
                final OnShareListener mOnShareListener = mShareBuilder.mOnShareListener;
                if (mOnShareListener != null) {
                    wbShareHandler.doResultIntent(intent, new WbShareCallback() {
                        @Override
                        public void onWbShareSuccess() {
                            mOnShareListener.onShareSuccess(mPlatform, mShareType);
                        }

                        @Override
                        public void onWbShareCancel() {
                            mOnShareListener.onCancleShare(mPlatform, mShareType, "取消分享!");
                        }

                        @Override
                        public void onWbShareFail() {
                            mOnShareListener.onShareFailed(mPlatform, mShareType, "分享失敗!");
                        }
                    });
                }
            }
        }
    }

3戈钢、微博SDK內(nèi)部需要加載libweibosdkcore.so的文件痹仙,原因可以參考 Android7.x找不到libsqlite.so 問題,項目中已經(jīng)添加殉了,具體請參考代碼

微博分享完整
public class WBShareTask {


    private static WbShareHandler mShareHandler;
    public static final int IMAGE_MAX_SIZE = 32768;//分享圖片大小限制

    /**
     * 子線程中執(zhí)行操作
     *
     * @param activity
     * @param builder
     */
    public static void executeShare(Activity activity, final ShareKeeper.Builder builder) {
        boolean weiboClientAvailable = isWeiboClientAvailable(activity);
        OnShareListener mOnShareListener = builder.mOnShareListener;
        //監(jiān)測是否有客戶端
        if (!weiboClientAvailable) {
            mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "監(jiān)測不到客戶端");
        } else {
            WbSdk.install(activity, new AuthInfo(activity, Config.WEIBO_APP_ID, Config.WEIBO_WEB_SITE, Config.SCOPE));
            if (mShareHandler == null) mShareHandler = new WbShareHandler(activity);
            mShareHandler.registerApp();
            final Bitmap mLocalImage = BitmapFactory.decodeFile(builder.mImagePath);
            final String mImageUrl = builder.mImageUrl;
            //根據(jù)有沒有圖片分為三種情況
            new Thread() {
                public void run() {
                    if (mLocalImage != null) {
                        performShare(mLocalImage, mShareHandler, builder);
                    } else if (!TextUtils.isEmpty(mImageUrl)) {
                        Bitmap urlBitmap = BitmpUtils.getUrlBitmap(builder.mImageUrl);
                        performShare(urlBitmap, mShareHandler, builder);
                    } else {
                        performShare(null, mShareHandler, builder);
                    }
                }
            }.start();
        }
    }

    /**
     * 開始分享
     *
     * @param bitmap
     * @param mShareHandler
     * @param builder
     */
    private static void performShare(Bitmap bitmap, WbShareHandler mShareHandler, ShareKeeper.Builder builder) {
        OnShareListener mOnShareListener = builder.mOnShareListener;
        BaseMediaObject iMediaObject = createIMediaObject(builder, bitmap);

        if (iMediaObject != null) {
            //檢測參數(shù)可以分享
            boolean checkArgs = checkShareArgs(builder.mShareType, iMediaObject);
            if (checkArgs) {
                WeiboMultiMessage message = new WeiboMultiMessage();
                message.mediaObject = iMediaObject;
                mShareHandler.shareMessage(message, true);
            } else {
                if (mOnShareListener != null) {
                    mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享參數(shù)異常");
                }
            }
        }
    }


    /**
     * 創(chuàng)建不同的 BaseMediaObject
     *
     * @param builder
     * @param bitmap
     * @return
     */
    private static BaseMediaObject createIMediaObject(ShareKeeper.Builder builder, Bitmap bitmap) {
        int mShareType = builder.mShareType;
        OnShareListener mOnShareListener = builder.mOnShareListener;
        BaseMediaObject baseMediaObject = null;

        if (mShareType == ShareKeeper.TYPE_TXT) {
            TextObject textObject = new TextObject();
            textObject.text = builder.mDesc;
            textObject.title = builder.mTitle;
            baseMediaObject = textObject;
        } else if (mShareType == ShareKeeper.TYPE_PICTURE) {
            ImageObject imageObject = new ImageObject();
            //縮略圖
            if (bitmap != null) {
                byte[] thumbData = BitmpUtils.compressBitmapSpecifySize(bitmap, IMAGE_MAX_SIZE);
                if (thumbData.length > IMAGE_MAX_SIZE) {
                    if (mOnShareListener != null) {
                        mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享的縮略圖過大");
                    }
                } else {
                    Bitmap byteToBitmap = BitmpUtils.byteToBitmap(thumbData);
                    if (byteToBitmap != null) {
                        imageObject.setImageObject(bitmap);
                    } else {
                        if (mOnShareListener != null) {
                            mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享的縮略圖異常");
                        }
                    }
                }
            }

            baseMediaObject = imageObject;
        } else if (mShareType == ShareKeeper.TYPE_AVDIO || mShareType == ShareKeeper.TYPE_DEFAULT) {
            WebpageObject webpageObject = new WebpageObject();
            webpageObject.actionUrl = builder.mWebUrl;
            webpageObject.title = builder.mTitle;
            webpageObject.description = builder.mDesc;
            baseMediaObject = webpageObject;
        }

        return baseMediaObject;
    }

    /**
     * 檢測參數(shù)是否可以分享
     *
     * @param mShareType
     * @param baseMediaObject
     * @return
     */
    private static boolean checkShareArgs(int mShareType, BaseMediaObject baseMediaObject) {
        if (mShareType == ShareKeeper.TYPE_TXT) {
            TextObject textObject = (TextObject) baseMediaObject;
            return textObject.checkArgs();
        } else if (mShareType == ShareKeeper.TYPE_PICTURE) {
            ImageObject imageObject = (ImageObject) baseMediaObject;
            return imageObject.checkArgs();
        } else if (mShareType == ShareKeeper.TYPE_AVDIO || mShareType == ShareKeeper.TYPE_DEFAULT) {
            WebpageObject webpageObject = (WebpageObject) baseMediaObject;
            return webpageObject.checkArgs();
        }
        return false;
    }


    /**
     * 判斷 用戶是否安裝微博客戶端
     */
    public static boolean isWeiboClientAvailable(Context context) {
        final PackageManager packageManager = context.getPackageManager();
        List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
        if (pinfo != null) {
            for (int i = 0; i < pinfo.size(); i++) {
                String pn = pinfo.get(i).packageName;
                if (pn.equalsIgnoreCase("com.sina.weibo")) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 獲取分享的handler
     *
     * @return
     */
    public static WbShareHandler getWbShareHandler() {
        return mShareHandler;
    }

    /**
     * 銷毀
     */
    public static void onDestory() {
        if (mShareHandler != null) {
            mShareHandler = null;
        }
    }
}

分享總結(jié)

本文既有原生分享又有第三方分享SDK分享开仰,后續(xù)會把微博分享補(bǔ)上。由于時間匆忙宣渗,也未做過多的測試抖所,如果使用過程中遇到什么問題,請在評論區(qū)留言痕囱。代碼已經(jīng)上傳至GitHub田轧,需要主要替換自己的APPID。
分享的輕量級封裝傳送門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鞍恢,一起剝皮案震驚了整個濱河市傻粘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帮掉,老刑警劉巖弦悉,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蟆炊,居然都是意外死亡稽莉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門涩搓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來污秆,“玉大人劈猪,你說我怎么就攤上這事×计矗” “怎么了战得?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長庸推。 經(jīng)常有香客問我常侦,道長,這世上最難降的妖魔是什么贬媒? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任聋亡,我火速辦了婚禮,結(jié)果婚禮上掖蛤,老公的妹妹穿的比我還像新娘杀捻。我一直安慰自己,他們只是感情好蚓庭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布致讥。 她就那樣靜靜地躺著,像睡著了一般器赞。 火紅的嫁衣襯著肌膚如雪垢袱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天港柜,我揣著相機(jī)與錄音请契,去河邊找鬼。 笑死夏醉,一個胖子當(dāng)著我的面吹牛爽锥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畔柔,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼氯夷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了靶擦?” 一聲冷哼從身側(cè)響起腮考,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎玄捕,沒想到半個月后踩蔚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枚粘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年馅闽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡捞蛋,死狀恐怖孝冒,靈堂內(nèi)的尸體忽然破棺而出柬姚,到底是詐尸還是另有隱情拟杉,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布量承,位于F島的核電站搬设,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏撕捍。R本人自食惡果不足惜拿穴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望忧风。 院中可真熱鬧默色,春花似錦、人聲如沸狮腿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缘厢。三九已至吃度,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贴硫,已是汗流浹背椿每。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留英遭,地道東北人间护。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像挖诸,于是被迫代替她去往敵國和親汁尺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 上大班的外甥和上二年級的外甥女聊天税灌。 外甥:我手讓蚊子咬了均函! 外甥女:天那么冷,哪來的蚊子傲獾印苞也? 外甥:真的有! 外...
    冬之雯語閱讀 386評論 0 7
  • 一直以來粘秆,覺得自己是個孤獨(dú)的人如迟。于是在一個安靜的夜晚,便粗粗的寫了這些…… 內(nèi)心有一些話,想說給你們還有...
    離辰星閱讀 263評論 0 0
  • 本文是參考大神的解決方式殷勘,但是出處暫時找不到了 解決方法就是duration此再,直接傳入sleep,而不是數(shù)字
    夏樹的寶馬閱讀 682評論 0 0