UIActivityViewController继承自UIViewController,是一个系统分享组件,它提供了一些通用的标准服务(AirDrop、Messages,Mail)等,类似于照片里点击分享功能。 国内App可能用的相对较少,一般都是对接友盟分享之类的。网上针对UIActivityViewController的使用介绍虽然有不少,但是却很少有介绍分享预览时的Header区域UI定制,笔者最后在stackoverflow上找到了答案,还参考了国外大神的写法,写下了这篇文章,希望能帮助到大家。
1. 常规分享调用:
先看一下实现效果
代码实现
/// 调起分享器
- (void)showShareActivityVCWith:(NSArray *)messages {
NSMutableArray *itemProviders = [NSMutableArray new];
for (SDModelMessage *message in messages) {
switch (message.type) {
case SDMessageText: {
// 文本类型
NSString *text = message.content;
[itemProviders addObject:text];
}
break;
case SDMessagePicture: {
// 图片类型
NSString *filePath = @"本地路径";
NSURL *imageUrl = [NSURL fileURLWithPath:filePath];
[itemProviders addObject:imageUrl];
}
break;
case SDMessageVideo: {
// 视频类型
NSString *filePath = @"本地路径";
NSURL *videoURL = [NSURL fileURLWithPath:filePath];
[itemProviders addObject:videoURL];
}
break;
case SDMessageAudio:
case SDMessageFile: {
// 语音和文件类型
NSString *filePath = @"本地路径";
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
[itemProviders addObject:fileURL];
}
break;
default:
break;
}
}
// 分享器
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemProviders applicationActivities:nil];
activityVC.excludedActivityTypes = @[UIActivityTypePrint, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll, UIActivityTypeAddToReadingList];
// 分享之后的回调
activityVC.completionWithItemsHandler = ^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) {
if (completed) {
// 分享成功
} else {
// 分享取消
SDLog(@"cancled");
}
};
[self presentViewController:activityVC animated:YES completion:nil];
}
2. 自定义分享预览:
先看一下实现效果(对外邀请):
首先,iOS13.0以前是不支持显示Header区域的,那么可以使用下面方法,也是网上最容易查询到的方法。
// 分享的标题
NSString *title = @"百度";
// 分享的图片
UIImage *image = [UIImage imageNamed:@"icon_logo.png"];
// 分享的url
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
NSArray *activityItems = @[title, image, url];
UIActivityViewController *activityVC = [[UIActivityViewController alloc]initWithActivityItems:activityItems applicationActivities:nil];
activityVC.excludedActivityTypes = @[UIActivityTypePrint, UIActivityTypeAssignToContact];
[self presentViewController:activityVC animated:YES completion:nil];
// 分享之后的回调
activityVC.completionWithItemsHandler = ^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) {
if (completed) {
// 分享 成功
} else {
// 分享 取消
}
};
注意:这里的title,image并不会对Header区域生效,activityVC会把他们和url一起拼接起来,生成分享内容。excludedActivityTypes是我们需要排除的activity; activityItems中的对象类型是可变的,可以是String、Image、URL,也可以是实现UIActivityItemSource的对象。
那么iOS13.0以后究竟如何自定义Header区域,我创建了一个分享的类,专门用于处理项目中分享相关的功能,方便拓展,并优化了异常处理方案。核心代码:
import UIKit
import LinkPresentation
@available(iOS 13.0, *)
@objcMembers class SDShareActivity: NSObject, UIActivityItemSource {
var metadata: LPLinkMetadata?
func inviteShare(_ urlString: String, sender: UIViewController) -> Void {
let url = URL(string: urlString)!
let provider = LPMetadataProvider()
provider.shouldFetchSubresources = false
provider.timeout = 0.5
provider.startFetchingMetadata(for: url) { linkMetadata, _ in
//linkMetadata?.iconProvider = linkMetadata?.imageProvider
//linkMetadata?.url = url;
//如果0.5s的超时时间内,没有获取到网页元素,走本地配置
//这样即使是网络很差,或者断网,也都会再0.5s弹出系统分享,优化用户体验
let metadata = linkMetadata != nil ? linkMetadata : LPLinkMetadata()
metadata?.iconProvider = NSItemProvider(object: UIImage(named: "icon_logo")!)
metadata?.title = NSLocalizedString("Let’s chat on Tanka!", comment: "")
metadata?.originalURL = url
self.metadata = metadata
let activityVc = UIActivityViewController(activityItems: [self], applicationActivities: nil)
DispatchQueue.main.async {
sender.present(activityVc, animated: true)
}
}
}
// The placeholder the share sheet will use while metadata loads
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return ""
}
// The item we want the user to act on.
// In this case, it's the URL to the Wikipedia page
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
return NSLocalizedString("Invite Template", comment: "")
}
// The metadata we want the system to represent as a rich link
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
return metadata
}
}
LinkPresentation是iOS13.0新增的框架,它能够以一致的方式表示内容丰富的URL。从URL检索元数据,在应用程序中显示丰富的链接内容,并在iOS中提供共享表单体验的链接元数据。也就是说:LinkPresentation能获取URL的元数据,包括它的标题、图标和图像或视频链接。想深入了解LinkPresentation可以参考这篇文章:LinkPresentation框架详细解析
参考国外大神写法:Composing Rich Link Previews Using LinkPresentation in Swift