iOS小組件Widget踩坑

上篇文章是對widget的整體調研,真正上項目會有很多坑

運行主項目或者單獨運行widget都可以使widget代碼生效

一.widget不走斷點

1.因為func getTimeline方法不一定每次運行項目都會及時生效锌雀,有時widget界面刷新了迅诬,但是斷點卻沒走,升級xcode到12.2就好很多

2.在主項目主動調用widget刷新

WidgetCenter.shared.reloadAllTimelines()

需要注意的是這個方法需要import WidgetKit惩歉,WidgetKit只有swift版本,所以主項目如果是OC需要混編調用swift

3.在主項目隨便打一個斷點(比如didFinishLaunch)上遥,因為主項目是走斷點的粉楚,運行下主項目亮垫,走斷點,運行主項目widget也會運行燃异,發(fā)現(xiàn)widget中的斷點也走了继蜡,神奇

4.老辦法:跑一遍主項目再跑widget項目,重新安裝APP鲫剿,clean Xcode稻轨,重啟Xcode,重啟電腦政冻,重啟手機

二.widget不刷新线欲,或者刷新不及時

我們都知道widget的刷新是受func getTimeline控制的,因為這個方法受系統(tǒng)控制苦锨,系統(tǒng)會根據(jù)widget的使用頻率和類型趴泌,來決定widget的刷新頻率,所以func getTimeline的刷新最早時間是我們手動寫的刷新策略秃励,很有可能刷新時間會延后
另外手動寫的刷新策略過于頻繁吉捶,會延后小組件的刷新
舉個??皆尔,策略為十分鐘以后刷新

        let currentDate = Date()
        let entryDate = Calendar.current.date(byAdding: .minute, value: 10, to: currentDate)!
        let entry = SimpleEntry(date: entryDate)
        
        var entries: [SimpleEntry] = []
        entries.append(entry)
        return Timeline(entries: entries, policy: .after(entryDate))

policy是刷新策略慷蠕,有三種方式
.atEnd,當前entries執(zhí)行完畢后砌们,立刻刷新
.after,設定時間刷新
.never,不刷新

entryDate是指定每個entry的刷新時間

雖然第一次添加widget搁进,func getTimeline一定會走昔头,但是在有些機器不能及時的刷新,目前沒有找到解決方案莱革,猜測和系統(tǒng)刷新頻率有關

還可以像上面說的在主項目主動調用widget刷新WidgetCenter.shared.reloadAllTimelines()讹开,比如在主項目切換到后臺時刷新

三.widget黑屏

1.不管是在添加widget界面還是把widget添加到桌面,黑屏可能widget已經(jīng)崩潰了闹击,單獨運行widget Extension查看是否崩潰成艘,
2.func getTimeline方法沒有返回,數(shù)據(jù)錯誤断箫,網(wǎng)絡錯誤秋冰,都要返回func getTimelinecompletion閉包
3.采用每個widget單獨加載一個widget樣式的方案,不要一個widget加載多個widget樣式埃撵,這樣在沒有加載出來widget時甥材,系統(tǒng)的占位文本不知道加載哪種widget樣式導致黑屏,具體加載方式看上一篇文章
4.有時是設備問題鸳惯,換臺設備試試

四.widget不停刷新

1.調用了持續(xù)定位

2.func getTimeline方法中completion閉包被頻繁調用,可能存在多個異步調用操作

比如報錯:
Terminating app due to uncaught exception 'NSFileHandleOperationException', reason: '*** -[NSConcreteFileHandle fileDescriptor]: Invalid argument'

原因:getTimeline的completion閉包只能調用一次

五.調用主項目绪商,三方庫

如果主項目是OC辅鲸,或者現(xiàn)在widget target項目里面加入OC文件,需要加入橋接文件例书,如果加入.intentdefinition的配置文件刻炒,需要在橋接文件中,引入#import "ConfigurationIntent.h"树瞭,否則會報錯誤Cannot find type 'ConfigurationIntent' in scope爱谁。

如果需要用cocopod中的其他庫,需要添加新的target凉敲,加入在widget擴展中需要用到的庫捐顷,比如加入AFNetworking:

target 'WidgetExtension' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  pod 'AFNetworking'
  # Pods for WidgetExtension

end

如果需要主項目中的文件,在需要用到的.m文件Target Membership中勾選widgetExtention废赞,這樣widget小組件才能用這個OC 文件叮姑。可能需要一些兼容性改動:引入一些缺少的頭文件耘沼,勾選其他關聯(lián)文件的Target Membership朱盐,添加widget關聯(lián)。勾選后編譯一下狂秘,沒問題后把用到的OC文件添加到橋接文件中聲明,這樣swiftUI才能調用原來OC主項目的文件

六.界面混編問題

widget界面不能用UIKit的任何東西破衔,遵守UIViewRepresentable協(xié)議橋接過來也不行钱烟,只能用swiftUI寫界面

七.不能高德定位

目前高德定位初始化[[AMapLocationManager alloc] init],會崩潰读第;報錯Assertion failure in -[CLLocationManager setPausesLocationUpdatesAutomatically:]稻扬,但是系統(tǒng)定位可以拿到經(jīng)緯度羊瘩,再反地理位置編碼
需要在info.plist添加NSLocationAlwaysAndWhenInUseUsageDescription,NSLocationAlwaysUsageDescription,NSLocationUsageDescription,NSLocationWhenInUseUsageDescription,還需要添加NSWidgetWantsLocation設為true逝她,允許小組件定位

八.機型適配睬捶,swiftUI布局

widget尺寸.jpeg

這是官方給的widget在各個機型的尺寸擒贸,然后我發(fā)現(xiàn)widget在各個機型尺寸都不一樣,和屏幕比例沒有關系徽惋,不成比例座韵,到屏幕邊緣的距離也各不相同,找不要系統(tǒng)方法誉碴,為了獲取widget的大小寬高,就根據(jù)這個表代咸,寫死了一套獲取代碼(不對成黄,下面有直接獲取方法)

enum WidgetSizeEnum {
    case small
    case medium
    case large
}

let ScreenWidth = UIScreen.main.bounds.width
let ScreenHeight = UIScreen.main.bounds.height


func WidgetSize(_ widgetType:WidgetSizeEnum) -> CGSize {
    
    if ScreenWidth == 320 && ScreenHeight == 568 {
        switch widgetType {
        case .small:
            return CGSize(width: 141, height: 141)
        case .medium:
            return CGSize(width: 291, height: 141)
        case .large:
            return CGSize(width: 291, height: 299)
        }
    }
    
    
    if ScreenWidth == 375 && ScreenHeight == 667 {
        switch widgetType {
        case .small:
            return CGSize(width: 148, height: 148)
        case .medium:
            return CGSize(width: 322, height: 148)
        case .large:
            return CGSize(width: 322, height: 324)
        }
    }

    if ScreenWidth == 414 && ScreenHeight == 736 {
        switch widgetType {
        case .small:
            return CGSize(width: 159, height: 159)
        case .medium:
            return CGSize(width: 348, height: 159)
        case .large:
            return CGSize(width: 348, height: 357)
        }
    }
    
    if ScreenWidth == 375 && ScreenHeight == 812 {
        switch widgetType {
        case .small:
            return CGSize(width: 155, height: 155)
        case .medium:
            return CGSize(width: 329, height: 155)
        case .large:
            return CGSize(width: 329, height: 345)
        }
    }
    
    if ScreenWidth == 414 && ScreenHeight == 896 {
        switch widgetType {
        case .small:
            return CGSize(width: 169, height: 169)
        case .medium:
            return CGSize(width: 360, height: 169)
        case .large:
            return CGSize(width: 360, height: 376)
        }
    }
    
  
    switch widgetType {
        case .small:
            return CGSize(width: 148, height: 148)
        case .medium:
            return CGSize(width: 322, height: 148)
        case .large:
            return CGSize(width: 322, height: 324)
    }
}



let kSmallWidgetWidth = WidgetSize(.small).width
let kMediumWidgetWidth = WidgetSize(.medium).width
let kLargeWidgetWidth = WidgetSize(.large).width

let kSmallWidgetHeight = WidgetSize(.small).height
let kMediumWidgetHeight = WidgetSize(.medium).height
let kLargeWidgetHeight = WidgetSize(.large).height

后來發(fā)現(xiàn)有些機型沒有包含贩耐,比如iPhone12,min管搪,max,后來在翻了一遍WidgetKit庫終于找到了系統(tǒng)方法更鲁,哭了奇钞,上面寫的這一套是費代碼,坑媒至,

public struct TimelineProviderContext {
  public let displaySize: CGSize
}

在widget三個方法placeholder,getSnapshot,getTimeline都可以獲取

context.displaySize

swiftUI布局也有很多坑谷徙,下次另開一篇文章細說
比如

Image("imageName")
    .resizable()
    .frame(width: fitWidth(22), height: fitWidth(22))

圖片設置大小要先設置resizable,否則不生效

發(fā)現(xiàn)一個神坑谋旦,原來不帶編輯功能的小組件屈尼,更新版本到有編輯功能的小組件,原來添加的靜態(tài)不可編輯的小組件就不能用了甲捏,重啟手機就好了(但不能讓用戶重啟手機吧)涨椒,新添加的widget沒有問題桶现,分析原因是初始化方式改變了,StaticConfiguration變成了IntentConfiguration眉反,代碼沒更新猎提,所以開始就帶上可編輯功能吧

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末锨苏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子贞谓,更是在濱河造成了極大的恐慌葵诈,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件理疙,死亡現(xiàn)場離奇詭異泞坦,居然都是意外死亡,警方通過查閱死者的電腦和手機赃梧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門李根,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事所森。” “怎么了纷妆?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵晴弃,是天一觀的道長。 經(jīng)常有香客問我际邻,道長芍阎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任轮听,我火速辦了婚禮,結果婚禮上血巍,老公的妹妹穿的比我還像新娘。我一直安慰自己驹暑,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布优俘。 她就那樣靜靜地躺著掀序,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叶雹。 梳的紋絲不亂的頭發(fā)上换吧,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音沾瓦,去河邊找鬼。 笑死风喇,一個胖子當著我的面吹牛缕探,可吹牛的內容都是我干的。 我是一名探鬼主播爹耗,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼倦始!你這毒婦竟也來了讼溺?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤炫狱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嬉荆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡鄙早,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年限番,在試婚紗的時候發(fā)現(xiàn)自己被綠了呀舔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡霜瘪,死狀恐怖惧磺,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情磨隘,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布训堆,位于F島的核電站白嘁,受9級特大地震影響膘流,放射性物質發(fā)生泄漏。R本人自食惡果不足惜耕魄,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一彭谁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦考润、人聲如沸读处。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽管闷。三九已至,卻和暖如春包个,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赃蛛。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工呕臂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人歧蒋。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像萝映,于是被迫代替她去往敵國和親阐虚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內容