微信图片分享支持url,缩略图支持url

简介: 在集成微信分享的过程中,如果`缩略图`是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图片压缩

相关文章
|
3月前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
106 4
|
6月前
|
小程序 开发者
【微信小程序-原生开发】实用教程05-首页(含自定义调试模式、插入图片、图文排版、底部留白、添加本地图片)
【微信小程序-原生开发】实用教程05-首页(含自定义调试模式、插入图片、图文排版、底部留白、添加本地图片)
79 0
|
3月前
|
小程序 JavaScript API
微信小程序开发之:保存图片到手机,使用uni-app 开发小程序;还有微信原生保存图片到手机
这篇文章介绍了如何在uni-app和微信小程序中实现将图片保存到用户手机相册的功能。
1361 0
微信小程序开发之:保存图片到手机,使用uni-app 开发小程序;还有微信原生保存图片到手机
|
3月前
|
算法 小程序 Java
java制作海报三:获取微信二维码详情,并改变大小,合成到海报(另一张图片)上
这篇文章介绍了如何使用Java获取微信小程序的二维码,并将其调整大小后合成到海报(另一张图片)上。
64 0
|
4月前
|
数据采集 存储 前端开发
Java爬虫开发:Jsoup库在图片URL提取中的实战应用
Java爬虫开发:Jsoup库在图片URL提取中的实战应用
|
5月前
|
小程序 前端开发
|
6月前
|
小程序 前端开发
【非常全】微信小程序下载图片到相册,微信小程序自动获取分享图片到相册
【非常全】微信小程序下载图片到相册,微信小程序自动获取分享图片到相册
397 3
|
6月前
|
前端开发 小程序
【微信小程序-原生开发】实用教程20 - 生成海报(实战范例为生成活动海报,内含生成指定页面的小程序二维码,保存图片到手机,canvas 系列教程)
【微信小程序-原生开发】实用教程20 - 生成海报(实战范例为生成活动海报,内含生成指定页面的小程序二维码,保存图片到手机,canvas 系列教程)
435 0
|
6月前
|
小程序 JavaScript 前端开发
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
190 0
|
6月前
|
Web App开发 前端开发
canvas保存图片时,谷歌浏览器Chrome报错【解决方案】Not allowed to navigate top frame to data URL
canvas保存图片时,谷歌浏览器Chrome报错【解决方案】Not allowed to navigate top frame to data URL
166 0
下一篇
开通oss服务