从iOS 8起,就有了App Extension。Extension的种类至今也扩充到了19种,应用也很广泛,值得重点关注起来。

Extension几乎可以看做一个内嵌的独立App,拥有独立的BundleID、证书、概要配置文件、进程空间、沙盒等等。只是需要打包在App内,类似于寄生在宿主App内,捆绑安装。不过一旦安装应用后,扩展可以由系统独立调用,执行扩展内的代码逻辑。

这篇只记录之前开发Today Extension的过程中,值得注意的事项。其实大多都是通用的。

1.创建Extension和证书管理

在已创建的项目中,新建File->New->Target->Today Extension,确定名称后,就可以在工程文件的Targets列表中,看到新建的extension。

在General栏可以看到,Extension有独立的Identity内容,Bundle Identifier一般具有宿主应用的Bundle Identifier前缀。如果使用Xcode8的自动管理证书,并登录了开发者账号,可以在开发者中心看到自动创建的该AppID。

接着为该AppID创建Provisioning files即可。

2.MainInterface.storyboard和主要的类

新创建的Extension与App的主Target分别在不同的文件目录下,彼此隔离。主界面、Info.plist和本地化文件等都是单独管理的,所以可创建并修改InfoPlist.strings的本地化文件中CFBundleDisplayName字段,单独为扩展命名,如果不修改,将默认使用宿主App的显示名称。

扩展和宿主App是隔离的,不能使用彼此的类、框架、资源,如果想使用宿主的类库或者资源文件等,最直接的办法就是拷贝到当前Target或者增加需要Link的框架。不过,查看Extension的Build Settings,Prefix Header可以填写宿主App的Prefix Header,并使用其引用头文件中的宏定义。

扩展默认使用了MainInterface.storyboard,并绑定了一个类TodayViewController,并已经创建了一个Hello World视图,我们可以直接使用并修改。但是如果不想使用storyboard或者需要修改启动类,可以将Info.plist文件中NSExtension字典的NSExtensionMainInterface项去掉,增加NSExtensionPrincipalClass项,value则为指定启动类的类名,例如TodayViewController。

3.生命周期

扩展的视图控制器与宿主的视图控制器一样,具有常见的生命周期方法。例如当第一次在下拉的“今日”列表中显示本应用扩展,则会执行viewDidLoad方法,然后依次执行其他方法;消失和再次出现,则会调用disappear和appear系列方法;即将被销毁时候,调用dealloc方法。

4.Today Extension的size

iOS10以后,重新规定了Today Extension的size。宽度是固定(例如在iPhone6上是359),所以无法改变;但是高度方面,提供了两种模式:

NCWidgetDisplayModeCompact:固定高度,则为110

NCWidgetDisplayModeExpanded:可以变化的高度,区间为110~616

使用如下代码可以修改模式:

  if ([[UIDevice currentDevice].systemVersion floatValue] >= 10) {

    self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;

}

我们可以在NCWidgetProviding协议的如下代理方法中,取到size的最大范围:

- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize NS_AVAILABLE_IOS(10_0);

用如下方法确定边距:

- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets NS_DEPRECATED_IOS(8_0, 10_0, "This method will not be called on widgets linked against iOS versions 10.0 and later.");

如果需要修改Widget展示的背景高度,可以修改属性:self.preferredContentSize

5.数据共享

既然扩展与宿主App是隔离的,那么数据共享就需要使用App Groups了。

在App主Target的Capabilities栏,找到App Groups项,开启功能,并点击“+”符号添加一个共享的数据容器名称,例如group.xxx。然后会发现主Target和扩展Target目录中都生成了一个entitlements类型文件,记录了一个App Groups项。

这个共享的容器,就是存放扩展和宿主App共用的数据的空间。

为了正常编译,还需要前往开发者中心,编辑主应用和扩展的AppID,开启支持App Groups功能,类似于开启推送功能。

配置完成后,就是使用了。不管是采用UserDefaults、Archive、CoreData、FMDB、LevelDB等哪种数据存储或操作方式,只需要将路径指向共享的容器路径就可以。

例如使用UserDefaults方式:

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

    [defaults setObject:@"xxxxx" forKey:@"phoneNum"];

只是打开了指定的UserDefaults对象,使用的实例方法为initWithSuiteName。

其他方式同理。

6.类库和资源共享

前面提到,扩展需要使用宿主Target的类库和资源,可以直接拷贝到扩展Target目录下,但是这样做会增加应用体积。

另一个方法,就是创建framework动态链接库。新建File->New->Target->Framework,得到一个新的Target,与系统的框架类似,我们可以自由添加类文件封装功能,只暴露public头文件供调用。在Build Phases栏的Headers项中,将Project组的头文件拖动到Public组即可。

framework也有Bundle ID,但是不需要关注,并且不需要配置证书。

需要注意的是,新建的动态链接库,一般会自动创建同名的头文件,可以直接在其中引用需要暴露的自定义类头文件。但是如果删除了该头文件,可能会有如下警告:

warning: no umbrella header found for target 'OrderFoodTodayKit', module map will not be generated

另外一个需要特别注意的地方,因为我们创建的动态链接库是需要提供给扩展使用的,而扩展不支持部分Api,所以该framework中就需要除去扩展不支持的部分Api。在framework的General栏的Deployment Info中,勾选Allow app extension API only。这样的话,如果在framework中使用了扩展不支持的Api,编译会报错。

7.Today Extension调起宿主App

如果需要从Today Extension中调起宿主App,可以使用宿主App的Url Scheme方式:

[self.extensionContext openURL:[NSURL URLWithString:@"xxxx://xxxx"] completionHandler:nil];

以上就是开发过程中,需要注意的事项记录。

完整的开发教程,推荐查阅:http://www.cocoachina.com/ios/20141023/10027.html

App Today Extension开发注意事项的更多相关文章

  1. 跨平台移动APP开发进阶(一)mui开发注意事项

    mui开发注意事项 Mui HTML5开发框架 mui是一个高性能的HTML5开发框架,从UI到效率,都在极力追求原生体验:这个框架自身有一些规则,刚接触的同学不很熟悉,特总结本文:想了解mui更详细 ...

  2. MUI开发注意事项

    mui开发注意事项,有需要的朋友可以参考下. mui是一个高性能的HTML5开发框架,从UI到效率,都在极力追求原生体验:这个框架自身有一些规则,刚接触的同学不很熟悉,特总结本文:想了解mui更详细的 ...

  3. Android Library开发注意事项

    Android Library开发注意事项 App Module添加依赖Android Library时可以设置library的优先级, 在编译时,app按照library从低到高的优先级依次与每个l ...

  4. 移动端App uni-app + mui 开发记录

    前言 uni-app uni-app是DCloud推出的终极跨平台解决方案,是一个使用Vue.js开发所有前端应用的框架,官网:https://uniapp.dcloud.io/ mui 号称最接近原 ...

  5. 【VS开发】ActiveX开发注意事项

    [VS开发]ActiveX开发注意事项 标签:[VS开发] 注意:必须在工程的app文件的InitInstance()中加入如下代码,否则动态创建控件不会成功: AfxEnableControlCon ...

  6. 使用IBM Blockchain Platform extension开发你的第一个fabric智能合约

    文章目录 安装IBM Blockchain Platform extension for VS Code 创建一个智能合约项目 理解智能合约 打包智能合约 Local Fabric Ops 安装智能合 ...

  7. uni-app开发注意事项

    关于vue 1.注意 如果使用老版的非自定义组件模式,即manifest中"usingComponents":false,部分模版语法不支持,但此模式已于2019年11月起下线. ...

  8. delphi 串口 关于RS485总线通信协议开发注意事项

    http://blog.csdn.net/shjhuang/article/details/9426739 关于RS485总线通信协议开发注意事项 1       前言 近段时间发现我们系统在进行设备 ...

  9. 实战使用Axure设计App,使用WebStorm开发(6) – 迈向后端

    系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求  实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目   实战使 ...

随机推荐

  1. java中map插入相同的key

    测试用例: package test; import org.junit.Test; import po.Person; import java.util.HashMap; import java.u ...

  2. 基于HT for Web的3D呈现A* Search Algorithm

    最近搞个游戏遇到最短路径的常规游戏问题,正巧看到老同事写的3D机房最短路径巡线文章,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现,算法基于开源 https://github.c ...

  3. 30天C#基础巩固-----值类型/引用类型,泛型,空合并操作符(??),匿名方法

    一:值类型/引用类型的区别      值类型主要包括简单类型,枚举类型,和结构体类型等,值类型的实例通常被分配在线程堆栈上面变量保存的内容是实例数据本身.引用类型被分配在托管堆上,变量保存的是地址.引 ...

  4. 优化MySchool数据库总结

  5. Servlet生命周期中的service方法分析

    问题ServletLifeCycle中的service方法内,有super.service(request, response); 会执行this.doGet(HttpServletRequest r ...

  6. 15天玩转redis —— 第八篇 你不得不会的事务玩法

    我们都知道redis追求的是简单,快速,高效,在这种情况下也就拒绝了支持window平台,学sqlserver的时候,我们知道事务还算是个比较复杂的东西, 所以这吊毛要是照搬到redis中去,理所当然 ...

  7. Repository 设计模式介绍

    在DDD设计中大家都会使用Repository pattern来获取domain model所需要的数据. 1.什么是Repository? "A Repository mediates b ...

  8. 反编译APK文件

    有时源代码丢失了,这时如果有apk文件的话,是可以对apk文件反编译得到源文件的,本文介绍一下简单的反编译apk文件的过程. 1.工具 反编译apk需要的工具有两个:apk2java和apktool, ...

  9. MSSQL N张表关联查询

    declare @newTime varchar(50); declare @lasetTime varchar(50); set @newTime= getdate(); set @lasetTim ...

  10. First day on cnblogs,破壳日~~

    突然很想找个地方写一点文章,又想到了这个老账号:没有因长期静默被删号实在是很感动...好吧,就这样纪念一下.第一天. I suddenly wanna write something and reca ...