前言
IOS扩展主要的目的是用户可以在 app 中使用其他应用提供的功能,而无需离开当前的应用,因此可以发现在浏览图片或者是打开safari,点击分享的按钮,可以分享至很多其他的应用,这都是归功于IOS share extension扩展强大之处,据我的了解目前大部分的应用都没有实现扩展功能,所以网络上能查询到的资料很少,我也是尝试着去了解其如何使用,我今天要讲的并不是如何去为应用创建一个扩展,因为网络上是有这方面的内容的,我侧重讲的自定义分享界面,因为可能系统自带的UI界面并不能满足我们应用的要求,自定义界面是势在必行的;
一、如何为当前的应用添加share extension扩展,这个网络上都有操作步骤,我就不再重复。
二、在创建好share extension中,去修改info.plist文件,如
如此设置代表着,扩展的入口为CustomShareViewController(默认的是ShareViewController),接下来就是自定义布局,你可以在控制器中定义自己的UI交互,比如我做的简单的布局;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor colorWithWhite:0 alpha:0.6];
//定义一个容器视图来存放分享内容和两个操作按钮
container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 175)];
container.center = self.view.center;
container.layer.cornerRadius = 7;
container.layer.borderColor = [UIColor lightGrayColor].CGColor;
container.layer.borderWidth = 1;
container.layer.masksToBounds = YES;
container.backgroundColor = [UIColor whiteColor];
container.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[self.view addSubview:container];
oldRect = container.frame;
othorView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 220)];
othorView.center = self.view.center;
othorView.layer.cornerRadius = 7;
othorView.layer.borderColor = [UIColor lightGrayColor].CGColor;
othorView.layer.borderWidth = 1;
othorView.alpha = 0;
othorView.layer.masksToBounds = YES;
othorView.backgroundColor = [UIColor whiteColor];
othorView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[self.view addSubview:othorView];
UIButton *backBut = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 65, 44)];
[backBut setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[backBut setTitle:@"返回" forState:UIControlStateNormal];
[backBut addTarget:self action:@selector(goBack:) forControlEvents:UIControlEventTouchUpInside];
textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 50, 200, 50)];
textView.text = @"测试";
[othorView addSubview:backBut];
[othorView addSubview:textView];
testBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 300, 44)];
UINavigationItem *ite = [[UINavigationItem alloc] initWithTitle:@"测试"];
//定义Post和Cancel按钮
UIButton *cancelBtn = [UIButton buttonWithType:UIButtonTypeSystem];
[cancelBtn setTitle:@"取消" forState:UIControlStateNormal];
cancelBtn.frame = CGRectMake(-15, 0, 65, 40);
[cancelBtn addTarget:self action:@selector(cancelBtnClickHandler:) forControlEvents:UIControlEventTouchUpInside];
[container addSubview:cancelBtn];
UIButton *postBtn = [UIButton buttonWithType:UIButtonTypeSystem];
[postBtn setTitle:@"发送" forState:UIControlStateNormal];
postBtn.frame = CGRectMake(15, 0, 65, 40);
[postBtn addTarget:self action:@selector(postBtnClickHandler:) forControlEvents:UIControlEventTouchUpInside];
[container addSubview:postBtn];
ite.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:cancelBtn];
ite.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:postBtn];
[testBar setItems:@[ite]];
[container addSubview:testBar];
[container addSubview:self.tableView];
//定义一个分享链接标签
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(8,
cancelBtn.frame.origin.y + cancelBtn.frame.size.height + 8,
container.frame.size.width - 16,
container.frame.size.height - 16 - cancelBtn.frame.origin.y - cancelBtn.frame.size.height)];
label.numberOfLines = 0;
label.textAlignment = NSTextAlignmentCenter;
[container addSubview:label];
//获取分享链接
__block BOOL hasGetUrl = NO;
[self.extensionContext.inputItems enumerateObjectsUsingBlock:^(NSExtensionItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj.attachments enumerateObjectsUsingBlock:^(NSItemProvider * _Nonnull itemProvider, NSUInteger idx, BOOL * _Nonnull stop) {
if ([itemProvider hasItemConformingToTypeIdentifier:@"public.url"])
{
[itemProvider loadItemForTypeIdentifier:@"public.url" options:nil completionHandler:^(id<NSSecureCoding> _Nullable item, NSError * _Null_unspecified error) {
if ([(NSObject *)item isKindOfClass:[NSURL class]])
{
dispatch_async(dispatch_get_main_queue(), ^{
label.text = ((NSURL *)item).absoluteString;
});
}
}];
hasGetUrl = YES;
*stop = YES;
}
*stop = hasGetUrl;
}];
}];
for (NSString *notificationName in @[UIKeyboardWillShowNotification, UIKeyboardWillHideNotification]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:notificationName object:nil];
}
}
其实就是简单的视图切换,当然你也可以定制更加丰富的界面交互,这是跟业务需求挂钩的;
其中还需要注意的两个方法:cancelRequestWithError与completeRequestReturningItems,这个是操作必须的方法,一个是错误执行,另一个是成功执行返回,且执行都会关闭扩展程序界面。
- (void)cancelBtnClickHandler:(id)sender
{
[self.extensionContext cancelRequestWithError:[NSError errorWithDomain:@"CustomShareError" code:NSUserCancelledError userInfo:nil]];
}
- (void)postBtnClickHandler:(id)sender
{
//执行分享内容处理
coverView = [[CoverView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:coverView];
[self performSelector:@selector(testAnima) withObject:nil afterDelay:0.1];
//[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}
三、扩展中使用AFNetworking,网络请求肯定是必须的,具体的使用与在app中使用的一样,如
AFHTTPSessionManager *httpClient = [AFAppHFAPIClient sharedClient];
[httpClient GET:urlString parameters:model progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failed) {
failed(error);
}
}];
但是,特别需要注意的是,扩展中是没有[UIApplication sharedApplication]对象的,所以在操作提示界面的时候,这个是需要注意的。
四、提交AppStore注意事项:
(1)扩展中的处理不能太长时间阻塞主线程(建议放入线程中处处理),否则可能导致苹果拒绝你的应用。
(2)扩展不能单独提审,必须要跟容器程序一起提交AppStore进行审核。
(3)提审的扩展和容器程序的Build Version要保持一致,否则在上传审核包的时候会提示警告,导致程序无法正常提审。