微信图片分享支持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);

示意图如下:

微信图片分享支持url,缩略图支持url_第1张图片

我们看下thumbData的定义,如下图所示:

微信图片分享支持url,缩略图支持url_第2张图片

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() {
    @Override
    public void subscribe(ObservableEmitter 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() {
            @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() {
        @Override
        public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
            // bitmap下载完成
        }
    });

我们再看下微信提供的分享图片的api,它支持图片的字节数组图片的本地路径两种方式,具体的大小都不能超过10M。

微信图片分享支持url,缩略图支持url_第3张图片

如果我们使用字节数组这种方式来实现,即使我们的图片小于10M,或者我们把bitmap对应的字节数组压缩到10M以下了,依然会遇到分享不成功的问题。失败的主要原因是因为Intent传值有大小限制,最大只能512KB,给微信发送分享数据,最终还是通过Binder传递的,Binder传递的数据大小很有限,这一步还是行不通。另外,如果图片比较大,对应的bitmap对象也很大,进行压缩等操作会极其耗时,影响用户体验。

这里选择使用图片的本地路径这种方式来实现,先将图片下载到本地的bitmap对象,然后将bitmap存储到手机上,将对应的存储路径设置给imagePath参数即可。

具体代码如下:

Observable.create(new ObservableOnSubscribe() {
    @Override
    public void subscribe(final ObservableEmitter emitter) throws Exception {
        Glide.with(mContext)
                .load(url)
                .asBitmap()
                .into(new SimpleTarget() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
                        emitter.onNext(resource);
                        emitter.onComplete();
                    }
                });
    }
}).subscribeOn(AndroidSchedulers.mainThread())
        .observeOn(Schedulers.io())
        .map(new Function() {
            @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() {
            @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图片压缩

你可能感兴趣的:(Android,微信分享)