自iOS8之后,蘋果支持了擴(kuò)展(Extension)的開發(fā),開發(fā)者可以通過系統(tǒng)提供給我們的擴(kuò)展接入點 (Extension point) 來為系統(tǒng)特定的服務(wù)提供某些附加的功能。
所謂Widget,就是我們熟知的小組件,這是獨立于應(yīng)用之外的又一個新小應(yīng)用,但是和主應(yīng)用之間又有著一定的關(guān)系。
本文介紹的是iOS14系統(tǒng)以下的widget組件,也就是Todat Extension
iOS14系統(tǒng)以上widget請見:
iOS14 Widget(Widget Extension)小組件開發(fā)
widget實現(xiàn)
1.創(chuàng)建添加Todat Extension
File -> New -> Target -> Todat Extension

2.添加widget的URL Schemes
由于extension 和主app 是兩個完全獨立的進(jìn)程,所以它們之間不能直接相互跳轉(zhuǎn)。為了實現(xiàn) Widget 調(diào)起 APP,這里通過 openURL 的方式來啟動 主app。
主APP中 Target -> Info-> URL Types -> +

調(diào)用方式
widget中點擊跳轉(zhuǎn)事件添加如下代碼
[self.extensionContext openURL:[NSURL URLWithString:@"NowWidget://"] completionHandler:nil];
主APP的AppDelegate中接收
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
if ([url.scheme isEqualToString:@"NowWidget"]){
//執(zhí)行跳轉(zhuǎn)后的操作
}
return YES;
}
3.數(shù)據(jù)共享
由于widget跟APP間相互獨立,如果想用相同的數(shù)據(jù)則需要兩者間數(shù)據(jù)共享,創(chuàng)建App Group
主APP中 Target -> Signing & Capability -> +Capability -> 添加 App Group

ps:網(wǎng)上說的還需創(chuàng)建申請 APPID 但在開啟自動管理 Automatically manage signing的情況下xcode會自動給你創(chuàng)建相關(guān)聯(lián)的APPID
兩者間的數(shù)據(jù)共享主要通過NSFileManager和NSUserDefaults兩種形式。
- 通過NSUserDefaults共享數(shù)據(jù)
//存數(shù)據(jù)
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.imoblife.now"];
[userDefaults setObject:@"content" forKey:@"widget"];
[userDefaults synchronize];
//取數(shù)據(jù)
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.imoblife.now"];
NSString *content = [userDefaults objectForKey:@"widget"];
- 通過NSFileManager共享數(shù)據(jù)
-(BOOL)saveDataByNSFileManager:(NSData *)data
{
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.imoblife.now"];
containerURL = [containerURL URLByAppendingPathComponent:@"widget"];
BOOL result = [data writeToURL:containerURL atomically:YES];
return result;
}
-(NSData *)readDataByNSFileManager
{
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.imoblife.now"];
containerURL = [containerURL URLByAppendingPathComponent:@"widget"];
NSData *value = [NSData dataWithContentsOfURL:containerURL];
return value;
}
4.開啟折疊及尺寸規(guī)定
不需要折疊功能忽略此步驟
- (void)viewDidLoad {
[super viewDidLoad];
//添加折疊效果
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}
//折疊及非折疊樣式更改
-(void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
/**
iOS10以后,重新規(guī)定了Today Extension的size。寬度是固定(例如在iPhone6上是359),所以無法改變;但是高度方面,提供了兩種模式:
NCWidgetDisplayModeCompact:固定高度,則為110
NCWidgetDisplayModeExpanded:可以變化的高度,區(qū)間為110~616
*/
if (activeDisplayMode == NCWidgetDisplayModeCompact) {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width-16, 110);
} else {
self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width-16, 250);
}
}
//此方法主要執(zhí)行刷新操作
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResultFailed
// If there's no update required, use NCUpdateResultNoData
// If there's an update, use NCUpdateResultNewData
completionHandler(NCUpdateResultNewData);
}
5.文件共享及pods共享
-
文件共享
文件共享.png
勾選共享widget選項即可 pods共享
正常使用下widget中無法使用pods導(dǎo)入的第三方SDK如Masonry等,會造成布局等極其不便,因此需要共享pods,在Podfile中需要另設(shè)置并重新install
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
inhibit_all_warnings!
#共享Masonry
def share_pods
pod 'HandyJSON'
end
target "targetName" do
pod 'AFNetworking'
share_pods
end
target "widgetTargetName" do
share_pods
end
完成后即可使用pods中的第三方SDK了
#import <Masonry.h>
#import <SDWebImage/UIImageView+WebCache.h>
#import <SDWebImageDownloader.h>
#import <SDImageCache.h>
#import <AFNetworking.h>...
Pods第三方SDK使用錯誤提示
如果在pods導(dǎo)入共享第三方庫,或者使用[UIApplication sharedApplication]方法報錯如下時
not available on iOS (App Extension) - Use view controller based solutions where appropriate instead.
則需要在pods Target里面,選中出錯的SDK并點擊buildSettings 搜索Require
然后把Require Only App-Extension-Safe API 然后把YES改為NO即可

ps:工程項目里也可按照這個方法去排查原因
在調(diào)試widget功能時不要忘記將Device變更為widget項目 ??♀???♀???♀?

