IOS 8 新特性探索

ios 8已经发布了8.1版本,新增了大量API, 涵盖健康、运动、游戏、分享、智能家居等众多领域;对开发者而言,苹果整个生态体系将变得更加开放和和友好,本文就从App Extension、动态Framework以及变化的API三个方面对IOS8进行探索,如有错误,欢迎大家拍砖、斧正。

App Extension

App ExtensionIOS 8 中提供的一种新功能。它是一种对系统固定区域进行扩展的机制;通过App Extension,可以为用户提供在其它应用中使用第三方服务的快捷方式,同时使得第三方应用之间的数据称为可能。

一、关键概念

App Extension Programming 中有几个关键概念:

1. Extension point

IOS 将系统分为几个不同的Extension Point,以此区分extension的类别。每种extension point的功能和使用方式都不一样。目前系统支持6种类型,并分别提供了相应的创建模板,他们分别是:

1Today

又叫widget,在通知中心的今日栏目展示小工具。

2)Share

提供基于Web或者其它应用的内容分享,插件出现在系统的分享菜单中。

3)Action

为当前App视图提供额外的处理、展示功能。

4)Photo Editing

提供Photos app内对照片的编辑功能。

5)Storage Provider

IOS app可以共享的数据。通过Document picker提供,通过Documents可以方便地在app间进行数据共享。

6)Custom Keyboard

自定义系统键盘,以便提供不同的输入法和布局,并在整个系统中使用。

2. App Extension

Extension 有独立的bundle,后缀名是.appex,但它并不是一个独立的app,并不能单独存在,必须有一个包含它的Containing app才能上传到appStore进行分发和安装;它随着Containing app的安装而安装、卸载而卸载。

Extension的使用必须通过用户手动开启。不同的extension开启方式也不尽相同,通常情况下在当前应用环境中激活,或者在设置中激活。开发者通过设置Activation Rule,使得extension出现在合适的位置(详见NSExtensionActivationRule)。

3. Containing App

即包含extensionapp。该app除了extension外,还必须具备其它的功能。

4. Host App

调用extensionapp称为host app

二、工作原理

1.生命周期

插件的生命周期独立于app,由系统负责生成和释放,如图1所示:

1 插件生命周期

当用户在host app内对extension发起请求时,系统对extension进行初始化,并建立host appextension间的通信。extension根据host app请求上下文环境,执行相关的任务,并返回结果。一旦任务完成,或者用户取消任务,或者开启了一个长时间的后台任务,系统便立即结束extension

2. 通信关系

IOS中插件涉及到三个角色,即extensionhost appcontaining app

1)extensionhost app通信、

Extensionhost app间可以直接通信,如图2

2 host app extension通信

这主要是通过extensionContext属性完成的,它是UIViewController的一个类别。

实际上extensionhost app的通信是通过IPC机制完成的,不过开发者并不需要关心, 通过高度抽象的接口NSExtensionContextNSExtensionRequestHandling就能很好地完成extensionhost app间的通信和交互。Extension中应当显示地使用这两个接口,告知host app任务的执行结果。

2)host app containing app通信

host app containing app之间没有直接关系,也不需要直接通信。他们之间的交互需要通过 extension,如图3所示:

3 host appextensioncontaining app间接通信

3)extensioncontaining app通信

虽然extensionbundle放在containing appbundle中,但是由于extension是采用不同的target生成的,他们是两个完全不同的独立进程,因此不能直接通信。只能通过一个被称为Share resources的方式间接交换数据。

实际上,Shared resources 是通过App Group实现的,它主要用于相同group下的app共享存储空间,从而便于交换数据。通过在target->Capabilities->app groups, 可以进行设置。这种数据交换方式可以由图4描述:

4 Share resource数据交换方式

读写数据可以通过NSUserDefaultNSFileManager完成,指明响应的group id即可,如图5

5 共享数据读写

需要注意的是,由于多个进程对共享区域同时具有读写权限,因此应当注意数据同步问题,可以采用NSFileCoordinatorNSFilePresenter中相关的接口对数据读写进行保护。或者采用Core Data或者SQLite等方式操作数据。

三、实践

总体来说App extension入门还是相对比较简单,只需要新建一个工程,然后通过菜单File->New Target->Application Extension 就可以基于模板创建对应的extension,如图6

6 基于模板创建extension

创建一个基于Action extension,完成后,可以在联系人分享中使用,如图7

Action Extension使用示意

但是调试的过程并不理想,虽然官方指出extension的调试与普通app调试并无差别,但在实验的过程中始终无法进行断点调试,NSlog也有一些问题,可能是还未修复的bug

此外,在开发的过程中需要注意以下问题:

1. 代码共享

在开发extension的过程中,难免会出现Containing Appextension需要共享业务代码的情况,ios 8提供的Framework机制可以很好地解决这个问题。需要注意的是,要保证Framework并不含有受限API,即NS_EXTENSION_UNAVAILABLE标注的API,否则导致extension链接时失败。

2. 长间任务

通常情况下,用户在extension中执行完操作后,需要尽快返回host app。如果extension涉及到上传、下载等需要较长时间才能完成的任务,就应当使用NSURLSession提供后台Session,从而保证即使在extension生命结束的情况下,任务也能顺利完成。当后台session完成时。如果extension生命周期已经结束,系统将在后台启动containing app 并调用接口application:handleEventsForBackgroundURLSession:completionHandler:

后台Session的执行需要建立Group app,也就是前面说的extensioncontaining app共享读写的shared container。后台任务主要由NSURLSessionNSURLSessionConfiguration以及NSURLSessionTask完成。

其中Session Identifier需要保证唯一,sharedContainerIdentifier 即是创建的group app标志。

后台Session的使用需要注意以下几点:

1. 同一时刻,每个后台Session只能由一个进程访问。官方的建议是containing app只使用由extension创建的后台session,如果containing app 有其他网络相关的任务,应当创建不同的session

2. 尽管在extension中创建后台session完成上传、下载等任务,但并不支持其它类型的后台任务,如voip、后台音乐等。

3. extension 对于其他的耗时任务似乎并没有更好的方式,由于返回host app后其生命周期会马上结束,因此,对于其它类型的耗时任务,只能在任务完成后,再调用completeRequestReturningItems:completionHandler:

四、总结

App extension可以说是IOS8中最重要的革新之一,将极大第丰富产品形态,同时也代表着IOS更为开放的态度。目前来看,IOS还并没有将这一全新的跨进程通信机制开放出来,只能在系统划分的基础上对系统APP进行扩展,要是能够开放整套通信体系,使得遵循协议的所有第三方APP都可以被扩展就好了。

参考

1. App Extension Programming Guide

2. 苹果的插件生态系统,开发者的新世界

3. http://www.cocoachina.com/applenews/devnews/2014/0627/8960.html

Framework

一、概念

ios8之前,程序中能够通过两种方式使用库文件,即.aframework.a是静态库的方式,framework本质上也是静态库的方式,只不过为了方便,将其打包为假的动态库。真正的动态库在ios8之前是不被支持的。

静态和动态是相对于编译期和运行期而言的。静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要该静态库;而动态库在程序编译时并不会被链接到目标代码中,只是在程序运行时才被载入,因为在程序运行期间还需要动态库的存在。因此,动态库具有以下好处:

1. 降低可执行文件大小。由于并不需要在在编译器链接到目标代码,因此可以降低可执行文件的大小。

2. 节省资源,多个应用程序共享内存中同一份库文件。

3. 便于程序动态升级。在不需要重新编译链接可执行程序的条件下,就能到达更新应用程序的目的。

从目前apple发布的beta版来看,ios8将正式支持用户自定义framework,这很可能会改变ios只支持静态库联编的现状,在官方文档中,对于framework是这样描述的:

Frameworks for iOS iOS developers can now create dynamic frameworks. Frameworks are a collection of code and resources to encapsulate functionality that is valuable across multiple projects. Frameworks work perfectly with extensions, sharing logic that can be used by both the main application, and the bundled extensions.

Xcode 6beta版中也提供了动态库的创建模板:

不过,从目前官方文档来看,由于沙盒机制,ios仍然不允许进程间动态库的共享,因为只能讲动态库纺织在应用程序的沙盒中。不过,app extension应该并不受此限制,完全可以通过将动态库放置在shared container中的方式,实现动态库的共享。

二、 动态库demo

1.动态库的创建

ios中,创建framework比之前要容易得多了,可以直接使用模板创建framework工程。创建完成后,添加共享的代码,及实现,然后设置公开的头文件,再run一次即可。

2. 创建通用库

然而,这样创建完成的库并不能同时在手机和模拟器上使用,要创建通用的动态库,还是需要我们像之前制作假的framework一样,写脚本完成,只是相比之下,同样简单很多。只需要以下简单的几步:

1. 创建通用target,通过模板为新建的库创建一个新的Aggregate Target

2. 设置targetTarget Dependencies,选择新建的动态库就好。

3. 添加run script脚本

添加的脚本也是之前创建假的动态库经常用到的脚本,不过要简单得多,只需要完成三件事即可:

1)分别编译生成手机和模拟器的framework

2)使用lipo命令将生成的framework合成一个新的framework

3)将生成的通用framework放在工程的Products目录下。

4. 运行一下CommonDynamicTest target即可,生成的动态库如下:

3. 动态库的使用

为了测试动态库的使用,我们新建DynamicDemo工程。与普通的静态库不同,动态库的使用不仅需要在Build Phases中设置Link Binary,同时需要将framework作为资源文件拷贝到工程的bundle中。否则会因为动态库无法加载而出现crash

我们通过调用framework中的代码,测试库是否正常。

测试结果显示调用正常

这是我们通常使用framework的方式,即程序一启动就链接到framework。为了测试framework的动态加载是否也ok,我们将测试frameworkLink Binary中删除,并尝试以bundledlopen的方式进行加载。

1bundle方式

首先,我们看bundle加载和卸载的方式,加载和卸载的代码为:

我们将动态库放在了bundle中,因此,直接从main bundle中加载:

从测试的结果看,在动态加载前,不能使用动态库中的代码和资源,加载后,可以正常使用。

比较奇怪的是在bundle卸载后,动态库依然能够使用,不知道是不是模拟器的bug?。

2dlopen方式

dlopen是一个强大的系统库函数。可以用它打开一个库装载到内存,可以以指定的模式打开,使用完后,可以关闭。

由于动态库中真正执行的为dynanicTest.framework/dynanicTest文件,因此使用dlopen动态加载时需要指定全路径,否则无法成功。

测试显示可以成功加载,加载后能够正常使用,同时也能卸载,不过比较奇怪的是,一次加载需要对应两次卸载,才能将动态库从内存中清除掉,这难道也是bug

需要注意的是,采用动态加载库的方式时,并不能直接使用其中的类,需要通过反射的方式,否则会导致错误。

三、 思考

IOS动态framework的机制给开发者极大的想象空间,实现真正的插件,动态升级似乎都再是遥远的事情。不过,在实验的过程中,还是遇到诸多问题,采用dlopen加载动态库的方式,苹果官方并没有正式的许可,不过总的来说ios新的framework机制还是给我们更多尝试的几乎,制作framework也不再需要以前那样繁琐啦。

参考

https://developer.apple.com

Framework Programming Guide

http://www.cnblogs.com/pengyingh/articles/2405652.html ios framework

IOS 8 API 变化

IOS 8新增4000多个API, 涵盖认证、健康、智能家居、游戏、家庭分享等多个方面。与IOS 7.1相比变化明显,本文仅对常用的API变化进行介绍,更详细的API变化可以参考苹果官网

一、语言变化

IOS 8中,除引入新的开发语言swift外,objective-c本身的变化并不大,根据官方的说法,这些变化使得OC更加现代化、安全和高效。主要的变化有:

1. instancetype取代id

从官方API变化文档中,可以看到OC中原来返回id的接口,如allocinitautorelease等接口都用intancetype替代了,主要是基于OC代码类型安全的考虑。不过需要注意的是 instancetype只能作为返回值。

instancetype相对于id作为返回值的好处在于编译器可以帮我们做类型检查,并给出警告。其实instancetypeios8之前也已经大量使用了。



2. properties取代gettersetter方法

Propertiesios中早就大量使用的技术,它具有以下好处:

1)自动生成gettersetter方法,保证配对。

2)语义更明确

3)通过对property增加attribute如,copyassignautomic等可以完成额外的行为,表达更多的信息。

其实这些都不是新的东西,根据实际情况灵活使用即可。不过官方也明确表明这些变化将更利于和swift交互。

此外,OC中对block部分有较多的补充,增加了dispatch_block_flags, 修改了dispatch等相关接口,详细见官方文档

二、UIKit 变化

UIKit是我们使用最多的一个系统组件。其主要的变化有:

1. local或者push通知,需要通过UIUserNotificationSetting明确指明提醒的类型,并获得用户授权。从SDK中可以看到UIApplication提供了一个新的类别接口用于通知注册:

IOS中,开发者将可以为local或者push通知定制额外的行为,在提醒上表现为一个额外的按钮;点击按钮后,可以响应定制的行为,响应的接口为:

才外,Local通知可以被地理位置触发。

2. 集合UICollectionView将支持动态改变单元的大小,也支持通过选项对布局的部分刷新,从而保证性能。

3. UISearchController将替代UISearchDisplayController,从代码上看,使用要简单得多,并且支持设置背景暗光状态、更新搜索内容等。

4. UISplitViewController提供了对iPhone的支持,这似乎是暗示大屏iPhone即将来临么?

5. UINavigationController可以改变大小了,并支持手势隐藏。

6. UIVisualEffect支持自定义blur效果了,貌似我们还没用到过。

7. 新增UIAlterController用于取代UIActionSheetUIAlertView,可以更加灵活地进行定制了。

8. IOS中将可以直接跳转到和app相关的设置项了,使用UIApplicationopenURL并传递参数UIApplicationOpenSettingsURLString即可完成。

三、PushKit

IOS中新增了Pushkit.framework,主要有四个类,PKPushRegistryPKPushPayloadPKPushCredentialsPKPushRegistryDelegate。从SDK的说明中可以看出,pushkit主要将用来注册第三方的通知,并对通知进行响应,目前只支持PKPushTypeVoIP类型。他们的关系为:

SDK里面的注释外,官方没有更多的介绍和说明,目前并不清楚可以如何使用。Pushkit是否可能成为令一种第三方通信通道,从其设计的方式看,PushPayload将能够传递更多的数据。

四、音视频相关

和音频相关的MediaPlayerMediaMoviePlayController等都有一些变化,增加了更多的元数据信息获取接口。详情见官方文档。此外,IOS8 AVFoundation.framework中,增加了AVAudioEngine等接口,提供对硬件设备更抽象的访问方法,包括音频输入、输出、录音、播放、音频解析、混音等。VideoToolBox.framwork加入到了IOS8中用于支持更底层的视频编、解码。

五、NotificationCenter

这个NotificationCenter并不是指我吗之前一直使用的通知,这个是IOS 8中新提供的一个framework,与之对应的还有NotificationUI framework, 不过后者还完全是空的。NotificationCenter主要提供对ios通知栏的管理,这个Today App extension不无关系。目前该组件中,主要有NCWidgetControllerNCWidgetProviding两个类,前者主要负责自定义插件在通知栏的显示、隐藏;后者则是实现Today App extension需要遵循的协议,现在主要提供两个方法,分别用于控制显示视图和更新视图。

其它新加入的framework还有支持Touch IDLocalAuthentication,支持健康appHeathKit、支持智能家居的HomeKit,支持VPNNetworkExtension等。在此,不再一一列举,详见官方文档。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。