微信圖片分享支持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);
示意圖如下:
我們看下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設置圖片的問題,這裏提供了一個解決思路,同學們如果有更好的方式,歡迎溝通。