@weakify(self); _homeParamsEntity.shareImagesWXBlock = ^(AWShareImagesEntiy *shareImagesEntiy) { @strongify(self); if(isEmptyArray(shareImagesEntiy.activityItems) || isEmptyArray(shareImagesEntiy.excludedActivityTypes)) { return ; } UIActivityViewController *activityVC = [[UIActivityViewController alloc]initWithActivityItems:shareImagesEntiy.activityItems applicationActivities:nil]; activityVC.excludedActivityTypes = shareImagesEntiy.excludedActivityTypes; [self presentViewController:activityVC animated:NO completion:nil]; activityVC.completionWithItemsHandler = ^(UIActivityType __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError){ NSLog(@"%@ ---- %@", activityType, returnedItems); UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; pasteboard.string = @""; }; };
这个代码片段就能实现多图片分享,设置自定义UIActivityType类型(@”com.apple.mobilenotes.SharingExtension”,@”com.apple.mobileslideshow.StreamShareService”,@”com.apple.CloudDocsUI.AddToiCloudDrive”),来让微信排在第一位。
如何获取到ActivityItems是最关键,excludedActivityTypes能排除不需要分享的应用图标在分享应用选择列表中,它结合前者共同实现把微信应用图标放在前面。UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.string = @”“;是清除粘贴板的内容。
最近我接到一个分享多个图片到微信和微信朋友圈的需求,而单图片分享我们是使用的友盟的图片分享,然而它没有提供多图片分享功能。只好去请教度娘,度娘告诉我可以使用UIActivityViewController实现系统自带的图片分享,也就是把图片下载下来,组成UIImage大军,生成UIActivityViewController对象设置ActivityItems和excludedActivityTypes,presentViewController下就实现多图片分享了,剩下的就交给操作系统它老人家了。然而理想是丰满的,现实是残酷的。我这样简单对待人家,就是测试小妹疯狂的bug,一遍说着这是系统它老人家的错来帅锅,一遍旁敲侧击的影响它老人家,让它不乱来,一边定位问题的根源,一边和别的应用比较。找到问题后再和服务端,产品提需求,提改进方案。最后终于制服它老人家了。咱们看看我遇到那些麻烦问题:
第一个问题:部分商品能分享多图片,部分商品分享多图片,应用卡死,系统分享应用选择组件出不来。也是醉了,功能性问题。没有办法甩锅了,自言自语吧!
第二个问题:分享是下载九张图片过慢,都5秒钟了,让人刚觉好像没有点到分享按钮,拼命在狂点击分享按钮。太不友好了吧!
第三个问题:分享时,九张图片出来了,系统分享应用选择组件也出来了,点击微信图标时,唤起微信分享选择页面很慢。
第四个问题:其它手机分享多图片正常,其中一个测试机,多图片分享时提示无法分享到微信,由于应用BundleID信息校验不通过,无法分享到微信。
第五个问题:多图片分享时,显示系统分享应用选择组件中微信不在第一个位置(点击更多,显示的活动只打开微信的情况下)。
我开始上马解决这一切的一切障碍,中间前前后后经历里很久,探索了很多方案,最终才找到了根源。像这样带有研究性质的新技术最好别完全列入开发计划中,适合当前期研究和后期的bug处理。因为这样的问题解决有和多不确定性,时间不可控,有时候问题真相离你只隔一层窗户纸,但是你可能永远找不到真相,也可能你通过很多尝试才找到根源。也可能你找不到根源,通过其它方式避免了这些问题。在开发进度严格控制下,没有那么多时间给你搞清本源,有很多不知道问题所在也能解决问题,不能太较真,当然找到本源最好。很多文章大家抄来抄去,不一定几个人搞清楚问题的根本在哪里,有的甚至按下了葫芦起了瓢(那个HybridNSURLProtocol的https协议拦截导致post请求参数被清空,有的人抄时连这个问题都不知道,何谈最终解决问题),有的是方案不完美,解决大部分情况下的问题,但是少部分还是有问题,这样的方案,当你没有更好的解决方案可以采纳。但是大家抄来抄去,让人感觉是完美方案了,实际上不完美的解决方案就是不完美的解决方案。虽然有人说不能让因为百分之九十九人迁就百分之一的人需求在紧急开发情况下可以采用,但是在时间充足后期完善产品是为何不尽量在满足那百分之九十九的人情况下,为那百分之一的人考虑呢?这就是紧急情况下的临时方案和最终妥协方案的区别。如个人热点分享导致蓝色状态栏下压问题,多少人抄那两篇文章,但是能满足所有情况吗?在特殊情况下还不是出现状态栏为黑色的一条问题吗?我们永远在追求完美的路上,而不是达到了完美,千万别被抄袭文章误导了大家,尽量追求问题的本质来达到该问题的完美解决。废话不多说了,来点正点的。
第一个问题,从分享多图片的代码来看,我们只给它传递了含有图片对象数组的ActivityItems,怎么看都是系统的错。想想系统确实有错,你吃不了这些数据给和错误信息啊?你就是这样装死,我们多伤心。既然惹不起系统,咱们就找咱们传递的数据是否有问题。一个一个下载这些有问题的图片,发现有的图片下载很慢,图片很大(有两兆以上的图片)。开始怀疑是图片大小问题,虽然测试说我用微信分享一个很大的图片也没有问题呀!服务器开发人员说我已经对图片压缩了。既然没有思路,本着不错过不放过的原则。为了尽量保持图片质量,我二分法通过修改UIImageJPEGRepresentation的参数循环压缩图片到指定大小及以下,开始把最大尺寸设置为512k。经过不断的完善,终于实现了我的想法。去测试和观察压缩的图片,发现由于循环压缩很费时间,结果正常的商品分享也慢了许多。看来路走错了。虽然路走错了,但是发现一个新问题,有的问题的图片把UIImageJPEGRepresentation的图片质量参数设置为0.0001了图片还是达不到512K。找到这些图片,把她们的地址从分享图片数组里移除,让后分享该产品就正常了。找运营,运营说你不可能让商家把它辛苦ps的商品图片不用啊,也没有统一的规范啊!然后是一堆的……。看来还是要自己解决啊!我研究了几天,点击那个图片时发现那个图片的属性有所不同,其它正常图片尺寸都很小,那几张图片的却很大达到6000*4000,这个尺寸虽然相对于单反来说可以轻松达到,但是比最大的iphone x的1242*2208ps像素大了几倍。我怀疑时图片尺寸太大,超过苹果手机的可兼容尺寸引起的。马上进行尺寸压缩(参照《图像的压缩算法–尺寸压缩、格式压缩和品质压缩》),立即测试,发现问题被ko了。这个问题可参考《超大尺寸的图片无法使用UIActivityViewController分享问题》。
至于第二个问题,这个下载很慢,研究的结果是,我们下载阿里云的图片时,我们对下载的图片进行了压缩,当图片比较大时,当然就就比较慢了。我们的网页,微信,app,app分享都用的同一张图片,图片上传是虽然也进行了压缩,对图像的尺寸没有限制。现在现网有大量各式各样的图片,对他们整改代价也太大了,所以就在图片下载出口进行了重新压缩,压缩到大图片是很费时的。最好的方式是在上传时对图片进行规范化限制,对部分图片进行不同的应用用不同的图片,而不是所有的应用用同一张图拼啊,特别把待分享的图片设置为单独的图片。这个就该产品从早期在设计上避免这种情况。但是理想是丰满的,现实是骨感,谁有时间做啊!我们改变不别人,那么我们就改变自己。我们在分享多图片,下载图片时现实下载进度条。虽然奇茇,但是确实对用户体验有提高。不会让急性子,看不到提示在抓狂的乱点吧。注意:由于这里是同步下载图片,并很可能费时较久,所以要起子线程下载,更新进度条的进度要回主线程更新。进度条类的代码如下:
AWLoadImagesProgressBar.h文件
AWLoadImagesProgressBar.h文件
#import <UIKit/UIKit.h> @interface AWLoadImagesProgressBar : UIView @property (nonatomic, strong) UIView *detailView; @property (nonatomic, strong) UIView *topView; @property (nonatomic, strong) UIView *bottomView; @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *infoLabel; @property (nonatomic, strong) NSString *info; @property (nonatomic, assign) NSInteger totalImagesCount; @property (nonatomic, assign) NSInteger loadImagesCount; -(id)init; -(void)show; @end
AWLoadImagesProgressBar.m文件
#import "AWLoadImagesProgressBar.h" @interface AWLoadImagesProgressBar () @end @implementation AWLoadImagesProgressBar -(id)init{ if (self = [super init]) { self.userInteractionEnabled = YES; self.frame = CGRectMake(0, 0, kUIScreenWidth, kUIScreenHeight); self.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.7f]; self.userInteractionEnabled = YES; [self setupSubViews]; } return self; } - (void)show { [[UIApplication sharedApplication].keyWindow addSubview:self]; self.frame = CGRectMake(0, 0, kUIScreenWidth, kUIScreenHeight); } -(void)setupSubViews{ CGFloat frontSize = 14; CGFloat height = 120; self.detailView = [[UIView alloc]initWithFrame:CGRectMake((kUIScreenWidth - 270)/2, (kUIScreenHeight- height)/2, 270, height)]; self.detailView.backgroundColor = [UIColor whiteColor]; self.detailView.layer.cornerRadius = 5; self.detailView.layer.masksToBounds = YES; [self addSubview:self.detailView]; self.topView = [[UIView alloc]init]; self.topView.backgroundColor = RGBA(255, 255, 255, 1); [self.detailView addSubview:self.topView]; UILabel *detailTitleLabel = [[UILabel alloc]init]; detailTitleLabel.text = @"正在下载"; detailTitleLabel.textAlignment = NSTextAlignmentCenter; detailTitleLabel.textColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0]; detailTitleLabel.font = [UIFont boldSystemFontOfSize:frontSize]; [self.topView addSubview:detailTitleLabel]; self.titleLabel = detailTitleLabel; self.bottomView = [[UIView alloc]init]; self.bottomView.backgroundColor = RGBA(255, 255, 255, 1); [self.detailView addSubview:self.bottomView]; detailTitleLabel = [[UILabel alloc]init]; detailTitleLabel.text = @"0/1"; detailTitleLabel.textAlignment = NSTextAlignmentCenter; detailTitleLabel.textColor = RGBA(127, 127, 127, 1); detailTitleLabel.font = [UIFont systemFontOfSize:frontSize]; [self.bottomView addSubview:detailTitleLabel]; self.infoLabel = detailTitleLabel; [self shareLayout]; } -(void)shareLayout { CGFloat height = 120; CGFloat width = 270; CGFloat contenWidth = width - 20 * 2; self.topView.sd_layout .widthIs(contenWidth) .heightIs(height/2) .topSpaceToView(self.detailView, 0) .centerXEqualToView(self.detailView); self.titleLabel.sd_layout .widthIs(contenWidth) .heightIs(16) .centerXEqualToView(self.topView) .centerYEqualToView(self.topView); self.bottomView.sd_layout .widthIs(contenWidth) .heightIs(height/2) .topSpaceToView(self.topView, 0) .centerXEqualToView(self.detailView); self.infoLabel.sd_layout .widthIs(contenWidth) .heightIs(16) .topSpaceToView(self.bottomView, 10) .centerYEqualToView(self.bottomView); } -(void)setLoadImagesCount : (NSInteger)loadImagesCount { if(loadImagesCount<= 0) { if(_totalImagesCount > 0) { self.infoLabel.text = [NSString stringWithFormat:@"1/%lu", _totalImagesCount]; } else { self.infoLabel.text = @"1/1"; } } else { _loadImagesCount =loadImagesCount; if(_totalImagesCount > 0) { self.infoLabel.text = [NSString stringWithFormat:@"%lu/%lu", _loadImagesCount, _totalImagesCount]; } else { self.infoLabel.text = [NSString stringWithFormat:@"%lu/%lu", _loadImagesCount, _loadImagesCount]; } if(_totalImagesCount < _loadImagesCount) { [self cancelView]; } } } -(void)cancelView { self.frame = CGRectMake(0, kUIScreenHeight, kUIScreenWidth, 250); } @end
加入进度条后的效果:
来开始解决第三个问题了,我想我只是给系统分享组件了图片,它唤醒的关我鸟事,开始帅锅。帅了锅,但是我怀疑一切的性格,还是对是否能改进探索了一下。探索的结果真的关我们鸟事,找到问题所在,就有了解决方案。原来微信分享的正方形图片,最终都转换为两种尺寸的图片:120*120(当然你的图片不是正方形的,回出现宽或高是120像素,高或宽小于120像素的情况),800*800(当然你的图片不是正方形的,回出现宽或高是800像素,高或宽小于800像素的情况)。若你给他一些很大的图片,他会对这些进行压缩,当然压缩图片是需要时间的,特别是一次来九张图片,那么时间就比较长了,一般人可以感知到了。app接收到图片判断图片尺寸,若是宽高都不大于800就不压缩,若超过就等比例压缩,保证最大的宽或高正好是800像素。当然图片服务器端才是问题的关键,app端只是预防处理。我们的解决方案是,对我们待分享的图片,阿里云下载接口压缩配置端设置宽度最大为800像素,高度自适应。配置好后确实,由于图片下载成功,那些无法八门尺寸的图片,少了本地图片下载后的压缩过程,也少了一部分唤起微信前的图片压缩过程,所以唤起微信分享选择页面比以前快多了。
正方形图片分享出来图片信息:
正方形图片分享出来图片信息:
长方形图片(宽比高大)分享出来图片信息:
第四个问题,怎么会有这种偶发现象呢?在网上一查真的存在这样的问题。具体参照文章《由于应用BundleID信息校验不通过,无法分享到微信(iOS)》。显然是在微信开发者平台注册app时,没有填项目的BundleId。真搞不懂,那为何有的手机分享好好的,就测试是异常呢!不过幸亏测试出来了,要是这个问题到了现网,我们就吃不了兜着走了。赶紧去微信开发者平台把项目的BundleId补充上去,测试机就可以玩分享了。
咱们这个五哥真的很难缠啊?我已经把有UIActivityType所有枚举类型都加上了,他还是有其它应用图标(如:添加到“备忘录”等)插队在前面,那为何别的应用能做到微信在最前排呢?查系统接口也查不出一个所以然来,他告诉我们把对应的UIActivityType类型加入excludedActivityTypes就能不显示对应图标。我开始了拼命骚扰度娘模式。在网上有的说可以自定义UIActivity,我如获至宝,赶紧去试。结果呢?加了自定义的微信图标,结果系统分享组件里又一个微信自己的图标,显然自己定义的这个微信图标还没有原生的好看,那个不显示的应用图标类型里也没有这个微信枚举类型。这个解决方案就是一个扯蛋的方案,你不可能不让别人装微信,不然两个微信图标太奇茇了。继续骚扰度娘。发现有很多抄袭的文章介绍各个activity可以支持的数据类型,我赶紧改变分享的activity,让它有且只含有标题和多个图片。有门,少了很多应用图标。
NSString *textToShare = self.homeParamsEntity.shareImagesEntiy.title; NSMutableArray *activityItems = [NSMutableArray array]; if(isEmptyString(textToShare)) { textToShare = @""; } [activityItems addSafeObject:textToShare]; [activityItems addSafeObject:image];
但是还有:添加到“备忘录”这个顽固分子还在。分享到添加到“备忘录”,打印activityType。代码如下:
acti
打印的日志显示为:2018-09-03 15:49:59.399972+0800 ArtEnjoymentWeChatAuction[53264:4927239] com.apple.mobilenotes.SharingExtension —- (null)。终于发现新大陆了,备忘录对应的字符串是:com.apple.mobilenotes.SharingExtension,注意它可没有枚举类型啊!不知道苹果怎么想的,为何不对它设置枚举类型。赶紧去向度娘问和她相好的其他类型有哪些,发现有十几种,经过筛选又加入了iCloud 云盘(@”com.apple.CloudDocsUI.AddToiCloudDrive”),可以它在二级选择理,加入以后没有卵用,既然加入就加入吧,还加入了@”com.apple.mobileslideshow.StreamShareService”,也没有看到效果。
2017-02-27 23:59:34.849563 WeixinActivity[6692:2156679] [core] SLComposeViewController _shareExtensionWithIdentifier: continuous discovery block got extensions ( "<NSExtension: 0x170167b00> {id = com.apple.share.SinaWeibo.post}", "<NSExtension: 0x170166240> {id = com.apple.share.TencentWeibo.post}", "<NSExtension: 0x1701663c0> {id = com.taobao.taobao4iphone.ShareExtension}", "<NSExtension: 0x170166540> {id = com.tencent.qqmail.shareextension}", "<NSExtension: 0x1701666c0> {id = com.apple.mobilenotes.SharingExtension}", "<NSExtension: 0x170166b40> {id = com.apple.share.Vimeo.post}", "<NSExtension: 0x1701669c0> {id = com.apple.mobileslideshow.StreamShareService}", "<NSExtension: 0x170166840> {id = com.tencent.mqq.ShareExtension}", "<NSExtension: 0x170166cc0> {id = com.tencent.xin.sharetimeline}", "<NSExtension: 0x170166e40> {id = com.apple.share.Twitter.post}", "<NSExtension: 0x170166fc0> {id = com.apple.share.Flickr.post}", "<NSExtension: 0x170167140> {id = com.alipay.iphoneclient.ExtensionSchemeShare}", "<NSExtension: 0x170167380> {id = com.apple.Music.MediaSocialShareService}", "<NSExtension: 0x170167500> {id = com.apple.share.Facebook.post}", "<NSExtension: 0x170167680> {id = com.apple.reminders.RemindersEditorExtension}", "<NSExtension: 0x170167800> {id = com.up.2.ShareExtension}", "<NSExtension: 0x170167980> {id = com.jianshu.Hugo.Share-Extension}", "<NSExtension: 0x1701660c0> {id = com.apple.Health.HealthShareExtension}" ) error (null) 2017-02-27 23:59:34.853193 WeixinActivity[6692:2156679] [core] SLComposeViewController _shareExtensionWithIdentifier: continuous discovery block did update _identifierToShareExtensionMap { "com.alipay.iphoneclient.ExtensionSchemeShare" = "<NSExtension: 0x170167140> {id = com.alipay.iphoneclient.ExtensionSchemeShare}"; "com.apple.Health.HealthShareExtension" = "<NSExtension: 0x1701660c0> {id = com.apple.Health.HealthShareExtension}"; "com.apple.Music.MediaSocialShareService" = "<NSExtension: 0x170167380> {id = com.apple.Music.MediaSocialShareService}"; "com.apple.mobilenotes.SharingExtension" = "<NSExtension: 0x1701666c0> {id = com.apple.mobilenotes.SharingExtension}"; "com.apple.mobileslideshow.StreamShareService" = "<NSExtension: 0x1701669c0> {id = com.apple.mobileslideshow.StreamShareService}"; "com.apple.reminders.RemindersEditorExtension" = "<NSExtension: 0x170167680> {id = com.apple.reminders.RemindersEditorExtension}"; "com.apple.share.Facebook.post" = "<NSExtension: 0x170167500> {id = com.apple.share.Facebook.post}"; "com.apple.share.Flickr.post" = "<NSExtension: 0x170166fc0> {id = com.apple.share.Flickr.post}"; "com.apple.share.SinaWeibo.post" = "<NSExtension: 0x170167b00> {id = com.apple.share.SinaWeibo.post}"; "com.apple.share.TencentWeibo.post" = "<NSExtension: 0x170166240> {id = com.apple.share.TencentWeibo.post}"; "com.apple.share.Twitter.post" = "<NSExtension: 0x170166e40> {id = com.apple.share.Twitter.post}"; "com.apple.share.Vimeo.post" = "<NSExtension: 0x170166b40> {id = com.apple.share.Vimeo.post}"; "com.jianshu.Hugo.Share-Extension" = "<NSExtension: 0x170167980> {id = com.jianshu.Hugo.Share-Extension}"; "com.taobao.taobao4iphone.ShareExtension" = "<NSExtension: 0x1701663c0> {id = com.taobao.taobao4iphone.ShareExtension}"; "com.tencent.mqq.ShareExtension" = "<NSExtension: 0x170166840> {id = com.tencent.mqq.ShareExtension}"; "com.tencent.qqmail.shareextension" = "<NSExtension: 0x170166540> {id = com.tencent.qqmail.shareextension}"; "com.tencent.xin.sharetimeline" = "<NSExtension: 0x170166cc0> {id = com.tencent.xin.sharetimeline}"; "com.up.2.ShareExtension" = "<NSExtension: 0x170167800> {id = com.up.2.ShareExtension}"; }
if (@available(iOS 11.0, *)) { self.homeParamsEntity.shareImagesEntiy.excludedActivityTypes = @[UIActivityTypePostToFacebook,UIActivityTypePostToTwitter, UIActivityTypePostToWeibo,UIActivityTypeMessage,UIActivityTypeMail,UIActivityTypePrint,UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList,UIActivityTypePostToFlickr,UIActivityTypePostToVimeo,UIActivityTypePostToTencentWeibo,UIActivityTypeAirDrop,UIActivityTypeOpenInIBooks,UIActivityTypeMarkupAsPDF,UIActivityTypeCopyToPasteboard,@"com.apple.mobilenotes.SharingExtension",@"com.apple.mobileslideshow.StreamShareService",@"com.apple.CloudDocsUI.AddToiCloudDrive",@"com.apple.reminders.RemindersEditorExtension"]; } else if (@available(iOS 9.0, *)) { self.homeParamsEntity.shareImagesEntiy.excludedActivityTypes = @[UIActivityTypePostToFacebook,UIActivityTypePostToTwitter, UIActivityTypePostToWeibo,UIActivityTypeMessage,UIActivityTypeMail,UIActivityTypePrint,UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList,UIActivityTypePostToFlickr,UIActivityTypePostToVimeo,UIActivityTypePostToTencentWeibo,UIActivityTypeAirDrop,UIActivityTypeOpenInIBooks,UIActivityTypeCopyToPasteboard,@"com.apple.mobilenotes.SharingExtension",@"com.apple.mobileslideshow.StreamShareService",@"com.apple.CloudDocsUI.AddToiCloudDrive",@"com.apple.reminders.RemindersEditorExtension"]; } else { self.homeParamsEntity.shareImagesEntiy.excludedActivityTypes = @[UIActivityTypePostToFacebook,UIActivityTypePostToTwitter, UIActivityTypePostToWeibo,UIActivityTypeMessage,UIActivityTypeMail,UIActivityTypePrint,UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList,UIActivityTypePostToFlickr,UIActivityTypePostToVimeo,UIActivityTypePostToTencentWeibo,UIActivityTypeAirDrop,UIActivityTypeCopyToPasteboard,@"com.apple.mobilenotes.SharingExtension",@"com.apple.mobileslideshow.StreamShareService",@"com.apple.CloudDocsUI.AddToiCloudDrive",@"com.apple.reminders.RemindersEditorExtension"]; }
排除类型加入完毕,测试发现你终于我一片天了,微信终于当老大了。不过你在活动中吧微信也关闭了,那么分享组件的应用选择第一栏也空空如野了。
不期望的系统分享组件显示的应用选择页面:
正常的系统分享组件显示的应用选择页面:
系统分享组件的活动页面,可以开关显示的应用:
系统分享组件的活动页面关闭所有显示的应用后的效果图,若发现该种情况并且已经安装微信,去活动页面使能微信显示功能:
排除类型加入完毕,测试发现你终于我一片天了,微信终于当老大了。不过你在活动中把微信也关闭了,那么分享组件的应用选择第一栏也空空如野了。
这个多图片分享真是多灾多难啊!就是一个小型技术研究了。这个问题的解决方案就是通过指定activity的内容为标题和图片分享,设置私有的excludedActivityTypes顾虑类型。所有问题解决完毕。来点干货:
多图片分享实际执行部分代码:
@weakify(self); _homeParamsEntity.shareImagesWXBlock = ^(AWShareImagesEntiy *shareImagesEntiy) { @strongify(self); if(isEmptyArray(shareImagesEntiy.activityItems) || isEmptyArray(shareImagesEntiy.excludedActivityTypes)) { return ; } UIActivityViewController *activityVC = [[UIActivityViewController alloc]initWithActivityItems:shareImagesEntiy.activityItems applicationActivities:nil]; activityVC.excludedActivityTypes = shareImagesEntiy.excludedActivityTypes; [self presentViewController:activityVC animated:NO completion:nil]; activityVC.completionWithItemsHandler = ^(UIActivityType __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError){ NSLog(@"%@ ---- %@", activityType, returnedItems); UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; pasteboard.string = @""; }; };
js下发多图片分享部分代码,不是完整的代码,自截去了和多:
-(void)processWeipaiJSBridgeMessage:(WKScriptMessage *)message { //服务器固定格式写法 window.webkit.messageHandlers.名字.postMessage(内容); //客户端写法 message.name isEqualToString:@"名字"] NSLog(@"message:%@", message); if ([message.name isEqualToString:@"WeipaiJSBridge"]) { NSLog(@"WeipaiJSBridge:%@", message.body); AWWeipaiJSBridgeEntity *weipaiJSBridgeEntity = [AWWeipaiJSBridgeEntity yy_modelWithJSON:message.body]; if(isEmptyString(weipaiJSBridgeEntity.methodName)) { // AWChooseImageEntity *chooseImageEntity = [AWChooseImageEntity alloc]; // FLDDLogVerbose(@"%@", chooseImageEntity); // [self.homeParamsEntity.chooseImageEntity updateChooseImageEntity:chooseImageEntity]; // [self chooseImage]; return; } else if ([weipaiJSBridgeEntity.methodName isEqualToString:onH5ShareWXClassNameStr]) { NSLog(@"onH5ShareWX:%@", weipaiJSBridgeEntity.methodName); AWShareImagesEntiy *shareImagesEntiy = [AWShareImagesEntiy yy_modelWithDictionary:weipaiJSBridgeEntity.params]; FLDDLogVerbose(@"%@", shareImagesEntiy); NSArray *arr = weipaiJSBridgeEntity.params[@"images"]; NSMutableArray *images = [NSMutableArray array]; for(NSUInteger i = 0; i < arr.count; i++) { NSString *url = arr[i]; [images addSafeObject:url]; } shareImagesEntiy.images = images; self.homeParamsEntity.shareImagesEntiy = shareImagesEntiy; if(images > 0) { if (![WXApi isWXAppInstalled]) { //把微信登录的按钮隐藏掉。 [[AWNoticeView currentNotice] showErrorNotice:@"您没有安装微信客户端"]; return; } self.homeParamsEntity.loadImagesProgressBar.totalImagesCount = images.count; self.homeParamsEntity.loadImagesProgressBar.loadImagesCount = 1; [self.homeParamsEntity.loadImagesProgressBar show]; @weakify(self); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @strongify(self); BOOL loadImagesSuccess = [self loadImages]; yx_dispatch_main_sync_safe(^{ @strongify(self); self.homeParamsEntity.loadImagesProgressBar.loadImagesCount = images.count + 1; if(loadImagesSuccess) { [self shareImagesWX]; } else { [[AWNoticeView currentNotice] showErrorNotice:@"下载失败"]; } }); }); } } } } -(void)shareImagesWX { if(self.homeParamsEntity.shareImagesWXBlock) { self.homeParamsEntity.shareImagesWXBlock(self.homeParamsEntity.shareImagesEntiy); } }
下面是图片下载和图片压缩相关函数,进度条上面有完整代码:
//异步下载多图片 -(BOOL)loadImages { NSString *textToShare = self.homeParamsEntity.shareImagesEntiy.title; NSMutableArray *activityItems = [NSMutableArray array]; if(isEmptyString(textToShare)) { textToShare = @""; } [activityItems addSafeObject:textToShare]; UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; pasteboard.string = textToShare; long long nowTime = (long long)([[NSDate date] timeIntervalSince1970]*1000); NSLog(@"nowTime:%lld毫秒", nowTime); // self.homeParamsEntity.loadImagesProgressBar.loadImagesCount = 1; BOOL loadImagesSuccess = YES; for(NSInteger i = 0; (i <= 8) && (i < self.homeParamsEntity.shareImagesEntiy.images.count); i++) { NSString *url = self.homeParamsEntity.shareImagesEntiy.images[i]; if(!isEmptyString(url)) { NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]]; if(data) { @weakify(self); yx_dispatch_main_sync_safe(^{ @strongify(self); self.homeParamsEntity.loadImagesProgressBar.loadImagesCount = i + 2; }); //[self getImageWithDada:data]; UIImage *image = [self compressImageWithDada:data]; [activityItems addSafeObject:image]; NSLog(@"nowTime:%lld毫秒", (long long)([[NSDate date] timeIntervalSince1970]*1000) - nowTime); } else { loadImagesSuccess = NO; @weakify(self); yx_dispatch_main_sync_safe(^{ @strongify(self); self.homeParamsEntity.loadImagesProgressBar.loadImagesCount = self.homeParamsEntity.shareImagesEntiy.images.count + 1; }); break; } } } if(!loadImagesSuccess) { return loadImagesSuccess; } NSLog(@"下载%lu张图片总耗时:%lld毫秒", (unsigned long)(self.homeParamsEntity.shareImagesEntiy.images.count), (long long)([[NSDate date] timeIntervalSince1970]*1000) - nowTime); if (@available(iOS 11.0, *)) { self.homeParamsEntity.shareImagesEntiy.excludedActivityTypes = @[UIActivityTypePostToFacebook,UIActivityTypePostToTwitter, UIActivityTypePostToWeibo,UIActivityTypeMessage,UIActivityTypeMail,UIActivityTypePrint,UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList,UIActivityTypePostToFlickr,UIActivityTypePostToVimeo,UIActivityTypePostToTencentWeibo,UIActivityTypeAirDrop,UIActivityTypeOpenInIBooks,UIActivityTypeMarkupAsPDF,UIActivityTypeCopyToPasteboard,@"com.apple.mobilenotes.SharingExtension",@"com.apple.mobileslideshow.StreamShareService",@"com.apple.CloudDocsUI.AddToiCloudDrive",@"com.apple.reminders.RemindersEditorExtension"]; } else if (@available(iOS 9.0, *)) { self.homeParamsEntity.shareImagesEntiy.excludedActivityTypes = @[UIActivityTypePostToFacebook,UIActivityTypePostToTwitter, UIActivityTypePostToWeibo,UIActivityTypeMessage,UIActivityTypeMail,UIActivityTypePrint,UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList,UIActivityTypePostToFlickr,UIActivityTypePostToVimeo,UIActivityTypePostToTencentWeibo,UIActivityTypeAirDrop,UIActivityTypeOpenInIBooks,UIActivityTypeCopyToPasteboard,@"com.apple.mobilenotes.SharingExtension",@"com.apple.mobileslideshow.StreamShareService",@"com.apple.CloudDocsUI.AddToiCloudDrive",@"com.apple.reminders.RemindersEditorExtension"]; } else { self.homeParamsEntity.shareImagesEntiy.excludedActivityTypes = @[UIActivityTypePostToFacebook,UIActivityTypePostToTwitter, UIActivityTypePostToWeibo,UIActivityTypeMessage,UIActivityTypeMail,UIActivityTypePrint,UIActivityTypeAssignToContact,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList,UIActivityTypePostToFlickr,UIActivityTypePostToVimeo,UIActivityTypePostToTencentWeibo,UIActivityTypeAirDrop,UIActivityTypeCopyToPasteboard,@"com.apple.mobilenotes.SharingExtension",@"com.apple.mobileslideshow.StreamShareService",@"com.apple.CloudDocsUI.AddToiCloudDrive",@"com.apple.reminders.RemindersEditorExtension"]; } self.homeParamsEntity.shareImagesEntiy.activityItems = activityItems; return loadImagesSuccess; } //安尺寸等比例压缩图片 -(UIImage *)compressImageWithDada : (NSData *)data { UIImage *image = [UIImage imageWithData:data]; if((image.size.height <= maxShareImageHeight) && (image.size.width <= maxShareImageWidth)) { return image; } if((maxShareImageWidth == 0) || (maxShareImageHeight == 0)) { //防止除数为0而crash,理论上不该出现maxIphoneScreenMaxSizeHeight为0 return nil; } // float imageWidth = image.size.width; // float imageHeight = image.size.height; //800x800 float width = maxShareImageWidth; float height = image.size.height/(image.size.width/width); if((image.size.width >= maxShareImageWidth) && (image.size.height >= maxShareImageHeight)) { width = maxShareImageWidth; height = image.size.height/(image.size.width/width); if(height > maxShareImageHeight) { height = maxShareImageHeight; width = image.size.width/(image.size.height/height); } } else if(image.size.width >= maxShareImageWidth) { height = maxShareImageHeight; width = image.size.width/(image.size.height/height); } // else if(image.size.height >= maxIphoneScreenMaxSizeHeight) // { // width = maxIphoneScreenMaxSizeWidth; // height = image.size.height/(image.size.width/width); // } // float widthScale = imageWidth /width; // float heightScale = imageHeight /height; // 创建一个bitmap的context // 并把它设置成为当前正在使用的context UIGraphicsBeginImageContext(CGSizeMake(width, height)); [image drawInRect:CGRectMake(0, 0, width , height)]; // if (widthScale > heightScale) { // [image drawInRect:CGRectMake(0, 0, imageWidth /heightScale , height)]; // } // else { // [image drawInRect:CGRectMake(0, 0, width , imageHeight /widthScale)]; // } // 从当前context中创建一个改变大小后的图片 UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 使当前的context出堆栈 UIGraphicsEndImageContext(); return newImage; }
以下是解决问题时走过的弯路,探索按照图片质量参数简易二分压缩图片各个函数,有压缩上限
-(UIImage *)getImageWithDada : (NSData *)data { if(!data) { return nil; } UIImage *image = [UIImage imageWithData:data]; if(data.length <= shareImageMaxLength) { NSLog(@"data.length:%lu", (unsigned long)data.length); return image; } else { CGFloat compressionQualityArr[1001] = {0}; compressionQualityArr[0] = 0.0001; for(NSInteger i = 1; i <= 1000; i++) { compressionQualityArr[i] = i*0.001; } NSData *compressedData = [self findImageWithImage:image lowerBoundary:0 upperBoundary:1000 compressionQualityArr:compressionQualityArr]; if(data.length <= shareImageMaxLength) { return [UIImage imageWithData:compressedData]; } else { return [self findScaleImageWithImage:image lowerBoundary:0 upperBoundary:1000 compressionQualityArr:compressionQualityArr];; } } } -(UIImage *)findScaleImageWithImage : (UIImage *)image lowerBoundary : (NSInteger)lowerBoundary upperBoundary : (NSInteger)upperBoundary compressionQualityArr : (CGFloat *)compressionQualityArr { NSInteger x = (lowerBoundary + upperBoundary) / 2; UIImage* compressedImage = [self resizeImageWithImage:image scale:compressionQualityArr[x]]; NSData *data = UIImageJPEGRepresentation(compressedImage, 0.7); if(data.length <= shareImageMaxLength) { NSLog(@"data.length:%lu,compressionQualityArr[%ld]:%f", (unsigned long)data.length, (long)x, compressionQualityArr[x]); return compressedImage; } if ((data.length > shareImageMaxLength) && (x > 0))//说明在compressionQualityArr[lowerBoundary]-compressionQualityArr[x]范围参数之中 { return [self findScaleImageWithImage:image lowerBoundary:lowerBoundary upperBoundary:x compressionQualityArr:compressionQualityArr]; } else { NSLog(@"data.length:%lu,compressionQualityArr[%ld]:%f; fail compressed Image", (unsigned long)data.length, (long)x, compressionQualityArr[x]); return nil; } } -(NSData *)findImageWithImage : (UIImage *)image lowerBoundary : (NSInteger)lowerBoundary upperBoundary : (NSInteger)upperBoundary compressionQualityArr : (CGFloat *)compressionQualityArr { NSInteger x = (lowerBoundary + upperBoundary) / 2; NSData *data = UIImageJPEGRepresentation(image, compressionQualityArr[x]); if(data.length <= shareImageMaxLength) { NSLog(@"data.length:%lu,compressionQualityArr[%ld]:%f", (unsigned long)data.length, (long)x, compressionQualityArr[x]); return data; } if ((data.length > shareImageMaxLength) && (x > 0))//说明在compressionQualityArr[lowerBoundary]-compressionQualityArr[x]范围参数之中 { return [self findImageWithImage:image lowerBoundary:lowerBoundary upperBoundary:x compressionQualityArr:compressionQualityArr]; } else { NSLog(@"data.length:%lu,compressionQualityArr[%ld]:%f", (unsigned long)data.length, (long)x, compressionQualityArr[x]); return data; } } - (UIImage *)resizeImageWithImage : (UIImage *)image scale : (CGFloat)scale { CGSize originalSize = image.size; CGSize newSize; newSize = CGSizeMake(originalSize.width * scale, originalSize.height * scale); // Scale the original image to match the new size. UIGraphicsBeginImageContext(newSize); [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; UIImage* compressedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return compressedImage; }