一、现象:‘微信小程序卡片分享’,部分手机分享失败
1.问题详细报错日志:checkArgs fail, thumbData should not be null or exceed 128kb
问题:参数错误,thumbData 不能为空或者不能大于128kb
2.解决办法
压缩Bitmap
方法:bmpToByteArrayBySize
参数:1.需要压缩的Bitmap;2.不能超过的大小,单位是kb;3.图片是否带有透明度
返回类型:ByteArray
代码如下:
private fun bmpToByteArrayBySize(
bmp: Bitmap,
maxSize: Int,
isWithAlpha: Boolean = false
): ByteArray? {
val byteArrayOutputStream = ByteArrayOutputStream()
//压缩的格式(如果被压缩的图片带有透明度需要选择PNG)
var compressFormat = Bitmap.CompressFormat.JPEG
if (isWithAlpha) {
compressFormat = Bitmap.CompressFormat.PNG
}
//压缩的质量(压缩质量范围0-100,值越大,质量越好,对于 PNG 和 WEBP 格式,此参数不起作用,可以设置为 0)
var compressQuality = 100
//将位图压缩为指定格式
bmp.compress(compressFormat, compressQuality, byteArrayOutputStream)
//判断压缩后的输出流是否符合指定的条件
while ((byteArrayOutputStream.size() / 1024) > maxSize) {
compressQuality -= 10
if (compressQuality <= 0) {
break
}
byteArrayOutputStream.reset()
bmp.compress(compressFormat, compressQuality, byteArrayOutputStream)
}
return byteArrayOutputStream.toByteArray()
}
分享小程序卡片方法调用,代码如下:
fun shareWXSmallProject(context: Context,miniProgramUserName: String,path: String){
val api = WXAPIFactory.createWXAPI(context, WX_ID)
if (!api.isWXAppInstalled && !AppKit.isAvailable(ScaffoldConfig.getApplication(), "com.tencent.mm")) {
shareTo(ShareMedia.SHARE_WX)
}else{
val miniProgramObj = WXMiniProgramObject()
miniProgramObj.webpageUrl = "http://www.qq.com" // 兼容低版本的网页链接
miniProgramObj.miniprogramType =
WXMiniProgramObject.MINIPTOGRAM_TYPE_RELEASE // 正式版:0,测试版:1,体验版:2
miniProgramObj.userName = miniProgramUserName // 小程序原始id
miniProgramObj.path = path //小程序页面路径;对于小游戏,可以只传入 query 部分,来实现传参效果,如:传入 "?foo=bar"
val msg = WXMediaMessage(miniProgramObj)
msg.title = getString(R.string.mini_program_title) // 小程序消息title
msg.description = getString(R.string.mini_program_des) // 小程序消息desc
val bmp = BitmapFactory.decodeResource(resources, R.mipmap.mini_program_share)
val thumb = bmpToByteArrayBySize(bmp,128)
msg.thumbData = thumb // 小程序消息封面图片,小于128k
val req = SendMessageToWX.Req()
req.transaction = buildTransaction("miniProgram")
req.message = msg
req.scene = SendMessageToWX.Req.WXSceneSession // 目前只支持会话
api.sendReq(req)
}
}
二、解决思路
1.问题的发现
开发好分享小程序卡片功能后,使用手头上测试机进行测试,发现这个报错提示图片过大,第一反应先去看资源文件大小65kb,这时候就想着图片是符合小于128kb这个要求的,怎么还有这个报错,对比其他资源文件,发现这张图片和其他资源文件的图片位数显示不一样,想着可能是对图片还有其他要求只是文档没有写出来,就去找设计师再要一张和其他资源文件一样位数的图片,后面设计师给我的图片大小24kb,我发现我手头的测试机可以了,我就想过真是图片位数问题,这文档没写清楚。
到这里我完全没有意识到其实是图片变小了,我的测试机才可以正常使用这个功能
后面,再用手头上有的测试机测试都通过,就想着这个功能没有问题了,结果有一部手机,点击微信没有反应,报错和之前的是一样的,因为只有一部手机出现这个报错,我就没有头绪了,我想着难道这个手机没有办法使用这张图片吗?微信没有做好兼容?我尝试随便换一张资源图片试试,看是不是图片原因。在这个时候我没有去思考这个报错日志,明明日志上写了 图片不符合要求,超过128kb,我却没有往这一方面思考。
2.造成以上奇怪思路的原因
1.对于资源文件生成Bitmap的原理不了解
val bmp = BitmapFactory.decodeResource(resources, R.mipmap.mini_program_share)
BitmapFactory.decodeResource() 方法用于从资源中解码位图。
资源文件的大小和解码后的位图大小会存在不同,因为解码过程中会将资源文件解压缩并还原为位图对象,这是为了方便在内存进行操作和显示。所以解码后的位图会受到尺寸,颜色,屏幕像素的影响。
这就是为什么会有部分手机出现无法分享的问题,因为在内存中位图大小大于128kb;不同手机分辨率不一样,屏幕像素不一样,生成的位图就不一样。
2.对于方法调用参数不理解
bmp.compress(compressFormat, compressQuality, byteArrayOutputStream)
参数一:要使用的压缩格式
Bitmap.CompressFormat 枚举类型。可以选择以下三种格式之一:
Bitmap.CompressFormat.JPEG:将位图压缩为 JPEG 格式。
Bitmap.CompressFormat.PNG:将位图压缩为 PNG 格式。
Bitmap.CompressFormat.WEBP:将位图压缩为 WEBP 格式。
参数二:压缩质量,取值范围为 0 到 100。对于 JPEG 格式,较高的值表示较高的质量但文件较大;对于 PNG 格式和 WEBP 格式,此参数不起作用,可以设置为 0。
参数三:输出流,通常使用 ByteArrayOutputStream 来存储压缩后的数据。
其实发现报错提示说大于 128kb时,有使用压缩方法进行压缩图片的,但是发现调用压缩方法了也没有任何作用,所以没有继续往图片压缩方向上思考
当时使用压缩方法是从网上复制过来的,完全没有思考这个压缩方法的原理以及方法参数,所以造成了没有头绪的现象。如果当时从网上复制过来的压缩方式,进行参数了解,很快问题就会解决了。
三、总结
对于使用过的代码,特别是复制过来的代码,一定要去了解清楚原理,这不至于本来是一个可以解决问题的方式,因为自己使用不对导致错过了这个解决方法;使用的代码,发现用的是自己不熟悉的知识点,需要去了解一下原理,就像那个Bitmap的生成,如果我之前知道位图和资源文件大小的存储方式以及原理,我就会马上意识到,确实会出现大于128kb的情况,这样也不至于让设计师一直无厘头的改图片
四、知识扩展
1.资源文件的大小和解码后的位图大小可能不一样的原因是因为它们表示不同的概念。
资源文件的大小:资源文件的大小是指在磁盘上存储的文件大小。它表示了资源文件(例如图片文件)在文件系统中所占用的字节数。资源文件的大小通常是根据文件的压缩格式和图像内容的复杂程度来确定的。例如,一个
PNG 格式的资源文件可能会比对应的 JPEG 格式文件大,因为 PNG 使用无损压缩算法,而 JPEG 使用有损压缩算法。解码后的位图大小:解码后的位图大小是指位图对象在内存中所占用的空间大小。它表示位图在内存中存储的像素数据所占用的字节数。位图的大小取决于像素的宽度、高度以及每个像素的颜色深度。例如,一个
100x100 像素的 RGB 24 位色深度的位图将占用 100x100x3 = 30,000 个字节的内存空间。
2.Bitmap.CompressFormat.JPEG
、Bitmap.CompressFormat.PNG
和 Bitmap.CompressFormat.WEBP
是三种不同的位图压缩格式。它们具有不同的特点和适用场景。
JPEG(Joint Photographic Experts Group):
- 压缩算法:JPEG 使用有损压缩算法,通过去除图像中的细节和冗余信息来减小文件大小。
- 压缩质量:
compressQuality
参数在 JPEG 压缩中起作用,值越高表示较高的质量但文件大小也越大。- 支持颜色深度:JPEG 支持 24 位真彩色(RGB)图像,以及灰度图像。
- 适用场景:JPEG 格式适用于存储照片和图像,尤其是对颜色细节要求不高但需要较小文件大小的情况。
PNG(Portable Network Graphics):
- 压缩算法:PNG 使用无损压缩算法,保留图像的所有细节和信息。
- 压缩质量:
compressQuality
参数在 PNG 压缩中没有实际作用,可以设置为 0。- 支持颜色深度:PNG 支持 8 位索引色、24 位真彩色(RGB)和 32 位带透明度的图像。
- 适用场景:PNG 格式适用于需要保留图像细节、支持透明度,并且对文件大小相对较小的情况,如图标、透明背景图像等。
WEBP:
- 压缩算法:WEBP 是一种支持有损和无损压缩的图像格式,具有较好的压缩性能。
- 压缩质量:
compressQuality
参数在 WEBP 压缩中起作用,值越高表示较高的质量但文件大小也越大。- 支持颜色深度:WEBP 支持 24 位真彩色(RGB),以及带透明度的图像。
- 适用场景:WEBP 格式适用于在网络上传输图像,可以在保持较小文件大小的同时提供较好的图像质量。
选择压缩格式应根据具体需求和使用场景来决定。JPEG 适用于照片和彩色图像,PNG 适用于需要保留细节和透明度的图像,而 WEBP则是一种综合性能较好的格式,适用于网络传输和图像展示。
3.Bitmap.Config 枚举类型可用于创建位图
Bitmap.Config.ALPHA_8: 此配置适用于只需存储图像的透明度信息而不需要颜色信息的情况。每个像素使用 8位表示透明度,不存储颜色信息。
Bitmap.Config.ARGB_4444: 此配置适用于需要存储透明度和颜色信息的情况。每个像素使用 4 位表示透明度和 4位表示红、绿、蓝色的分量。
Bitmap.Config.ARGB_8888: 这是最常用的配置,适用于需要存储透明度和高质量颜色信息的情况。每个像素使用 8位表示透明度,8 位表示红色分量,8 位表示绿色分量,8 位表示蓝色分量。
Bitmap.Config.RGB_565: 此配置适用于需要存储颜色信息但不需要透明度的情况。每个像素使用 5 位表示红色分量,6 位表示绿色分量,5 位表示蓝色分量。