Extension 与主app共享数据

    xiaoxiao2021-03-26  30

    http://www.tuicool.com/articles/UfI7vy6

    注意:一个说法----宿主应用和容器应用是一个东西(container app)

    扩展(Extension)是 iOS 8 和 OSX 10.10 中引入新功能,Extension 不会单独存在,它将做为 App 的附加功能出现,为 App 提供更好的交互体验。由此 Extension 和容器应用(Containing App)之间的数据共享在所难免。Apple 在它的 官方文档 中只是以 NSUserDefaults 举例做了介绍,然后丢了一句“ Use Core Data, SQLite, or Posix locks to help coordinate data access in a shared container.”就算完事儿了。下面就来介绍下具体如何操作。 

    Extension Target

    喵神在 WWDC 2014 Session笔记 – iOS 通知中心扩展制作入门 已经有了非常详尽的介绍,总之你需要在项目中添加一个 Application Extension Target( File > New Target > Application Extension > …),然后就可以从你非常熟悉的 view controller 开始编写 widget 代码了。 

    App Groups

    在默认情况下,Extension 是无法直接获取 Containing App 的数据的,但在 iOS 8 中我们可以通过开启 App Groups 以实现同一个 team 的 Apps 及其 Extension 之间的数据共享。开启 App Groups:

    在 Xcode 6 的 Targets 中选中主 App‘s Target,找到 Capabilities 标签 找到 App Groups 选项并展开,然后戳一下添加按钮 给你的 App Groups 起个名字,通常是 group.xxx 的格式,随后 Xcode 自动创建 .entitlements 授权文件,其中包含了共享容器的访问名称,并将此 App Group 登记在你的开发者账号下的,确保只有你的 team 的 app 可以使用这些共享容器  选中 Extension’s Target,重复以上操作,勾选刚才创建的 group 就可以了

    现在你把原来存在 App 沙箱中的数据改存在 这个 group 中就可以实现数据的共享了,在具体举例之前,你可能发现仅有数据好像还不够,比如你使用了 CoreData,还需要选中 .xcdatamodeld 文件和要用到的 model 文件,在 Xcode 的右侧工具栏中的找到 Target Membership 勾选 Extension 名,把它们加到 Extension Target 中。然后把 .xcdatamodeld 文件加到 Extension 的 Resource Bundle 里面: 

    Targets 中选中 Extension‘s Target,找到 Build Phase 标签 找到 Copy Bundle Resources 选项并展开,然后戳一下添加按钮 添加相应的 .xcdatamodel 文件 

    数据共享

    好了,一切准备就绪,把

    [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

    换成

    [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.xxx"]

    也就是让主 App 和 Extension 都去访问共享容器中的文件,从而实现数据的共享。现在“you can also use Core Data, or in some cases SQLite, to help coordinate data access in a shared container.”(捂嘴笑)

    如果是 NSUserDefaults 就是把 

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    换成

    NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.xxx"];

    http://www.jianshu.com/p/7f8472a97aa6

    ======================================================

    在整个通信过程中,难点在于宿主应用和应用扩展的数据共享,不仅仅是数据共享,可能还需要共享一些开发文件,比如类文件、xib、storyboard等。不要以为宿主应用和应用扩展同属于一个工程项目,它们两个就可以共同使用项目内的数据和所有文件。这是错误的。那么,宿主应用和应用扩展如何进行数据共享?我们需要创建一个共享域,当然,苹果早就给我们准备好了,我们只需要配置一下即可。

    1、配置共享域 (1)配置宿主应用共享域

    点击ON后,其实App Groups这里是空的,因为我之前做项目有配置过共享域,所以在选择证书的时候,系统会把证书配置过的共享域都给我自动加载了出来。如果这里是空的,就点击下面的+号,添加一个共享域。

    这时,Xcode会弹出提示框,让你给共享库起一个名字以辨别,因为有些项目可能需要不只一个共享域,如果项目支持Apple watch,就需要一个新的共享域支持Apple watch。共享域的名字以group.开头,名字自己起。

    OK,添加完共享域后,新的共享域就出现在了APP Groups中,选中它。

    到这里,宿主应用的共享域配置告一段落。

    (2)配置应用扩展

    点击ON后,系统会弹出提示框,让你选择证书,因为共享域是在证书的基础上配置的。证书选择后,会把对应的所有共享域显示在App Groups中。

    选中我们之前在宿主应用创建(选择)的共享域。

    OK,应用扩展的共享域配置完毕。

    2、数据共享 (1)NSUserDefaults

    NSUserDefaults *userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.testAppExtension"]; 获取共享域的偏好设置

    接下来平时怎么用这里就怎么用。 (2)数据库 在创建应用扩展前,数据库我是放到这个路径下的。

    [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"TestDB.sqlite"]

    而现在,即使共享域配置完毕,应用扩展继续访问这个路径下的数据库也是访问不到的,因为共享域它有自己的路径。宿主应用和应用扩展之间的空间关系如下:

    所以,我们要将数据库放在共享域的路径下。共享域的路径如下:

    [[[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.testAppExtension"] absoluteString] stringByAppendingPathComponent:@"TestDB.sqlite"] 通过containerURLForSecurityApplicationGroupIdentifier方法和共享域标识符我们可以获取到该共享域的路径

    OK,共享数据到这里暂告一段落。

    共享类文件

    创建一个Framework文件,让Framework文件引用这些需要共享的类,再让宿主应用和应用扩展分别导入Framework文件。这样做就很好的解决了问题,还不容易出错,也便于后期维护。

    1、创建framework文件

    framework文件的命名规范一些,以Kit为结尾。

    创建完framework后工程目录如下

    2、引用文件 (1)先把宿主应用target的文件引用删除,因为应用扩展同样要使用FMDB,所以也要把第三方文件从target中删除,否则编译照样会报错。

    (2)增加AppExtensionKit的引用文件

    需要注意的是,在这里不要添加xib文件,xib在哪修改下面会说。

    (3)为应用扩展导入AppExtensionKit文件

    添加完后编译一下,报错,40多个。 这是因为应用扩展也要用到libsqlite3.0.tbd这个包,但是并没有为应用扩展添加这个包,所以,重复上面的操作,把libsqlite3.0.tbd加入到AppExtensionKit中。

    再编译一下,错误全部消失不见。OK,配置全部完成。

    共享xib文件

    PasswrodCell是从xib加载的,但我们并没有把xib文件加入到AppExtensionKit中。知道问题出在哪了,去解决。

    在宿主应用的target中,找到PasswordCell的引用并删除。如下:

    操作完后,xib文件从原来bundle下的路径变成了bundle下AppExtensionKit下的路径。

    做完这些还不够,我们还要在ExtensionDemo和PasswordAppExtension两个target下的Copy Bundle Resources中将AppExtensionKit导入进来,否则宿主应用和应用扩展还是用不了PasswordCell.xib。如图:

    ExtensionDemo的target:

    那我们再次加载Password.xib文件,就需要从Bundle下的AppExtensionKit文件中加载。 加载方式代码如下:

    cell = [[NSBundle mainBundle] loadNibNamed:@"AppExtensionKit.framework/ExtensionCell" owner:nil options:nil].lastObject;
    转载请注明原文地址: https://ju.6miu.com/read-663936.html

    最新回复(0)