iOS:应用程序扩展开发之Today扩展(Today Extesnsion)
<p><span style="font-size: 16px; font-family: 楷体"><strong>一、简介</strong></span></p><p><span style="font-size: 15px; font-family: 楷体">iOS应用程序扩展是苹果在iOS8推出的一个新特性,可以将自定义的功能和内容扩展到应用程序之外,在之后又经过不断地优化和更新,已经成为开发中不可或缺的功能之一。扩展也是一个Target项目,它运行在主机应用程序上,可以与主机应用程序实现资源共享,和宿主应用程序的Target项目是彼此独立的。系统提供的扩展有很多,Toady扩展就是其中之一,也被成为应用程序插件,它的作用是将今日发生的简单消息展示在系统的插件界面上。Toady扩展模板名称为Today Extension。图1是创建Today扩展,图2是扩展显示在插件界面上(可以通过点击Edit来添加或者移除扩展)。 </span><span style="font-family: 楷体"><span style="font-size: 15px"><br></span></span></p>
<p><img src="https://img2018.cnblogs.com/blog/791499/201911/791499-20191120132900974-1370460397.png"></p>
<p> </p>
<p><span style="font-size: 16px; font-family: 楷体"><strong>二、创建</strong></span></p>
<p><span style="font-size: 15px; font-family: 楷体">按照上图1的方式创建一个Today Extension的Target后,系统会默认帮我们生成一个</span><span style="font-size: 15px; font-family: 楷体">TodayViewController控制器类、MainInterface.storyBoard故事板、plist序列化文件,文件结构图如下:</span></p>
<p><img src="https://img2018.cnblogs.com/blog/791499/201911/791499-20191120133948393-464574678.png"></p>
<p><span style="font-size: 15px; font-family: 楷体">上图中红色圈内和箭头指向的配置就是系统通过MainInterface.storyBoard帮我们实现了一个基本的Toady插件UI布局,运行后可以直接显示在插件界面上。可是,有的时候开发者并不想使用系统的故事板来构建UI,系统支持自定义的,我们只需要修改plist配置即可。具体的配置是这样的:</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)"> 将NSExtensionMainStoryboard字段删除;</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)"> 添加NSExtensionPrincipalClass字段,修改value为控制器的类名。 </span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)"> 在TodayViewController中的ViewDidLoad中设置preferredContentSize属性大小,用来调整widget界面UI的尺寸。</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(0, 0, 0, 1)">配置如下图所示:</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)"><img src="https://img2018.cnblogs.com/blog/791499/201911/791499-20191120135032509-1363294602.png"></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置尺寸</span>
self.preferredContentSize = CGSizeMake(.bounds.size.width, <span style="color: rgba(128, 0, 128, 1)">300</span>); </pre>
</div>
<p> </p>
<p><span style="font-family: 楷体; font-size: 16px"><strong>三、分析</strong></span></p>
<p><span style="font-family: 楷体; font-size: 15px">TodayViewController类比较简单,就是一个VC类,它实现了系统提供的一个扩展协议<NCWidgetProviding>,可以在协议方法中实现对扩展的更新和状态监控。</span></p>
<p><span style="font-family: 楷体"><span style="font-size: 15px">协议如下,都是可选的,开发者根据需要进行重写。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">协议</span>
<span style="color: rgba(0, 0, 255, 1)">@protocol</span> NCWidgetProviding <NSObject><span style="color: rgba(0, 0, 0, 1)">
@optional
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当数据更新时调用的方法,系统会定期更新扩展</span>
- (<span style="color: rgba(0, 0, 255, 1)">void</span>)widgetPerformUpdateWithCompletionHandler:(<span style="color: rgba(0, 0, 255, 1)">void</span> (^<span style="color: rgba(0, 0, 0, 1)">)(NCUpdateResult result))completionHandler;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听显示模式(宽松型、紧奏型)和尺寸的改变,其中宽松和紧凑表示的是展开和折叠状态, iOS10开始才能使用</span>
- (<span style="color: rgba(0, 0, 255, 1)">void</span>)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize __API_AVAILABLE(ios(<span style="color: rgba(128, 0, 128, 1)">10.0</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置扩展UI边距,注意:使用StoryBoard时,若要所见即所得,则这个方法中需要返回UIEdgeInsetsZero; (iOS10 and later 不会再被调用,弃用了)</span>
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets __API_DEPRECATED(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">This method will not be called on widgets linked against iOS versions 10.0 and later.</span><span style="color: rgba(128, 0, 0, 1)">"</span>, ios(<span style="color: rgba(128, 0, 128, 1)">8.0</span>, <span style="color: rgba(128, 0, 128, 1)">10.0</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 0, 255, 1)">@end</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">扩展,都是iOS10开始才能使用</span>
<span style="color: rgba(0, 0, 255, 1)">@interface</span><span style="color: rgba(0, 0, 0, 1)"> NSExtensionContext (NCWidgetAdditions)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置widget折叠或展开状态</span>
@property (nonatomic, assign) NCWidgetDisplayMode widgetLargestAvailableDisplayMode __API_AVAILABLE(ios(<span style="color: rgba(128, 0, 128, 1)">10.0</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">只读,widget状态</span>
@property (nonatomic, assign, <span style="color: rgba(0, 0, 255, 1)">readonly</span><span style="color: rgba(0, 0, 0, 1)">) NCWidgetDisplayMode widgetActiveDisplayMode __API_AVAILABLE(ios(</span><span style="color: rgba(128, 0, 128, 1)">10.0</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取widget不同状态的尺寸</span>
- (CGSize)widgetMaximumSizeForDisplayMode:(NCWidgetDisplayMode)displayMode __API_AVAILABLE(ios(<span style="color: rgba(128, 0, 128, 1)">10.0</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 0, 255, 1)">@end</span></pre>
</div>
<p> </p>
<p><span style="font-size: 16px; font-family: 楷体"><strong>四、交互</strong></span></p>
<p><span style="font-size: 15px; font-family: 楷体">Today扩展是寄宿于主机应用程序上的, TodayViewController又是一个UIViewController类,系统支持Today扩展对UIViewController进行切换。也就是说,苹果在考虑提供给开发者在对UIViewController中添加各种展示控件这种便利的同时,也相应的提供给开发者通过Today扩展的widget从主机应用程序激活并打开宿主应用程序的机会。不过这个操作必须通过设置并调起scheme来实现。</span><span style="font-size: 15px; font-family: 楷体">步骤如下:</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)"> 配置宿主应用程序的scheme;</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)"> 使用扩展的openURL打开宿主应用程序。</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(0, 0, 0, 1)">交互如下:</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(0, 0, 0, 1)"><img src="https://img2018.cnblogs.com/blog/791499/201911/791499-20191120141657975-1136906215.png"></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">扩展通过scheme打开主宿主应用程序</span>
completionHandler:nil];</pre>
</div>
<p> </p>
<p><span style="font-size: 16px; font-family: 楷体"><strong>五、数据</strong></span></p>
<p><span style="font-family: 楷体; font-size: 15px">既然Today扩展能与宿主应用程序进行交互,那么肯定就存在数据通信的问题了。扩展与宿主目录应用程序位于不同的目录结构中,默认情况下,扩展与宿主应用程序的数据并不共享,代码也不能复用。例如在宿主目录应用程序中可能有网络请求、数据持久化存储等结构框架,在扩展中不可以直接使用,扩展需要提供自己的网络请求框架、数据持久化框架等。这些问题苹果都提供了解决方法,可以通过创建静态库的方式实现代码共享,通过APP Group和Scheme跳转实现数据共享。这里主要讲一下数据共享。注意:扩展和宿主应用程序的素材文件也是互相独立的,必须将扩展中的素材添加到扩展Target。</span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="font-family: 楷体"><span style="font-size: 15px">方式一:通过配置scheme跳转来实现数据共享。可以将传递的数据配置到URL中,然后宿主应用程序通过AppDeleagte的代理方法</span></span><span style="font-size: 15px; font-family: 楷体">application:openURL:options:获取数据,不过这个数据传递只能是单方向的。</span></span></p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">打开主应用程序</span>
-(<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">)openMainApp {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">共享数据</span>
NSString *schemeFormat = <span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">MainApp://action=openCarema?name=xiayuanquan</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
completionHandler:nil];
}</span></pre>
</div>
<div class="cnblogs_code">
<pre>-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,<span style="color: rgba(0, 0, 255, 1)">id</span>> *<span style="color: rgba(0, 0, 0, 1)">)options {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从URL获取共享数据,截取数据</span>
NSLog(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">---------url = %@---------</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,url);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> YES;
}</span></pre>
</div>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)">方式二:给扩展的Target和宿主应用程序的Target项目都开启APP Group,两者配置相同的appgroupIndentifier标识,分别生成后缀名为.entitlements文件。然后对于小数据推荐使用偏好进行双向传递共享数据,如图所示。</span></p>
<p><span style="font-size: 15px; font-family: 楷体; color: rgba(255, 0, 0, 1)"><img src="https://img2018.cnblogs.com/blog/791499/201911/791499-20191120144405471-853677770.png"></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">共享数据
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用偏好设置</span>
NSUserDefaults *defalut = [ initWithSuiteName:<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">group.xiayuanquan</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">];
;</pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从偏好设置获取共享数据</span>
NSUserDefaults *defalut = [ initWithSuiteName:<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">group.xiayuanquan</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">];
NSString </span>*name1 = ;
NSLog(</span><span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">1------------name1=%@</span><span style="color: rgba(128, 0, 0, 1)">"</span>,name1);</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1); font-size: 15px; font-family: 楷体">方式三:配置跟方式二一样,不过双向传递共享数据使用文件目录来实现。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">共享数据
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式二:使用共享目录</span>
NSFileManager *fileManager =<span style="color: rgba(0, 0, 0, 1)"> ;
NSURL </span>*baseURL = ;
NSURL </span>*filePath = ;
NSData </span>*data = ;
;</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从共享目录获取共享数据</span>
NSFileManager *fileManager =<span style="color: rgba(0, 0, 0, 1)"> ;
NSURL </span>*baseURL = ;
NSURL </span>*filePath = ;
NSData </span>*data =<span style="color: rgba(0, 0, 0, 1)"> ;
NSLog(</span><span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">2------------data=%@</span><span style="color: rgba(128, 0, 0, 1)">"</span>,data);</pre>
</div>
<p> </p>
<p><span style="font-size: 16px; font-family: 楷体"><strong>六、适配</strong></span></p>
<p><span style="font-size: 15px; font-family: 楷体">从iOS10开始,苹果提供了</span><span style="font-size: 15px; font-family: 楷体">NCWidgetDisplayMode展示模式,通过设置该模式来</span><span style="font-size: 15px; font-family: 楷体">支持对widget进行折叠和展开。在这里,</span><span style="font-size: 15px; font-family: 楷体">preferredContentSize就用到了。这个是用来设置widget的尺寸的。苹果对widget的尺寸有自己的标准,width为maxSize.width,height取值范围。</span><span style="font-family: 楷体"><span style="font-size: 15px">这个maxSize可以在扩展协议<NCWidgetProviding>的协议方法也即widgetActiveDisplayModeDidChange:withMaximumSize中获取</span></span><span style="font-size: 15px; font-family: 楷体">:,可以发现每一种机型maxSize不一样。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 6s模拟器下:
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> NCWidgetDisplayModeCompact模式下:{359.000000, 110.000000}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> NCWidgetDisplayModeExpanded模式下:{359.000000, 528.000000}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 8 plus模拟器下:
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> NCWidgetDisplayModeCompact模式下:{304.000000, 110.000000}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> NCWidgetDisplayModeExpanded模式下:{304.000000, 616.000000}</span></pre>
</div>
<p><span style="color: rgba(128, 0, 0, 1); font-size: 15px; font-family: 楷体">折叠状态:widget的高为110,此时设置preferredContentSize无效;</span> </p>
<p><span style="color: rgba(128, 0, 0, 1); font-size: 15px; font-family: 楷体">展开状态:widget的高为开发者设置的preferredContentSize.height,但是如果preferredContentSize.height>maxSize.height,此时取值为maxSize.height。</span> </p>
<p><span style="color: rgba(128, 0, 0, 1)"><span style="font-family: 楷体"><span style="font-size: 15px">适配iOS10,默认支持展开,设置如下: </span></span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置widget默认为可以展开,此时处于折叠状态</span>
<span style="color: rgba(0, 0, 255, 1)">#ifdef</span> __IPHONE_10_0 <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">适配iOS10</span>
self.extensionContext.widgetLargestAvailableDisplayMode =<span style="color: rgba(0, 0, 0, 1)"> NCWidgetDisplayModeExpanded;
</span><span style="color: rgba(0, 0, 255, 1)">#endif</span></pre>
</div>
<p> </p>
<p><span style="font-family: 楷体; font-size: 16px"><strong>七、范例</strong></span></p>
<p><span style="font-family: 楷体; font-size: 16px"><strong>【去掉MainInterface.storyBoard,采用纯代码实现】</strong></span></p>
<p><span style="font-size: 15px; font-family: 楷体"><span style="font-family: 楷体">1、宿主应用程序AppDelegate</span></span></p>
<div class="cnblogs_code">
<pre>- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *<span style="color: rgba(0, 0, 0, 1)">)launchOptions {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Override point for customization after application launch.
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">存储共享数据
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式二:使用偏好设置</span>
NSUserDefaults *defalut = [ initWithSuiteName:<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">group.xiayuanquan</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">];
;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">存储共享数据
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式三:使用共享目录</span>
NSFileManager *fileManager =<span style="color: rgba(0, 0, 0, 1)"> ;
NSURL </span>*baseURL = ;
NSURL </span>*filePath = ;
NSData </span>*data = ;
;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> YES;
}
</span>-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,<span style="color: rgba(0, 0, 255, 1)">id</span>> *<span style="color: rgba(0, 0, 0, 1)">)options {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式一:从URL获取共享数据,例如参数</span>
NSLog(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">---------url = %@---------</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,url);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> YES;
}</span></pre>
</div>
<p><span style="font-size: 15px; font-family: 楷体">2、Widget扩展TodayViewController</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">TodayViewController.m
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">TodayExtension
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Created by 夏远全 on 2019/11/19.
</span><span style="color: rgba(0, 128, 0, 1)">//
</span>
<span style="color: rgba(0, 0, 255, 1)">#import</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">TodayViewController.h</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">#import</span> <NotificationCenter/NotificationCenter.h>
<span style="color: rgba(0, 0, 255, 1)">@interface</span> TodayViewController () <NCWidgetProviding>
<span style="color: rgba(0, 0, 255, 1)">@end</span>
<span style="color: rgba(0, 0, 255, 1)">@implementation</span><span style="color: rgba(0, 0, 0, 1)"> TodayViewController
</span>- (<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">)viewDidLoad {
;
;
;
;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">配置</span>
-(<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">)config {
self.view.backgroundColor </span>= ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">widget背景色为灰色</span>
self.preferredContentSize = CGSizeMake(.bounds.size.width, <span style="color: rgba(128, 0, 128, 1)">300</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">widget尺寸大小, 宽度实际取maxSize,width,高度
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置widget默认为可以展开,此时处于折叠状态</span>
<span style="color: rgba(0, 0, 255, 1)">#ifdef</span> __IPHONE_10_0 <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">适配iOS10</span>
self.extensionContext.widgetLargestAvailableDisplayMode =<span style="color: rgba(0, 0, 0, 1)"> NCWidgetDisplayModeExpanded;
</span><span style="color: rgba(0, 0, 255, 1)">#endif</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建UI</span>
-(<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">)createUI {
CGFloat width </span>=<span style="color: rgba(0, 0, 0, 1)"> self.view.frame.size.width;
CGFloat btnWidth </span>= <span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">;
UIButton </span>*button = [ initWithFrame:CGRectMake((width-btnWidth)/<span style="color: rgba(128, 0, 128, 1)">2</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, btnWidth, <span style="color: rgba(128, 0, 128, 1)">40</span><span style="color: rgba(0, 0, 0, 1)">)];
button.backgroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ;
;
forState:UIControlStateNormal];
;
;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">打开主应用程序</span>
-(<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">)openMainApp {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">传递共享数据
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式一:参数传递</span>
NSString *schemeFormat = <span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">MainApp://action=openCarema?name=xiayuanquan</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
completionHandler:nil];
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取共享数据</span>
-(<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">)fecthData {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式二:从偏好设置获取共享数据</span>
NSUserDefaults *defalut = [ initWithSuiteName:<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">group.xiayuanquan</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">];
NSString </span>*name1 = ;
NSLog(</span><span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">1------------name1=%@</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,name1);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式三:从共享目录获取共享数据</span>
NSFileManager *fileManager =<span style="color: rgba(0, 0, 0, 1)"> ;
NSURL </span>*baseURL = ;
NSURL </span>*filePath = ;
NSData </span>*data =<span style="color: rgba(0, 0, 0, 1)"> ;
NSLog(</span><span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">2------------data=%@</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,data);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当数据更新时调用的方法,系统会定期更新扩展</span>
- (<span style="color: rgba(0, 0, 255, 1)">void</span>)widgetPerformUpdateWithCompletionHandler:(<span style="color: rgba(0, 0, 255, 1)">void</span> (^<span style="color: rgba(0, 0, 0, 1)">)(NCUpdateResult))completionHandler {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取共享的数据,根据判断回调对应的block
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">NCUpdateResultNewData,
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">NCUpdateResultNoData,
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">NCUpdateResultFailed</span>
<span style="color: rgba(0, 0, 0, 1)">
completionHandler(NCUpdateResultNoData);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">监听显示模式(宽松型、紧奏型)和尺寸的改变
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">NCWidgetDisplayModeCompact :折叠
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">NCWidgetDisplayModeExpanded : 展开</span>
- (<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">maxSize:
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">虽说是最大的Size,但苹果还是把Widget的高度范围限制在了之间
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果设置高度小于110,那么default = 110;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果设置高度大于开发者设置的preferredContentSize.Heiget,那么default = maxSize;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">折叠状态下,苹果将高度固定为110,这个时候设置preferredContentSize属性无效。</span>
NSLog(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">width = %lf-------height = %lf</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,maxSize.width,maxSize.height);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可以更改状态</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (activeDisplayMode ==<span style="color: rgba(0, 0, 0, 1)"> NCWidgetDisplayModeExpanded) {
self.preferredContentSize </span>= CGSizeMake(.bounds.size.width, <span style="color: rgba(128, 0, 128, 1)">300</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
self.preferredContentSize </span>= CGSizeMake(.bounds.size.width, <span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置扩展UI边距,注意:使用StoryBoard时,若要所见即所得,则这个方法中需要返回UIEdgeInsetsZero; (iOS10 and later 不会再被调用)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> return UIEdgeInsetsZero;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">}</span>
<span style="color: rgba(0, 0, 255, 1)">@end</span></pre>
</div>
<p><span style="font-size: 15px; font-family: 楷体">3、打印和gif</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(128, 0, 128, 1)">2019</span>-<span style="color: rgba(128, 0, 128, 1)">11</span>-<span style="color: rgba(128, 0, 128, 1)">20</span> <span style="color: rgba(128, 0, 128, 1)">16</span>:<span style="color: rgba(128, 0, 128, 1)">22</span>:<span style="color: rgba(128, 0, 128, 1)">31.074596</span>+<span style="color: rgba(128, 0, 128, 1)">0800</span> TodayExtension[<span style="color: rgba(128, 0, 128, 1)">29668</span>:<span style="color: rgba(128, 0, 128, 1)">1132736</span>] <span style="color: rgba(128, 0, 128, 1)">1</span>------------name1=<span style="color: rgba(0, 0, 0, 1)">xiayuanquan
</span><span style="color: rgba(128, 0, 128, 1)">2019</span>-<span style="color: rgba(128, 0, 128, 1)">11</span>-<span style="color: rgba(128, 0, 128, 1)">20</span> <span style="color: rgba(128, 0, 128, 1)">16</span>:<span style="color: rgba(128, 0, 128, 1)">22</span>:<span style="color: rgba(128, 0, 128, 1)">31.234435</span>+<span style="color: rgba(128, 0, 128, 1)">0800</span> TodayExtension[<span style="color: rgba(128, 0, 128, 1)">29668</span>:<span style="color: rgba(128, 0, 128, 1)">1132736</span>] <span style="color: rgba(128, 0, 128, 1)">2</span>------------data={length = <span style="color: rgba(128, 0, 128, 1)">149</span>, bytes = <span style="color: rgba(128, 0, 128, 1)">0x62706c69</span> <span style="color: rgba(128, 0, 128, 1)">73743030</span> d4010203 <span style="color: rgba(128, 0, 128, 1)">04050607</span> ... <span style="color: rgba(128, 0, 128, 1)">00000000</span> <span style="color: rgba(128, 0, 128, 1)">00000068</span><span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(128, 0, 128, 1)">2019</span>-<span style="color: rgba(128, 0, 128, 1)">11</span>-<span style="color: rgba(128, 0, 128, 1)">20</span> <span style="color: rgba(128, 0, 128, 1)">16</span>:<span style="color: rgba(128, 0, 128, 1)">22</span>:<span style="color: rgba(128, 0, 128, 1)">31.234970</span>+<span style="color: rgba(128, 0, 128, 1)">0800</span> TodayExtension[<span style="color: rgba(128, 0, 128, 1)">29668</span>:<span style="color: rgba(128, 0, 128, 1)">1132736</span>] maxSize.width = <span style="color: rgba(128, 0, 128, 1)">359.000000</span>-------maxSize.height = <span style="color: rgba(128, 0, 128, 1)">110.000000 <span style="color: rgba(51, 153, 102, 1)">//折叠</span></span>
<span style="color: rgba(128, 0, 128, 1)">2019</span>-<span style="color: rgba(128, 0, 128, 1)">11</span>-<span style="color: rgba(128, 0, 128, 1)">20</span> <span style="color: rgba(128, 0, 128, 1)">16</span>:<span style="color: rgba(128, 0, 128, 1)">22</span>:<span style="color: rgba(128, 0, 128, 1)">38.117764</span>+<span style="color: rgba(128, 0, 128, 1)">0800</span> TodayExtension[<span style="color: rgba(128, 0, 128, 1)">29668</span>:<span style="color: rgba(128, 0, 128, 1)">1132736</span>] maxSize.width = <span style="color: rgba(128, 0, 128, 1)">359.000000</span>-------maxSize.height = <span style="color: rgba(128, 0, 128, 1)">528.000000 <span style="color: rgba(51, 153, 102, 1)">//展开</span></span></pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/791499/201911/791499-20191120163418652-475497750.gif"></p>
<p> </p>
<p> </p>
<p> </p>
<p><span style="font-size: 15px; font-family: 楷体"><span style="font-family: 楷体; font-size: medium"> </span></span></p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!<br><br>
来源:https://www.cnblogs.com/XYQ-208910/p/11897343.html
頁:
[1]