【iOS扩展开发攻略】Share Extension

本文详细介绍了iOS中的Share Extension开发,从创建扩展Target、配置Share Extension到处理分享数据,包括从inputItems中获取数据、传递给容器程序以及设置提示操作。此外,还讨论了如何在AppStore提交扩展时的注意事项,以及进阶研究,如扩展默认分享界面和解决相关问题。
摘要由CSDN通过智能技术生成

1. 什么是扩展?

扩展( Extension )是 iOS 8 中引入的一个非常重要的新特性。扩展让 app 之间的数据交互成为可能。用户可以在 app 中使用其他应用提供的功能,而无需离开当前的应用。在 iOS 8 系统之前,每一个 app 在物理上都是彼此独立的, app 之间不能互访彼此的私有数据。而在引入扩展之后,其他 app 可以与扩展进行数据交换。基于安全和性能的考虑,每一个扩展运行在一个单独的进程中,它拥有自己的 bundle , bundle 后缀名是.appex 。扩展 bundle 必须包含在一个普通应用的 bundle 的内部。

iOS 8 系统有 6 个支持扩展的系统区域,分别是 Today 、 Share 、 Action 、 Photo Editing 、 Storage Provider 、 Custom keyboard 。支持扩展的系统区域也被称为扩展点。

Today Widget

对于赛事比分,股票、天气、快递这类需要实时获取的信息,可以在通知中心的Today 视图中创建一个 Today 扩展实现。 Today 扩展又称为 Widget 。

Today扩展效果图

Share

在 iOS 8 之前,用户只有 Facebook,Twitter 等有限的几个分享选项可以选择。如果希望将内容分享到 Pinterest ,开发者则需要一些额外的努力。在 iOS 8 中,开发者可以创建自定义的分享选项。

Share扩展效果图

Action

action 在所有支持的扩展点中扩展性最强的一个。它可以实现转换另一个 app 上下文中的内容。苹果在 WWDC 大会上演示了一个 Bing 翻译动作扩展,它可以将在 Safari 中选中的文本翻译成不同的语言。

Action扩展效果图

Photo Editing

在 iOS 8 之前,如果你想为你的照片添加一个特殊的滤镜,你需要进入第三方 app 中,这个过程是相当繁琐的。在 iOS 8 中,你可以直接在 Photos 中使用第三方 app ,如 Instagram , VSCO cam 、 Aviary 提供的 Photo Editing 扩展完成对图片的编辑,而无需离开当前的 app 。

Photo Editing扩展效果图

Storage Provider

Storage Provider 让跨多个文件存储服务之间的管理变得更简单。类似 Dropbox 、 Google Drive 等存储提供商通过在 iOS 8 中提供一个 Storage Provider 扩展, app 直接可以使用这些扩展检索和存储文件而不再需要创建不必要的拷贝。

Storage Provider扩展效果图

Custom Keyboard

苹果公司在 2007 年率先推出了触摸屏键盘,但一直没多大改进。在这一方面, Android 则将键盘权限开放给了第三方开发者,所以出现了许多像 Swype , SwiftKey 等优秀的键盘输入法。在 iOS 8 中,苹果终于将键盘权限开发给了第三方开发者,自定义键盘输入法可以让用户在整个系统范围内使用。

Custom Keyboard扩展效果图

以下是iOS 9中新增扩展

网络扩展

开发者可以通过改扩展来实现自定义的VPN客户端、透明的网络代理客户端以及实现动态的设备端网络内容过滤。

Safari扩展

该扩展可以让用户通过Safari的分享链接看到你的内容。又或者提供一个屏蔽列表,让你的用户使用你的App浏览Web内容时屏蔽指定的内容。

Spotlight扩展

该扩展可以对App内的数据进行索引,并且可以在不重启App的情况下重建数据索引。

Audio Unit扩展

该扩展允许App提供类似于GarageBand,Logic等App提供的乐器演奏,音频特效,声音合成功能。

2. 转入正题 - Share Extension

本篇文章主要是探讨Share Extension的开发与使用。下面会结合一个例子对其做一个全面的探讨和深入的了解。

2.1 创建Share Extension扩展Target

** 注:扩展不能单独创建,必须依赖于应用工程项目,因此如果你还没有创建一个应用工程,先去创建一个。**

1、打开项目设置,在TARGETS侧栏地下点击“+”号来创建一个新的Target,如图:

添加Target

2、然后选择”iOS” -> “Application Extension” -> “Share Extension”,点击“Next”。如图:

创建Share扩展

3、给扩展起个名字,这里填写了“Share”,点击“Finish”。如图:

填写扩展信息

4、这时候会提示创建一个Scheme,点击“Activate”。如图:

那么,直到这里创建Share Extension的工作就算是完成了。接下来可以先进行一下编译运行。这里跟做App开发的时候会稍微有点不一样。因为Extension是需要Host App(宿主应用)来运行的。所以,XCode中会弹出界面让我们选择一个iOS的App来运行Extension。如图:

选择宿主应用

这里我选择了XCode建议的应用Safari,然后点击“Run”来进行调试运行。XCode会启动Safari,如图:

能看到Safari中间的分享按钮是灰色不可用的。别急,你还没打开一个网页呢_。我们随便点开一个网页,可以看到分享按钮变为激活状态。点击分享按钮就会弹出分享菜单,如图:

运行效果图

可以看到刚才建立的Share扩展已经显示在面板上了,如果你没有发现自己的扩展,那么你可以将菜单滑动到最右边,在“更多”选项中激活自己的扩展。如图:

我们点击自己创建的分享项,其弹出一个分享窗口。如图:

分享界面效果图

2.2. 配置Share Extension

接下来我们需要给他一些设置。我们展开XCode左侧栏的Share目录,找到Info.plist文件。如:

扩展Info.plist

我们只需要关注以下几个字段的设置:

名称 说明
Bundle display name 扩展的显示名称,默认跟你的项目名称相同,可以通过修改此字段来控制扩展的显示名称。
NSExtension 扩展描述字段,用于描述扩展的属性、设置等。作为一个扩展项目必须要包含此字段。
NSExtensionAttributes 扩展属性集合字段。用于描述扩展的属性。
NSExtensionActivationRule 激活扩展的规则。默认为字符串“TRUEPREDICATE”,表示在分享菜单中一直显示该扩展。可以将类型改为Dictionary类型,然后添加以下字段:
NSExtensionActivationSupportsAttachmentsWithMaxCount
NSExtensionActivationSupportsAttachmentsWithMinCount
NSExtensionActivationSupportsImageWithMaxCount
NSExtensionActivationSupportsMovieWithMaxCount
NSExtensionActivationSupportsWebPageWithMaxCount
NSExtensionActivationSupportsWebURLWithMaxCount
NSExtensionMainStoryboard 设置主界面的Storyboard,如果不想使用storyboard,也可以使用NSExtensionPrincipalClass指定自定义UIViewController子类名
NSExtensionPointIdentifier 扩展标识,在分享扩展中为:com.apple.share-services
NSExtensionPrincipalClass 自定义UI的类名
NSExtensionActivationSupportsAttachmentsWithMaxCount 附件最多限制,为数值类型。附件包括File、Image和Movie三大类,单一、混选总量不超过指定数量
NSExtensionActivationSupportsAttachmentsWithMinCount 附件最少限制,为数值类型。当设置NSExtensionActivationSupportsAttachmentsWithMaxCount时生效,默认至少选择1个附件,分享菜单中才显示扩展插件图标。
NSExtensionActivationSupportsFileWithMaxCount 文件最多限制,为数值类型。文件泛指除Image/Movie之外的附件,例如【邮件】附件、【语音备忘录】等。

单一、混选均不超过指定数量。
NSExtensionActivationSupportsImageWithMaxCount 图片最多限制,为数值类型。单一、混选均不超过指定数量。
NSExtensionActivationSupportsMovieWithMaxCount 视频最多限制,为数值类型。单一、混选均不超过指定数量。
NSExtensionActivationSupportsText 是否支持文本类型,布尔类型,默认不支持。如【备忘录】的分享
NSExtensionActivationSupportsWebURLWithMaxCount Web链接最多限制,为数值类型。默认不支持分享超链接,需要自己设置一个数值。
NSExtensionActivationSupportsWebPageWithMaxCount Web页面最多限制,为数值类型。默认不支持Web页面分享,需要自己设置一个数值。

对于不同的应用里面有可能出现只允许接受某种类型的内容,那么Share Extension就不能一直出现在分享菜单中,因为不同的应用提供的分享内容不一样,这就需要通过设置NSExtensionActivationRule字段来决定Share Extension是否显示。例如,只想接受其他应用分享链接到自己的应用,那么可以通过下面的步骤来设置:

  1. 将NSExtensionActivationRule字段类型由String改为Dictionary。
  2. 展开NSExtensionActivationRule字段,创建其子项NSExtensionActivationSupportsWebURLWithMaxCount,并设置一个限制数量。

调整后如下图所示:

Info.plist

2.3 处理Share Extension中的数据

其实在Share Extension中默认都会有一个数据展现的UI界面。该界面继承SLComposeServiceViewController这个类型,如:

@interface ShareViewController : SLComposeServiceViewController

@end

其展现效果,如图:

分享界面

顶部包括了标题、取消(Cancel)按钮和提交(Post)按钮。然后下面跟着左边就是一个文本编辑框,右边就是一个图片显示控件。那么,每当用户点击取消按钮或者提交按钮时,都会分别触发下面的方法:

/**
 *  点击取消按钮
 */
- (void)didSelectCancel
{
   
    [super didSelectCancel];
}

/**
 *  点击提交按钮
 */
- (void)didSelectPost
{
   
    // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.

    // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
    [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}

在这两个方法里面可以进行一些自定义的操作。一般情况下,当用户点击提交按钮的时候,扩展要做的事情就是要把数据取出来,并且放入一个与Containing App(** 容器程序,尽管苹果开放了Extension,但是在iOS中extension并不能单独存在,要想提交到AppStore,必须将Extension包含在一个App中提交,并且App的实现部分不能为空,这个包含Extension的App就叫Containing app。Extension会随着Containing App的安装而安装,同时随着ContainingApp的卸载而卸载。**)共享的数据介质中(包括NSUserDefault、Sqlite、CoreData),要跟容器程序进行数据交互需要借助AppGroups服务,下面的章节会对这块进行详细说明。下面先来看看怎么获取扩展中的数据。

在ShareExtension中,UIViewController包含一个extensionContext这样的上下文对象:

@interface UIViewController(NSExtensionAdditions) <NSExtensionRequestHandling>

// Returns the extension context. Also acts as a convenience method for a view controller to check if it participating in an extension request.
@property (nullable, nonatomic,readonly,strong) NSExtensionContext *extensionContext NS_AVAILABLE_IOS(8_0);

@end

通过操作它就可以获取到分享的数据,返回宿主应用的界面等操作。我们可以先看一下extensionContext的定义。

NS_CLASS_AVAILABLE(10_10, 8_0)
@interface NSExtensionContext : NSObject

// The list of input NSExtensionItems associated with the context. If the context has no input items, this array will be empty.
@property(readonly, copy, NS_NONATOMIC_IOSONLY) NSArray *inputItems;

// Signals the host to complete the app extension request with the supplied result items. The completion handler optionally contains any work which the extension may need to perform after the request has been completed, as a background-priority task. The `expired` parameter will be YES if the system decides to prematurely terminate a previous non-expiration invocation of the completionHandler. Note: calling this method will eventually dismiss the associated view controller.
- (void)completeRequestReturningItems:(nullable NSArray *)items completionHandler:(void(^ __nullable)(BOOL expired))completionHandler;

// Signals the host to cancel the app extension request, with the supplied error, which should be non-nil. The userInfo of the NSError will contain a key NSExtensionItemsAndErrorsKey which will have as its value a dictionary of NSExtensionItems and associated NSError instances.
- (void)cancelRequestWithError:(NSError *)error;

// Asks the host to open an URL on the extension's behalf
- (void)openURL:(NSURL *)URL completionHandler:(void (^ __nullable)(BOOL success))completionHandler;

@end

// Key in userInfo. Value is a dictionary of NSExtensionItems and associated NSError instances.
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionItemsAndErrorsKey NS_AVAILABLE(10_10, 8_0);

// The host process will enter the foreground
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionHostWillEnterForegroundNotification NS_AVAILABLE_IOS(8_2);

// The host process did enter the background
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionHostDidEnterBackgroundNotification NS_AVAILABLE_IOS(8_2);

// The host process will resign active status (stop receiving events), the extension may be suspended
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionHostWillResignActiveNotification NS_AVAILABLE_IOS(8_2);

// The host process did become active (begin receiving events)
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionHostDidBecomeActiveNotification NS_AVAILABLE_IOS(8_2);

NSExtensionContext的结构比较简单,包含一个属性和三个方法。其说明如下:

方法 说明
inputItems 该数组存储着容器应用传入给NSExtensionContext的NSExtensionItem数组。其中每个NSExtensionItem标识了一种类型的数据。要获取数据就要从这个属性入手。
completeRequestReturningItems:
completionHandler:
通知宿主程序的扩展已完成请求。调用此方法后,扩展UI会关闭并返回容器程序中。其中的items就是返回宿主程序的数据项。
cancelRequestWithError: 通知宿主程序的扩展已取消请求。调用此方法后,扩展UI会关闭并返回容器程序中。其中error为错误的描述信息。
NSExtensionItemsAndErrorsKey NSExtensionItem的userInfo属性中对应的错误信息键名。

类的下面还定义了一些通知,这些通知都是跟宿主程序的行为相关,在设计扩展的时候可以根据这些通知来进行对应的操作。其说明如下:

通知名称 说明
NSExtensionHostWillEnterForegroundNotification 宿主程序将要返回前台通知
NSExtensionHostDidEnterBackgroundNotification 宿主程序进入后台通知
NSExtensionHostWillResignActiveNotification 宿主程序将要被挂起通知
NSExtensionHostDidBecomeActiveNotification 宿主程序被激活通知

2.3.1 从inputItems中获取数据

inputItems是包含NSExtensionItem类型对象的数组。那么,要处理里面的数据还得先来了解一下NSExtensionItem的结构:

@interface NSExtensionItem : NSObject<NSCopying, NSSecureCoding>

// (optional) title for the item
@property(nullable, copy, NS_NONATOMIC_IOSONLY) NSAttributedString *attributedTitle;

// (optional) content text
@property(nullable, copy, NS_NONATOMIC_IOSONLY) NSAttributedString *attributedContentText;

// (optional) Contains images, videos, URLs, etc. This is not meant to be an array of alternate data formats/types, but instead a collection to include in a social media post for example. These items are always typed NSItemProvider.
@property(nullable, copy, NS_NONATOMIC_IOSONLY) NSArray *attachments;

// (optional) dictionary of key-value data. The key/value pairs accepted by the service are expected to be specified in the extension's Info.plist. The values of NSExtensionItem's properties will be reflected into the dictionary.
@property(nullable, copy, NS_NONATOMIC_IOSONLY) NSDictionary *userInfo;

@end

// Keys corresponding to properties exposed on the NSExtensionItem interface
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionItemAttributedTitleKey NS_AVAILABLE(10_10, 8_0);
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionItemAttributedContentTextKey NS_AVAILABLE(10_10, 8_0);
FOUNDATION_EXTERN NSString * __null_unspecified const NSExtensionItemAttachmentsKey NS_AVAILABLE(10_10, 8_0);

NSExtensionItem包含四个属性

属性 说明
attributedTitle 标题。
attributedContentText 内容。
attachments 附件数组,包含图片、视频、链接等资源,封装在NSItemProvider类型中。
userInfo 一个key-value结构的数据。NSExtensionItem中的属性都会在这个属性中一一映射。

对应userInfo结构中的NSExtensionItem属性的键名如下:

名称 说明
NSExtensionItemAttributedTitleKey 标题的键名
NSExtensionItemAttributedContentTextKey 内容的键名
NSExtensionItemAttachmentsKey 附件的键名

从上面的定义可以看出除了文本内容,其他类型的内容都是作为附件存储的,而附件又是封装在一个叫NSItemProvider的类型中,其定义如下:

typedef 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS中,我们可以使用Action Extension扩展应用程序的功能。Action Extension是一种允许用户在其他应用程序中执行特定操作的扩展,例如分享内容、保存信息等。 要创建Action Extension扩展,可以按照以下步骤进行操作: 1. 在Xcode中打开你的应用程序项目。 2. 在左侧导航栏中选择项目的名称,打开项目设置。 3. 在顶部菜单栏中选择"Target"。 4. 点击页面下方的"+"按钮,选择"Action Extension"作为新的目标。 5. 输入Extension的名称,例如"ShareExtension",然后点击"Finish"。 6. Xcode会自动生成一些默认的文件和设置,你可以根据需求进行修改。 7. 打开"Info.plist"文件,配置Action Extension的一些基本信息,例如名称、图标等。 8. 在Action Extension的代码文件中,你可以获取分享的内容,并进行相应的处理。 9. 你还可以在Action Extension中添加自定义的界面,使用户能够更方便地进行操作。 10. 编译并运行你的应用程序,可以选择其他应用程序中的内容,然后在分享菜单中找到你的Action Extension,执行相应的操作。 需要注意的是,为了使Action Extension正常工作,还需要在应用程序设置中配置一些权限和共享数据的支持。你可以在"Capabilities"选项卡中设置对应的权限和所需的共享数据类型。 创建完Action Extension后,你可以将其与应用程序打包在一起分发,用户可以通过在其他应用程序中选择分享菜单来使用你的Action Extension。 总的来说,创建iOS中的Action Extension扩展是一个相对简单的过程,通过使用Action Extension,你可以方便地为你的应用程序提供更多的功能和交互方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值