iOS開發 Widget(小組件)的開發

在iOS開發中,Widget(小組件)的功能屬于雞肋的功能,因為大多數的人都很少去使用,或者很多人都不知道還有這功能。不過在項目完成時可以添加上去,增加項目的bigger。本文會詳細介紹小組件的開發以及開發中會遇到的坑,如果大家又遇到新的坑,可以在下面留言,大家一起交流。
聲明:本文是使用Xcode11.0beta6版本+iOS13.1beta2版本作為展示用例。但是項目創建是使用Xcode10.3創建的,這是因為害怕部分用戶下載Demo后無法在Xcode10中運行。現在使用Xcode的11創建APP會多一個SceneDelegate,在Xcode10中無法識別,也會簡單的說明一下當前Demo找Xcode10與Xcode11的簡單區別。所展示的支付寶版本為10.1.72,今日頭條版本為7.4.0。(避免今后兩款APP更新以后與本文展示的不一致)

1.什么是小組件

小組件即如圖的下面兩種呈現方式:第一種是在最左頁(俗稱第0頁)或者是往下滑的時候會出現的頁面,展示如下:


最左頁

這個需要用戶去點擊編輯才會顯示出來。
第二種展示方式是長按當前APP后會出來(也就是3DTouch),展示如下:


長按顯示1
長按顯示2

這種方式只要長按就會觸發,不需要用戶去添加。
常見的小組件都是這兩種方式顯示,一種是支付寶的那種固定樣式的,點擊某一個功能后就跳轉到APP的某個頁面去。另外一種是今日頭條的動態顯示的,每次都回去請求數據然后刷新顯示。接下來兩種方式的開發都會進行講解。

2.靜態小組件的開發(類似支付寶的樣式)

對于想做成類似支付寶的點擊小組件的某個按鈕就跳轉的指定頁面的是最簡單的。有一些其他文章上來就說需要去添加APP Groups的對于這種類型的來說是不必要的,這個不涉及到數據共享的東西,就簡單的跳轉,完全沒必要去進行創建APP Groups。下面說明詳細步驟:
完成主項目后,點擊如下兩個步驟完成widget的創建:


添加方式1.png
添加方式2.png

選擇Today Extension:


Today Extension

填寫項目名稱即可完成創建。接下來在TodayViewController的viewDidLoad里面進行按鈕的創建:

    CGFloat width = [UIScreen mainScreen].bounds.size.width;
    //NCWidgetDisplayModeCompact   不需要折疊樣式,整個完整顯示
    //NCWidgetDisplayModeExpanded  有折疊按鈕,點擊可以顯示更多
    self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeCompact;
    //設置整個小組件的寬高
    self.preferredContentSize = CGSizeMake(width, 130);
    NSArray *titleArray = @[
                            @"掃一掃",
                            @"掃一掃",
                            @"掃一掃",
                            @"掃一掃",
                            ];
    NSArray *imageArray = @[
                            @"widget_scan",
                            @"widget_scan",
                            @"widget_scan",
                            @"widget_scan",
                            ];
    CGFloat btnWidth = 60;
    CGFloat btnHeight = 60;
    CGFloat margin = (width - titleArray.count * btnWidth) / (titleArray.count + 1);
    CGFloat y = 20;
    for (NSInteger i = 0; i < titleArray.count; i ++) {
        CGFloat x = margin + i * (btnWidth + margin);
        UIButton *btn = [[UIButton alloc] init];
        btn.frame = CGRectMake(x, y, btnWidth, btnHeight);
        [btn setImage:[UIImage imageNamed:imageArray[i]] forState:UIControlStateNormal];
        [btn setTitle:titleArray[i] forState:UIControlStateNormal];
        btn.tag = i;
        [btn addTarget:self action:@selector(btnDidClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:btn];
    }

運行后效果如下圖:
運行效果圖

這是為什么呢?沒有寫hello world確顯示出來了。這是因為系統默認是用小組件的MainInterface.storyboard進行顯示的,如果你喜歡使用storyboard直接在里面布局就行了,但是我一般都用代碼開發,所以需要去當前小組件的文件下的info.plist刪除 NSExtensionMainStoryboard 選項,增加 NSExtensionPrincipalClass,value為類的名字TodayViewController即可用純代碼進行布局。
配置純代碼.png

配置完成后再次運行。
運行結果

現在能看到文字顯示出來了,但是圖片沒有,這是因為在放進去圖片的時候,沒有勾選在widget項目里面也能共,所以當前項目找不到圖片,只需要去勾選就可以在當前文件使用即可。
圖片添加

順便說一下,主項目里面的文件如何讓widget也能使用,如果是單純的.h文件,比如之前存放的一些宏的定義,顏色的定義之類的,只需要在這個地方設置導入即可:
引入頭文件

如果想引入主項目里面的其他文件,也和圖片一樣的勾選,只是在上面那里導入是不行的,必須進行勾選才能使用,比如我需要導入一個分類文件:


分類文件導入

勾選圖片以后就能看到圖片了。
demo有不完美的地方,按鈕的圖片和title不能對齊,不過不影響demo的演示:)

布局完成能顯示以后,接下來進行點擊按鈕跳轉,由于需要跳轉到主項目的某個頁面,所以需要在主項目中用到URL Types。強烈建議設置成包名的形式,否則和其他APP一樣的schemes可能會跳轉他們的APP去
URL Types

ok,配置完成后,只需要在widget的按鈕里面實現點擊事件然后在主項目的AppDelegate的openURL里面實現點擊以后的判讀即可。
widget的點擊事件如下:
- (void)btnDidClick:(UIButton *)btn{
    NSInteger index = btn.tag;
    //因為我是需要跳轉到某個頁面,所以我直接傳遞跳轉頁面的類名
    NSString *vcString = @"";
    if (index == 0) {
        vcString = @"OneViewController";
    }else if (index == 1){
        vcString = @"OneViewController";
    }else if (index == 2){
        vcString = @"ViewController";
    }else if (index == 3){
        vcString = @"TwoViewController";
    }
    [self.extensionContext openURL:[NSURL URLWithString:[NSString stringWithFormat:@"com.widgetDemo://%@",vcString]] completionHandler:nil];
}

AppDelegate的openURL如下:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
    [self appCallbackWithOpenUrl:url];
    return YES;
}

- (void)appCallbackWithOpenUrl:(NSURL *)url{
    // 針對url進行不同的操作
    NSString *URLString = [NSString stringWithFormat:@"%@",url];
    NSArray *array = [URLString componentsSeparatedByString:@"://"];
    NSString *vcString = @"";
    //這里最好進行判斷URL的開頭是不是設置的schemes,如果用到其他的第三方SDK,有可能是他們的URL
    if (array.count >= 2) {
        vcString = array[1];
    }
   //這里可以先判斷是否登錄或者其他邏輯在進行下面的操作
        
    if ([vcString isEqualToString:@"OneViewController"]) {
        UINavigationController *nav = ((UITabBarController*)self.window.rootViewController).selectedViewController;
        UIViewController *VC = [[NSClassFromString(vcString) alloc] init];
        [nav pushViewController:VC animated:YES];
    }else if ([vcString isEqualToString:@"ViewController"]){
        UINavigationController *nav = ((UITabBarController*)self.window.rootViewController).selectedViewController;
        UIViewController *VC = [[NSClassFromString(vcString) alloc] init];
        [nav pushViewController:VC animated:YES];
    }else if ([vcString isEqualToString:@"TwoViewController"]){
        UITabBarController *tabBarVC = (UITabBarController *)self.window.rootViewController;
        tabBarVC.selectedIndex = 1;
    }
}

一個固定點擊跳轉的小組件就這樣開發完成,很簡單的。如果不需要數據共享,根本不需要其他文章說的先去配置APP Groups,就如此簡單即可。

3.動態小組件的開發(類似今日頭條的樣式)

做了靜態的小組件以后,動態的也不難,類似于今日頭條的小組件,會有數據的共享,以及數據的請求。但是有以下注意點:

3.1主項目框架的使用

如果項目中用CocoaPods導入了第三方框架,比如Masonry和AFNetworking。在小組件的項目中有可能是能直接導入頭文件的,但是實際使用卻是不行的。這時候需要在podfile文件中加入小組件的target然后在pod install,這樣在小組件的項目中才能使用。
pod文件

這樣以后才能在小組件的項目里面使用第三方框架。

3.2數據共享

如果需要將主APP的某些數據共享給小組件使用,這時候就需要進行數據共享,使用到APP Groups,本次以Xcoede11截圖。在Xcode10中,直接把開關打開添加即可。因為我直接在Xcode里面登錄了賬號,所以不需要去網頁上進行證書那些的配置即可,如果是用其他方式的,需要去網頁上進行相關的設置。
APP Groups

然后就可以在需要存儲的地方進行數據的存儲了,不過現在只支持兩種存儲,一個是NSUserDefaults,一個是NSFileManager。
NSUserDefaults存儲數據

NSUserDefaults *sharedData = [[NSUserDefaults alloc] initWithSuiteName:GroupID];
    [sharedData setValue:@"測試存儲" forKey:Name];
    [sharedData synchronize];

NSFileManager 存儲數據

NSError *error = nil;
    NSURL *containUrl = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:GroupID];
   containUrl = [containUrl URLByAppendingPathComponent:Data];
    NSString *text = @"NSFileManager 存儲數據";
    BOOL result = [text writeToURL:containUrl atomically:YES encoding:NSUTF8StringEncoding error:&error];
    if (result){
        NSLog(@"save success");
    }else {
        NSLog(@"error:%@", error);
    }

在這個方法你可以獲取到時候折疊

// 展開/折疊監聽
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize{
    
}

至此,兩種方式創建的小組件都完成。
如果大家還遇到什么其他問題可以在下面留言,大家一起交流交流。
最后附上Demo地址
)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • ——最美不過你曾溫柔呼喚,而我剛好有過應答 我希望你能被打磨 永遠光明磊落 我...
    旺角煙頭閱讀 346評論 0 4
  • 今天媽媽陪我去公園玩,看到了幾只黑天鵝,媽媽說黑天鵝近乎已經絕跡,讓我們保護動物,愛護動物。今天玩的很開心,也學到...
    5d137d4a8501閱讀 127評論 0 0
  • 從課時量可以看出來,目前語文課絕大部分課時實際上花在閱讀教學,上寫作課是很少的。布置作業的時候呢,有隨筆日記等形式...
    小姜老師0301閱讀 345評論 0 4
  • 荷香滿塘的七月,和朋友在陸河吃完晚飯,便開車經螺溪向上砂的方向出發。 千山夜月明,夏涼滿山坳。把車里空...
    懵園園閱讀 963評論 0 3