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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343