iOS-Share Extension

本文介绍如何在 iOS 应用中实现自定义 Share Extension 分享界面,包括修改 info.plist 文件指定自定义控制器、实现视图布局及交互,并提供 AFNetworking 网络请求示例。同时提醒开发者注意 App Store 提交审核时的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

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要保持一致,否则在上传审核包的时候会提示警告,导致程序无法正常提审。

转载于:https://my.oschina.net/u/1450995/blog/810009

<think>好的,用户想了解如何在Xamarin.iOS中实现Share Extension功能。我需要先回忆一下Share Extension的基本概念。Share ExtensioniOS允许应用扩展系统分享功能的一种方式,用户可以在其他应用中使用分享按钮直接分享内容到目标应用。例如,分享网页到社交媒体应用。 首先,用户需要在Xamarin.iOS项目中添加一个新的Extension项目。在Visual Studio中,右键解决方案,选择添加新项目,然后选择iOS扩展中的Share Extension模板。这一步应该比较直接,但需要注意选择正确的模板。 接下来,配置Info.plist文件。需要确保NSExtensionActivationRule正确设置,定义支持的数据类型,比如文本、图片、URL等。这部分如果配置不当,可能导致分享选项不出现或者无法处理特定类型的数据。可能需要引用苹果的文档或者Xamarin的指南来确认正确的配置方式。 然后,处理分享的数据。在ShareViewController中,需要重写DidSelectPost方法,这里可以获取用户分享的内容。使用extensionContext?.InputItems获取输入项,遍历其中的attachments,根据数据类型进行处理。例如,检查是否有URL或者文本,然后提取数据。需要注意的是,处理数据时需要异步进行,可能需要用到async/await。 用户可能需要将分享的数据发送到主应用,这时候要配置App Groups。在iOS中,扩展和主应用需要通过App Groups共享数据。需要在开发者账户中启用App Groups,并在项目和扩展的Entitlements.plist中添加相同的群组标识符。使用NSUserDefaults或文件共享来传递数据。 实现UI部分可能需要自定义界面,但系统默认会提供一个简单的界面。如果需要自定义,可能需要使用Interface Builder创建故事板,并调整ShareViewController的视图。但根据用户的问题,可能暂时不需要深入这部分,保持默认即可。 最后,测试和调试。由于扩展是独立的进程,调试时需要将扩展项目设为启动项,然后选择宿主应用进行调试。这可能会比较麻烦,但通过正确配置调试目标应该可以解决。 在回答时,需要分步骤说明,确保用户能够逐步跟随。同时,注意引用相关的文档,比如Xamarin的官方指南和苹果的开发者文档,以增强可信度。另外,用户提供的引用中提到了Xamarin的活跃社区和API文档,可以适当引用这些点来说明Xamarin的支持情况。 可能用户在实际操作中会遇到的问题,比如如何正确处理不同类型的数据,如何配置App Groups,或者如何处理异步加载。需要预见到这些问题,并在回答中提到可能的解决方案或注意事项。 总结步骤:添加扩展项目、配置Info.plist、处理数据、配置App Groups、实现数据传输、测试调试。每个步骤需要简明扼要,代码示例要准确,使用C#和Xamarin的语法。同时,相关问题可以涉及性能优化、数据安全、自定义UI等,帮助用户深入理解。</think>在Xamarin.iOS中实现Share Extension功能需要以下步骤,结合系统级API和Xamarin特性进行开发: ### 1. 创建Share Extension项目 在现有Xamarin.iOS解决方案中: - 右击解决方案 > 添加 > 新建项目 - 选择`iOS扩展 > Share Extension`模板 - 设置最低iOS版本(建议11.0+) ### 2. 配置Info.plist 修改扩展的`Info.plist`文件: ```xml <key>NSExtension</key> <dict> <key>NSExtensionPrincipalClass</key> <string>ShareViewController</string> <key>NSExtensionPointIdentifier</key> <string>com.apple.share-services</string> <key>NSExtensionAttributes</key> <dict> <key>NSExtensionActivationRule</key> <dict> <key>NSExtensionActivationSupportsWebURLWithMaxCount</key> <integer>1</integer> <key>NSExtensionActivationSupportsImageWithMaxCount</key> <integer>10</integer> </dict> </dict> </dict> ``` 此配置允许接收网页链接和图片类型数据[^1] ### 3. 实现数据接收逻辑 在`ShareViewController.cs`中重写关键方法: ```csharp public override void DidSelectPost() { foreach (var inputItem in ExtensionContext.InputItems) { var attachments = inputItem.Attachments; foreach (var itemProvider in attachments) { if (itemProvider.HasItemConformingTo(UTType.URL)) { itemProvider.LoadItem(UTType.URL, null, async (data, error) => { var url = data as NSUrl; // 处理URL数据 await ShareToHostApp(url.AbsoluteString); }); } else if (itemProvider.HasItemConformingTo(UTType.PlainText)) { // 类似处理文本数据 } } } ExtensionContext.CompleteRequest(); } ``` ### 4. 配置应用组共享 A. 在Apple Developer Center创建App Group ID B. 在主应用和扩展的Entitlements.plist中添加: ```xml <key>com.apple.security.application-groups</key> <array> <string>group.your.company.app</string> </array> ``` C. 使用NSUserDefaults共享数据: ```csharp var sharedDefaults = new NSUserDefaults("group.your.company.app", NSUserDefaultsType.SuiteName); sharedDefaults.SetString(sharedData, "sharedKey"); sharedDefaults.Synchronize(); ``` ### 5. 调试技巧 - 在项目属性中设置`Debug > Start external program`为`/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app` - 选择调试目标为`Share Extension` - 添加`CFBundleDisplayName`确保扩展可见
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值