[TOC]
1、Tips
-
擴展App想要使用主App中的代碼,需要在如下位置引入
01.png 調(diào)試主App則運行主App;調(diào)試擴展則運行擴展 (解決擴展不走斷點的問題)
擴展App想要使用的圖片資源等,需要引入到擴展文件夾下
2、純代碼需要配置info.plist的倆項參數(shù)
移除
NSExtensionMainStoryboard
鍵,并添加NSExtensionPrincipalClass
鍵,使用view controller的名字作為值。
3、UI樣式
- 背景:盡量不要使用背景,默認的毛玻璃效果很好,主要文字顏色最好是白色,次要文字的顏色最好是
lightTextColor
- 不要在今日面板里使用可以滾動的 Scroll View,而是要完全展開
- 縮進:盡量保持默認的縮進,即左邊會空幾個像素。如果想改變默認縮進,在TodayViewController里面實現(xiàn)以下方法
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets: (UIEdgeInsets)defaultMarginInsets {
return UIEdgeInsetsZero;
}
4、與主App進行交互
- Today跳轉App(喚起App,調(diào)用App某項功能)
[UIApplication sharedApplication]在擴展App中是無法訪問的,需要通過NSExtensionContext來調(diào)用主App的openURL方法
//
[self.extensionContext openURL:[NSURL URLWithString:@"跳轉鏈接"] completionHandler:^(BOOL success) {
NSLog(@"open url result:%d",success);
}];
跳轉鏈接示例:iMyApp://
為跳轉頁面做標識
- App 處理URL Schemes
// iOS 9+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options {
// [url.absoluteString hasPrefix:@"iMyApp://"]
if ([url.host isEqualToString:@"iMyApp"]) {
// 操作
return YES;
}
return YES;
}
// iOS 7、iOS 8
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
// [url.absoluteString hasPrefix:@"iMyApp://"]
if ([url.host isEqualToString:@"iMyApp"]) {
// 操作
return YES;
}
return YES;
}
5、與主App共享數(shù)據(jù)
- 利用group,將主App和擴展App做一個數(shù)據(jù)共享空間(
NSUserDefault
),先在主App的Targets中創(chuàng)建并設置,再在擴展App的Targets設置(如圖)
- 主App存擴展App所需要數(shù)據(jù)
NSUserDefaults* userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.iMyApp"];
[userDefault setBool:YES forKey:@"islogin"];
- 擴展App取所需要數(shù)據(jù)
NSUserDefaults *myDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.iMyApp"];
BOOL isLogin = [myDefaults objectForKey:@"islogin"];
6、 - (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult result))completionHandler
方法說明
對于擴展App,即使擴展App現(xiàn)在不可見 (即用戶沒有拉開通知中心),系統(tǒng)也會時不時地調(diào)用實現(xiàn)了 NCWidgetProviding 的擴展的這個方法,來要求擴展刷新界面。
這個機制和 iOS 7 引入的后臺機制是很相似的。在這個方法中我們一般可以做一些像 API 請求之類的事情,在獲取到了數(shù)據(jù)并更新了界面,或者是失敗后都使用提供的 completionHandler 來向系統(tǒng)進行報告
7、定時更新機制(通過增加定時更新的NSTimer)
把NSTimer fire觸發(fā)代碼調(diào)用放到
viewWillAppear
方法中來(viewDidLoad
方法并不是每次都執(zhí)行).同理當Widget關閉后在viewDidDisappear
方法取消NSTimer invalidate定時更新即可。
8、關閉today widget中擴展App的顯示
有時候在沒有數(shù)據(jù)的時候需要隱藏擴展,可以使用以下方法:
NCWidgetController *widgetController = [NCWidgetController widgetController];
[widgetController setHasContent:NO forWidgetWithBundleIdentifier:@"擴展的id"];
9、iOS10 的適配- 展開、折疊按鈕
在NSExtensionContext中,新添了
widgetLargestAvailableDisplayMode
屬性,來確認當前widget是展開還是折疊狀態(tài)。所以,先在viewWillAppear中設置widget的mode為展開。
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
展開和折疊狀態(tài)變化時的處理
-(void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
if (activeDisplayMode == NCWidgetDisplayModeCompact) {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 110);
// 處理~~
} else {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 300);
// 處理~~
}
}
- 如何用XCode 7.3打出能夠適配iOS 10的widget呢?
Xcode 7沒有iOS 10,可以通過KVC來解決這個問題
[self.extensionContext setValue:@"1" forKey:@"widgetLargestAvailableDisplayMode"];
if (activeDisplayMode == 0) {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 110);
} else {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 300);
}
}
- 切記:UI的更新要在主線程操作
//通知主線程刷新
dispatch_async(dispatch_get_main_queue(), ^{
//...........;
});