微信圖片分享支持url,縮略圖支持url

微信圖片分享支持url,縮略圖支持url

在集成微信分享的過程中,如果縮略圖是url形式,或者大圖分享的圖片是個url,就需要我們先把圖片下載下來,然後依據微信的要求對圖片做一些壓縮操作,最後將圖片的數據設置給要分享的對象即可。

我們一般需要支持的分享類型主要有文字類型(WXTextObject)圖片類型(WXImageObject)網頁類型(WXWebpageObject),具體請看分享與收藏功能-Android開發手冊

縮略圖支持url

拿我們常見的網頁分享舉例,msg.thumbData對應的就是縮略圖對象,具體代碼如下:

//初始化一個WXWebpageObject,填寫url
WXWebpageObject webpage = new WXWebpageObject();
webpage.webpageUrl ="網頁url";

//用 WXWebpageObject 對象初始化一個 WXMediaMessage 對象
WXMediaMessage msg = new WXMediaMessage(webpage);
msg.title ="網頁標題 ";
msg.description ="網頁描述";
Bitmap thumbBmp = BitmapFactory.decodeResource(getResources(), R.drawable.send_music_thumb);
msg.thumbData =Util.bmpToByteArray(thumbBmp, true);

//構造一個Req
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("webpage");
req.message =msg;
req.scene =mTargetScene;
req.userOpenId = getOpenId();

//調用api接口,發送數據到微信
api.sendReq(req);

示意圖如下:

msg.thumbData

我們看下thumbData的定義,如下圖所示:

thumbData的定義

thumbData的類型是字節數組byte[],並且大小不超過32kb

一般情況下,thumbData設置的是應用內置的icon,通過BitmapFactory.decodeResource即可獲取到對應的Bitmap對象,接着對bitmap進行壓縮,最後將Bitmap的對應的字節數組設置給thumbData即可。

如果thumbData的數據來源是url,則我們需要先下載圖片,再進行後續的操作。經過研究,我們可以通過glide提供的api來下載圖片url對應的字節數組,接着將字節數組壓縮到32k以內,最後將壓縮後的字節數組設置給thumbData即可。

1、下載圖片url對應的字節數組
byte[] bytes = Glide.with(context)
        .load(url)
        .asBitmap()
        .toBytes()
        .into(150, 150)
        .get();
2、將字節數組壓縮到32kb以內
/**
 * 將Bitmap的字節流壓縮爲目標大小
 *
 * @param src
 * @param targetSize 單位B
 * @return
 */
private static byte[] compressBitmapBytes2TargetSize(byte[] src, int targetSize) {
    // 將字節數據轉換成臨時bitmap對象,爲壓縮做準備
    Bitmap bmp = BitmapFactory.decodeByteArray(src, 0, src.length);
    byte[] result = getBytesFromCompressBitmap(bmp, targetSize);
    // 回收不用的Bitmap
    if (!bmp.isRecycled()) {
        bmp.recycle();
    }
    return result;
}

/**
 * 壓縮bitmap的字節數據,quality每次減少5
 * @param bitmap
 * @param targetSize
 * @return
 */
private static byte[] getBytesFromCompressBitmap(Bitmap bitmap, int targetSize) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // 默認quality爲100,quality取值範圍[0, 100]
    int quality = 100;
    bitmap.compress(Bitmap.CompressFormat.PNG, quality, baos);
    byte[] bytes = baos.toByteArray();
    while (bytes.length > targetSize && quality >= 5) {
        quality -= 5;
        if (quality < 0) {
            quality = 0;
        }
        // 重置,不然會累加
        baos.reset();
        // 將數據寫入ByteArrayOutputStream對象中
        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        // 將流轉換成字節數組
        bytes = baos.toByteArray();
    }
    // 關閉流
    try {
        baos.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return bytes;
}

具體調用:

// 略縮圖byte[]小於32k
msg.thumbData = compressBitmapBytes2TargetSize(bytes, 32 * 1024);
3、異步處理下載過程

由於下載url的字節數據這個操作是io操作,所以我們需要放到子線程中來完成,下載完成後再在主線程中進行處理即可。完整版代碼如下:

Observable.create(new ObservableOnSubscribe<byte[]>() {
    @Override
    public void subscribe(ObservableEmitter<byte[]> emitter) throws Exception {
        try {
            byte[] bytes = Glide.with(context)
                    .load(url)
                    .asBitmap()
                    .toBytes()
                    .into(150, 150)
                    .get();
            emitter.onNext(bytes);
            emitter.onComplete();
        } catch (Exception e) {
            e.printStackTrace();
            emitter.onError(new Throwable("下載略縮圖失敗"));
        }
    }
})
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<byte[]>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(byte[] bytes) {
                if (bytes != null) {
                    // 略縮圖byte[]小於32k
                    msg.thumbData = compressBitmapBytes2TargetSize(bytes, 32 * 1024);
                } else {
                    // 設置默認的縮略圖,這裏一般使用應用logo
                }
                // 發送分享請求
            }

            @Override
            public void onError(Throwable e) {
                // 設置默認的縮略圖,這裏一般使用應用logo
                // 發送分享請求
            }

            @Override
            public void onComplete() {
            }
        });

這裏使用了RxJava做的切換線程的操作。當然了,這裏的壓縮bitmap數據也屬於io操作,也應該放在子線程中完成,這個細節有待完善。

大圖分享支持url

與縮略圖的處理方式不同,縮略圖我們是知道最終要顯示的大小的(150,來自微信官方demo),所以我們直接通過下載byte[]進行後續即可。而我們這裏要分享的大圖的大小和寬高等信息都是未知的,在下載完成之前我們無法通過url獲取更多信息,所以我們還是需要先將圖片下載下來。

由於下載byte[]的api必須指定寬高,所以我們換另一個不需要指定寬高的api,直接下載bitmap對象,具體代碼如下:

Glide.with(mContext)
    .load(url)
    .asBitmap()
    .into(new SimpleTarget<Bitmap>() {
        @Override
        public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
            // bitmap下載完成
        }
    });

我們再看下微信提供的分享圖片的api,它支持圖片的字節數組圖片的本地路徑兩種方式,具體的大小都不能超過10M。

在這裏插入圖片描述

如果我們使用字節數組這種方式來實現,即使我們的圖片小於10M,或者我們把bitmap對應的字節數組壓縮到10M以下了,依然會遇到分享不成功的問題。失敗的主要原因是因爲Intent傳值有大小限制,最大隻能512KB,給微信發送分享數據,最終還是通過Binder傳遞的,Binder傳遞的數據大小很有限,這一步還是行不通。另外,如果圖片比較大,對應的bitmap對象也很大,進行壓縮等操作會極其耗時,影響用戶體驗。

這裏選擇使用圖片的本地路徑這種方式來實現,先將圖片下載到本地的bitmap對象,然後將bitmap存儲到手機上,將對應的存儲路徑設置給imagePath參數即可。

具體代碼如下:

Observable.create(new ObservableOnSubscribe<Bitmap>() {
    @Override
    public void subscribe(final ObservableEmitter<Bitmap> emitter) throws Exception {
        Glide.with(mContext)
                .load(url)
                .asBitmap()
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                        emitter.onNext(resource);
                        emitter.onComplete();
                    }
                });
    }
}).subscribeOn(AndroidSchedulers.mainThread())
        .observeOn(Schedulers.io())
        .map(new Function<Bitmap, BitmapAndFilePathBean>() {
            @Override
            public BitmapAndFilePathBean apply(Bitmap bitmap) throws Exception {
                String filePath = "";
                if (bitmap != null) {
                    // 將圖片存儲到手機,返回決定路徑
                }
                BitmapAndFilePathBean bitmapAndFilePathBean = new BitmapAndFilePathBean(bitmap, filePath);
                return bitmapAndFilePathBean;
            }
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<BitmapAndFilePathBean>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(BitmapAndFilePathBean bitmapAndFilePathBean) {
                WXImageObject imgObj = new WXImageObject();
                //設置大圖
                imgObj.setImagePath(bitmapAndFilePathBean.getFilePath());
                WXMediaMessage msg = new WXMediaMessage();
                msg.mediaObject = imgObj;
                // 設置縮略圖
                Bitmap thumbBmp = Bitmap.createScaledBitmap(bitmapAndFilePathBean.getBitmap(), 150, 150, true);
                msg.thumbData = ImageUtil.bitmapToByteArray(thumbBmp, true);
                // 發送分享請求
            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onComplete() {
            }
        });

這裏的BitmapAndFilePathBean對象其實是Bitmap對象和filePath的包裝類,具體如下:

public class BitmapAndFilePathBean extends BaseBean {
    private Bitmap bitmap;
    private String filePath;

    public BitmapAndFilePathBean(Bitmap bitmap, String filePath) {
        this.bitmap = bitmap;
        this.filePath = filePath;
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
}

當然了,保存圖片到手機是需要文件讀寫權限的,需要做好動態權限申請和校驗。

關於微信分享中使用url設置圖片的問題,這裏提供了一個解決思路,同學們如果有更好的方式,歡迎溝通。

參考

Android 使用Glide下載圖片的幾種方式

Glide坑遇記:寬度鋪滿高度自適應 & GIF加載之坑

微信分享大圖遇到的問題(Android)

bitmap的六種壓縮方式,Android圖片壓縮

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