美文网首页
微信图片分享支持url,缩略图支持url

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

作者: tinyvampirepudg | 来源:发表于2020-05-30 11:04 被阅读0次

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

    相关文章

      网友评论

          本文标题:微信图片分享支持url,缩略图支持url

          本文链接:https://www.haomeiwen.com/subject/pasczhtx.html