问题描述:
在做微信图片分享的时候,分享图片至微信好友,如果立即选择好友发送的话没有问题。但是在选择好友的页面停留一段时间后再选择朋友发送,选择界面将会闪退。发送对话框仍然会弹出,并且能够发送成功。
正常效果如下:
异常效果:
图片的分享代码如下:
public void share() {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.send_img);
WXImageObject imgObj = new WXImageObject(bmp);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
bmp.recycle();
msg.thumbData = Util.bmpToByteArray(thumbBmp, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("img");
req.message = msg;
req.scene = mTReq(req);
//finish();
}
调试发现如下报错信息:
2022-08-02 19:50:49.626 1320-1338/? E/ActivityTaskManager: Transaction too large, intent: Intent { cmp=com.tencent.mm/.ui.transmit.SendAppMessageWrapperUI (has extras) }, extras size: 417988, icicle size: 0
2022-08-02 19:50:59.628 1320-1338/? W/ActivityTaskManager: Exception when starting activity com.tencent.mm/.ui.transmit.SendAppMessageWrapperUI
android.os.TransactionTooLargeException: data parcel size 427240 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java:527)
at android.app.IApplicationThread$Stub$Proxy.scheduleTransaction(IApplicationThread.java:2591)
at android.app.servertransaction.ClientTransaction.schedule(ClientTransaction.java:135)
at com.android.server.wm.ClientLifecycleManager.scheduleTransaction(ClientLifecycleManager.java:47)
at com.android.server.wm.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1126)
at com.android.server.wm.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1263)
at com.android.server.wm.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:3590)
at com.android.server.wm.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:3024)
at com.android.server.wm.RootActivityContainer.resumeFocusedStacksTopActivities(RootActivityContainer.java:1207)
at com.android.server.wm.RootActivityContainer.resumeFocusedStacksTopActivities(RootActivityContainer.java:1194)
at com.android.server.wm.ActivityStack.completePauseLocked(ActivityStack.java:2230)
at com.android.server.wm.ActivityStack.activityPausedLocked(ActivityStack.java:2157)
at com.android.server.wm.ActivityTaskManagerService.activityPaused(ActivityTaskManagerService.java:2452)
at android.app.IActivityTaskManager$Stub.onTransact(IActivityTaskManager.java:2194)
at android.os.Binder.execTransactInternal(Binder.java:1021)
at android.os.Binder.execTransact(Binder.java:994)
可以发现报了 TransactionTooLargeException 错误。错误日志是 Binder 类出现的,字面意思是数据过大。查看微信的 SDK 源码可以发现实际上调用微信 API,微信会将图片传递给一个新的 Activity。而 Intent传值有大小限制,最大只能512KB !
既然发现了问题,那该如何解决?
既然直接传图片的Bitmap太大,那就把图片先保存在本地,然后直接传递图片的地址。
解决方法:
通过查询微信分享文档可以发现两种分享图片的方式:
WXImageObject (WXMediaMessage.IMediaObject的派生类,用于描述一个图片对象)
| 字段 | 类型 | 含义 | 备注 |
|---|---|---|---|
| imageData | byte[] | 图片的二进制数据 | 内容大小不超过10MB |
| imagePath | String | 图片的本地路径 | 对应图片内容大小不超过10MB |
上述代码采用的是 imageData 直接传递图片的二进制数据。我们改成传递图片本地路劲的方式的话,先要保存图片到本地。 如果分享的消息中涉及文件路径(如图片类型消息),建议开发者针对 Android 7.0 版本及以上设备,判断微信版本支持的情况下,更新为 FileProvider 的方式进行分享。详情查阅《OpenSDK 支持 FileProvider 方式分享文件到微信文档》
保存图片代码:
private static String saveImage(Context context, Bitmap bitmap) {
String storePath = context.getExternalCacheDir() + File.separator + "share";
File appDir = new File(storePath);
// 此处可以考虑每次保存的话将老的文件删除,这样起到删除缓存的作用
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
fileOutputStream.close();
} catch (IOException e) {
}
String path;
if (checkVersionValid(context) && checkAndroidNotBelowN()) {
Uri contentUri = FileProvider.getUriForFile(context,
"com.example.app.fileprovider", // 要与`AndroidManifest.xml`里配置的`authorities`一致,假设你的应用包名为com.example.app
file);
// 授权给微信访问路径
context.grantUriPermission("com.tencent.mm", // 这里填微信包名
contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
path = contentUri.toString(); // contentUri.toString() 即是以"content://"开头的用于共享的路径
} else {
path = file.getAbsolutePath();
}
return path;
}
改良之后的分享图片代码:
public void share() {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.send_img);
WXImageObject imgObj = new WXImageObject();
// 保存图片,返回存储路径
String path = saveImage(context, bmp);
imgObj.setImagePath(path);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
bmp.recycle();
msg.thumbData = Util.bmpToByteArray(thumbBmp, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("img");
req.message = msg;
req.scene = mTargetScene;
api.sendReq(req);
//finish();
}
简单总结下来,就是不使用 WXImageObject 中的 imageData 直接传递图片二进制数据,而是使用 imagePath 传递保存的图片本地路径。