Android 輕量級分享封裝 前言 屬性介紹 微信分享 QQ分享 原生分享 微博分享 分享總結

前言

提到分享,幾乎所有應用都會有的功能,雖然說不是難點,但是還是要有。最近公司也在做分享功能,以前也做過很多次分享,基本都是集成第三方分享SDK,然後按照開發文檔步驟完成。隔一段時間就會忘記來龍去脈,再次做分享,還要去查看官方文檔。因此,本次準備花點時間封裝第三方分享SDK,這樣做的好處是方便以後使用,另一方面也可以自己學習到一些新的東西。分享有兩種方式,一種是第三方分享SDK,第二種是隱士跳轉方式,用於隱士跳轉方式有某些侷限,一方面是QQ空間分享不對外開放,另一方面是第三方分享SDK額分享監聽做的比較全面,不需要再次自己去封裝。因此本文主要介紹關於第三方分享SDK的封裝,,後面也會把原生的封裝帶上。本文同樣採用建造者模式創建,結構簡單清晰,本文省略申請賬號過程。基本使用如下:

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

屬性介紹

可能看到上面的使用可能會覺得那麼多屬性,肯定很複雜,其實不然。上面舉例是把所有的屬性都列舉出來了,但是實際用不到那麼多屬性。下面就來介紹所有的屬性。

builder(this) :構建建造者模式
setPlatform(): 設置分享平臺,例如:QQ、微信、QQ空間等 (可以不填,默認QQ分享)
setShareType():設置分享的類型,根據形式分爲,圖文、純圖片、音視頻、純文本(此分類不已第三方分享SDK分類),可以不設置,默認爲圖文類型
setTitle(title):設置標題,可以不設置(內部已經做了防止空指針,但是建議設置,或者設置appname亦可)
setDesc(desc):設置簡介,設置同上
setImageUrl(imageUrl):設置網絡圖片路徑
.setImagePath(localPicPath):設置本地圖片路徑
setAVdioUrl(videoUrl):設置網絡音視頻鏈接
setAVdioPath(localVideoPath):設置本地音視頻地址
setWebUrl(webUrl):設置分享的鏈接(除了分享圖片之外,都是必備的屬性)
setOnShareListener(this):設置分享監聽回調(建議回調)

微信分享

檢測客戶端
/**
     * 手機是否安裝微信客戶端
     *
     * @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內部做了分享的封裝類,包括文本、圖片、視頻等
WXMediaMessage :攜帶IMediaObject 以及標題、描述、縮略圖信息
msg.title :標題
msg.description :描述
msg.thumbData :縮略數據(圖片內容)
SendMessageToWX.Req:攜帶WXMediaMessage 和分享數據
transaction    :分享攜帶數據,相當於類型,回調到WXEntryActivity爲BaseResp resp中的參數,可以做過濾作用
message :攜帶WXMediaMessage 
scene :場景,即分享平臺
創建不同的類型

由於微信分享和朋友圈分享沒有區別,所以在一起統一封裝如下:

/**
     * 創建分享的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封裝了微信分享不同,所以在此根據分享類型創建不同的IMediaObject,有些必不可缺的屬性都做了分享回調失敗,當然也可以做拋異常的形式(不建議,程序會崩潰)。

微信分享
/**
     * 執行
     *
     * @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) {
            //檢測參數可以分享
            boolean checkArgs = iMediaObject.checkArgs();
            if (checkArgs) {
                //共同的部分
                WXMediaMessage msg = new WXMediaMessage(iMediaObject);
                msg.title = builder.mTitle;//標題
                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;//縮略數據(圖片內容)
                }
                //共同的部分
                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;
                //攜帶監聽
                Bundle bundle = new Bundle();
                bundle.putSerializable("builder", builder);
                req.toBundle(bundle);
                iwxapi.sendReq(req);
            } else {
                if (mOnShareListener != null) {
                    mOnShareListener.onShareFailed(builder.mPlatform, "分享參數異常");
                }
            }
        }
    }

說明:1、boolean checkArgs = iMediaObject.checkArgs(),微信分享SDK內部檢測參數,判斷參數是否正確
2、byte[] thumbData = BitmpUtils.compressToBitmapLast(bitmap, IMAGE_MAX_SIZE)爲縮略圖,除了分享圖片 必備之外,其他情況都可以沒有。

壓縮圖片

關於微信分享最容易出錯的就是分享的圖片過大,微信規定分享的縮略圖大小不能超過32768K,所以分享之前必須做壓縮處理,本文主要採用先質量壓縮至10%,如果還超過規定分享縮略圖大小再採取尺寸壓縮,如果尺寸壓縮之後依舊不行,可以採用第三方壓縮工具或者替換圖片。

 /**
     * 圖片壓縮到指定大小
     *
     * @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%,把壓縮後的數據存放到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) {
        //繼續在當前的質量下壓縮
        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%,把壓縮後的數據存放到baos中
            options--;
        }

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

微信分享結果處理

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

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, "發送失敗");
                } else if (errCode == BaseResp.ErrCode.ERR_AUTH_DENIED) {
                    onShareListener.onShareFailed(shareBuilder.mPlatform, "認證被否決");
                } 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, "未知錯誤");
                }
            }
        }

說明:關於微信分享結果需要注意一點,由於微信分享SDK升級,分享取消和分享成功都會返回分享成功。
新版微信分享取消與成功合併

QQ分享

檢測QQ客戶端
/**
     * 手機是否安裝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:分享標題(默認不可以爲空,內部做了防止空指針)
QQShare.SHARE_TO_QQ_SUMMARY:分享簡介(設置同上)
QQShare.SHARE_TO_QQ_TARGET_URL:weburl(除了分享圖片以外必須參數)
QQShare.SHARE_TO_QQ_IMAGE_URL:網絡圖片(縮略圖,但不是單純分享圖片的地址,沒有也不影響)
QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL:本地圖片路徑(單純的本地圖片,必要參數,一定要本地路徑)
QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN):分享qq空間特有(權限)

注意:1、qq空間的屬性需要把QQ替換成QZONE
2、網絡圖片鏈接在qq分享和qq空間分享的數據裝載形式不一樣,qq分享直接存在Bundle中,qq空間在先存放在集合中,然後添加集合方式,具體看下面代碼。

QQ分享

由於QQ不能單獨分享文本,因此需要單獨處理,另外QQ空間不對外開放且QQ空間不能單獨分享圖片和視頻,因此QQ空間分享只做默認的圖文分享。因此下面僅介紹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默認只支持本地圖片路徑分享,因此如果是網絡圖片,需要先下載到本地然後再去分享,本地圖片分享跟其他分享區別不大,只有一點就是純圖片分享,圖片不能爲空,但是鏈接是唯一可以爲空的類型,因此這裏主要講解網絡圖片的分享。

/**
     * 分享網絡圖片
     * 需要先下載到本地
     * 然後設置到本地路徑去分享
     *
     * @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分享網絡圖片
                    final String saveBitmapToLocal = BitmpUtils.saveBitmapToLocal(activity, urlBitmap);
                    builder.setImagePath(saveBitmapToLocal);
                    //最後轉爲本地分享
                    performShareLocalPic(activity, mTencent, builder);
                } catch (IOException e) {
                    e.printStackTrace();
                    if (mOnShareListener != null) {
                        mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享異常:" + e.getMessage());
                    }
                }
            }
        }.start();
    }

音視頻分享

QQ分享SDK是支持音視頻分享的,不過是分享的鏈接,因此如果要分享本地音視頻,要特殊處理。因此此處單獨做QQ本地音視頻的分享講解。此處採用系統的分享方式,通過隱士跳轉分享。

 /**
     * 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);
    }
其他類型分享
/**
     * 分享網頁  默認類型
     *
     * @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);//默認分享類型
        params.putString(QQShare.SHARE_TO_QQ_TITLE, builder.mTitle + "");//分享標題(默認不可以爲空,防止空指針)
        params.putString(QQShare.SHARE_TO_QQ_SUMMARY, builder.mDesc + "");//分享簡介(默認可以爲空防止空指針)
        params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, builder.mWebUrl);//weburl(除了圖片以外都需要)
        params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, builder.mImageUrl);//網絡圖片(縮略圖,沒有也不影響)
        params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, builder.mImagePath);//本地圖片路徑(單純的本地圖片分享使用)
        //創建監聽器
        mQQShareListener = new QQShareListener(builder);
        mTencent.shareToQQ(activity, params, mQQShareListener);
    }

說明:
1、由於文本分享沒用SDK,所以監聽只以跳轉成功爲分享成功,無取消分享監聽
2、QQ空間無法進行圖片分享(建議QQ空間只做圖文分享)
3、QQ分享如果單獨分享圖片,只能分享本地圖片
4、由於SDK做了判斷,因此performShare()不再做一些基本的參數判斷

QQ分享結果處理

QQ分享一定要處理當前activity的onActivityResult(),否則無法監聽到QQ內部的分享回調。

/**
     * 處理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);
                }
            }
        }
    }

原生分享

利用原生的分享也是可以的,但是無法監聽分享的結果,暫且以跳轉到目標頁面爲分享成功,異常情況爲分享失敗。

原生分享文本
/**
     * 分享文本
     *
     * @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異常!");
            }
        }
    }
原生分享圖片

原生分享還是分享本地圖片,網絡圖片要下載到本地再做分享。

/**
     * 原生本地圖片分享
     *
     * @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異常!");
            }
        }
    }

微博分享

微博分享跟微信分享是非常相似的,所以很多細節,具體細節可以參考代碼。

檢測微博客戶端
/**
     * 判斷 用戶是否安裝微博客戶端
     */
    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;
    }

檢測參數是否異常

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

 /**
     * 檢測參數是否可以分享
     *
     * @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、結果回調需要用到當前分享activity的onNewIntent(Intent intent)方法

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

wbShareHandler.doResultIntent即是微博分享的回調,處理如下:

/**
     * 處理微博的分享監聽
     *
     * @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內部需要加載libweibosdkcore.so的文件,原因可以參考 Android7.x找不到libsqlite.so 問題,項目中已經添加,具體請參考代碼

微博分享完整
public class WBShareTask {


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

    /**
     * 子線程中執行操作
     *
     * @param activity
     * @param builder
     */
    public static void executeShare(Activity activity, final ShareKeeper.Builder builder) {
        boolean weiboClientAvailable = isWeiboClientAvailable(activity);
        OnShareListener mOnShareListener = builder.mOnShareListener;
        //監測是否有客戶端
        if (!weiboClientAvailable) {
            mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "監測不到客戶端");
        } 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;
            //根據有沒有圖片分爲三種情況
            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) {
            //檢測參數可以分享
            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, "分享參數異常");
                }
            }
        }
    }


    /**
     * 創建不同的 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;
    }

    /**
     * 檢測參數是否可以分享
     *
     * @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;
        }
    }
}

分享總結

本文既有原生分享又有第三方分享SDK分享,後續會把微博分享補上。由於時間匆忙,也未做過多的測試,如果使用過程中遇到什麼問題,請在評論區留言。代碼已經上傳至GitHub,需要主要替換自己的APPID。
分享的輕量級封裝傳送門

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章