面向 Extension 開發(fā) ?? Today Extension

習(xí)慣性美女做封面

App Extension 讓我們在用戶正在使用其他 App 的時候, 拓展我們 App 的功能澜薄。

Today Extension 也叫做 widget侣滩。 它能夠讓一些重要的消息更快速的到達你的用戶。比如說, 用戶可以通過它查看天氣涡真,或者股票價格, 查看日程表等等分俯。蘋果在官方文檔中說到, 一個 widget 應(yīng)該有以下的特點哆料。

  • 確保內(nèi)容是最新的
  • 響應(yīng)的用戶事件
  • 性能好(在iOS上占用大量內(nèi)存缸剪,系統(tǒng)可能會kill掉這個widget)

創(chuàng)建 Today Extension

Xcode -> File -> New -> Target -> TodayExtension

跟創(chuàng)建一個新的項目一樣, 設(shè)置創(chuàng)建好之后, 項目中會多一個 Target, 修改Scheme 為你剛剛創(chuàng)建的 Extension 再運行, 就能在 通知中心的 Today 里面看到你剛剛創(chuàng)建的 widget 了, 上面寫著“Hello world”

另外 Xcode 給你創(chuàng)建了默認(rèn)的模版文件。

  • TodayViewController.swift(如果是 OC 對應(yīng)會是 .h.m 文件)
  • MainInterface.storyboard
  • Info.plist

注意: 默認(rèn)是使用這個 storyboard 作為這個 widget 的入口东亦。如果不需要使用storyboard 可以刪除掉這個storyboard并且將Info.plist 中的

  • NSExtensionMainStoryboard 改成 NSExtensionPrincipalClass
  • MainInterface 改成 TodayViewController

設(shè)置界面

完成了上面的步驟之后, 不論你是選擇用 stroyboard 作為你 widget 的入口, 還是選擇用代碼來做這件事情杏节。都是一樣的。

由于不知道什么原因, 我在網(wǎng)上看到的文章都是使用代碼來做的這件事情典阵。所以在這篇文章以及后面的示例代碼中都將使用 Xcode 默認(rèn)的 storyboard 來做這個 widget 的布局奋渔。

我將解決的問題

  • 在 widget 中打開主 App 并傳遞參數(shù)
  • widget 和 主 App 共享數(shù)據(jù)
  • widget 和 主 App 共用資源
  • widget 的打開和折疊

我遇到的坑

也沒什么坑, 畢竟 Today Extension 并不是什么很難的東西。

  • 測試的時候, 由于 widget 和 主 App 是兩個不同的 target, 所以在傳遞參數(shù)的時候, 在 appdelegate 中打印對應(yīng)的值沒有效果壮啊。最開始我還以為是因為設(shè)置的 scheme 是 widget 所以在 主 App 中的修改是無效的嫉鲸。但是實際是并不是這樣。將參數(shù)以 alert 的形式表現(xiàn)出來, 這時候能夠發(fā)現(xiàn), 其實主 App 是跑起來了的歹啼。

先說說我做的準(zhǔn)備工作吧

為了不扯那么多沒用的東西玄渗。先說說我做了那些跟今天主題沒什么關(guān)系的事情座菠。

寫主 App

在主 App 中我寫了一個 UITableView, 并使用 Userdefault 將我要持久化的數(shù)據(jù)保存下來。然后對應(yīng)給 Todo list 做了藤树,添加浴滴,和刪除的功能。

widget

在 widget 中我也下了同樣的一個 UITableView 只有查看的功能也榄。

要做的事情

widget 和 主 App 共用資源

widget 和主 App 共享代碼和資源巡莹。作為一個工程師, 我們在任何事情的時候都要想到高類聚低耦合著句不變的真理。所以我們還是要盡可能的讓 widget 和主 App 共享代碼甜紫。

主要有兩個方案:

  • framework
  • 直接共享

framework 的話降宅,就拿 cocoapods 來說吧, 由于 widget 是一個新的target, 所以只需要在 podfile 中對應(yīng)添加代碼就能夠在 widget 中使用囚霸。

另外一個是 直接共享, 這個就很簡單了腰根。我在示例中讓主 App 和 widget 共享了一張圖片,一個 TodoCell 類(包括xib 文件)拓型。我做的唯一的一件事情就是在 Xcode 中選中這個文件额嘿,然后在 Xcode右邊的 TargetMenberShip 中勾選對應(yīng)的 target.

widget 和 主 App 共享數(shù)據(jù)

嚴(yán)格來說 widget 和 App 是不同的兩個 App 了, 他們之間要共享數(shù)據(jù)的話只能使用 App Groups 了。

首先在主 App

target -> capabilities -> App Groups

打開 App Groups 功能, 點擊 + , 設(shè)置 id 劣挫。如果重復(fù)了就改一個册养。

widget App

target -> capabilities -> App groups

這時候的 group 列表就能夠看到對應(yīng)的 group 了。勾選即可压固。

這時候已經(jīng)完成了widget 和 主 App 共享數(shù)據(jù)的前提條件球拦。

接下來還需要做的事情, 就是將我們準(zhǔn)備工作里面Userdefault相關(guān)代碼進行調(diào)整。

UserDefaults.standard 改成

UserDefaults(suiteName: "your group id")

這樣就可以在 widget 中 使用

let userdefault = UserDefaults(suiteName: "group.com.sunny.group")

獲得在主 App 中持久化的數(shù)據(jù)了帐我。關(guān)于 App Groups 其他的用法坎炼,可以繼續(xù)深入研究。

widget 的折疊和展開

蘋果的官方文檔里面明確的說了拦键,widget 的界面是不能滑動的谣光。畢竟 widget 和通知中心的滑動不能沖突啊。

所以有時候我們需要將 widget 折疊起來芬为,畢竟太長的 widget 實在是令人討厭啊萄金。

主要還是說說iOS10 上怎么做的吧,畢竟沒有iOS10 以下的設(shè)備媚朦。

在 TodayViewController 的 didLoad 中添加

        // iOS10 添加折疊按鈕
        if #available(iOSApplicationExtension 10.0, *) {
            extensionContext?.widgetLargestAvailableDisplayMode = .expanded
        } else {
// iOS8 捡絮、iOS9 上需要自己添加折疊按鈕
        }

然后實現(xiàn) NCWidgetProviding 協(xié)議中的方法

    func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) {
// 由于 iOS8 、iOS9 上沒有這個代理莲镣。需要對自己添加的按鈕設(shè)置 target-action 然后進行修改
        switch activeDisplayMode {
        case .compact:
            preferredContentSize = maxSize
        case .expanded:
            preferredContentSize = CGSize(width: 0.0, height: 60 * CGFloat(dataSource.count))
        }
    }

在 iOS8 和 iOS9 中, 由于系統(tǒng)沒有這個功能。我們只能自己寫一個按鈕然后再來做這些事情了涎拉。

widget 打開 主 App

widget 打開主 App 還是老思路瑞侮,openurl 就可以了的圆,然后在url 中添加對應(yīng)需要的參數(shù)。

準(zhǔn)備工作

主 App -> target -> info -> UrlTypes

添加一個 URlType 然后設(shè)置 URL Scheme 為你自定義的字符串半火。 比如 “sunny”越妈。

在 widget 中需要跳轉(zhuǎn)的地方寫這樣的代碼

self.extensionContext?.open(NSURL(string: "sunny://action=\(dataSource[indexPath.row])")

參數(shù)傳遞也就是按照上文, 在url中拼接了。上文有提到, widget 和 App 可以共享數(shù)據(jù)钮糖。這也可能是一種傳遞參數(shù)的方式梅掠。

這個時候打開主要 App 就是直接進入主要界面了。如果我們需要做一些其他的事情應(yīng)該怎么做呢店归?

想想以前做微信或者支付寶支付的時候阎抒, 都要在 appdelegate 中寫一些代碼。

    func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
        let prefix = "sunny://"http:// 判斷是否是可靠的地方傳遞過來的
        if url.absoluteString.hasPrefix(prefix) {
        // 參數(shù)過來了消痛! 做對應(yīng)的事情
            let a = UIAlertController(title: url.absoluteString, message: nil, preferredStyle: .alert)
            a.addAction(UIAlertAction(title: "取消", style: .cancel, handler: nil))
            self.window?.rootViewController?.present(a, animated: true, completion: nil)
            return true
        }
        return false
        
    }

others

高度

widget的默認(rèn)高度是有限制的且叁。

compact 下:

  • max = 110
  • mim = 110

expanded 下:

  • min = 110
  • max = 根據(jù)不同的機型二不同。

無論怎么設(shè)置, 都不回超出這個范圍

widgetPerformUpdate
    func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
        // Perform any setup necessary in order to update the view.
        
        // If an error is encountered, use NCUpdateResult.Failed
        // If there's no update required, use NCUpdateResult.NoData
        // If there's an update, use NCUpdateResult.NewData
        
        completionHandler(NCUpdateResult.newData)
    }

這個方法用來選擇 widget 再出現(xiàn)的時候會不會重新刷新秩伞。

通知

NSExtensionContext 中看到的幾個通知貌似不是給 TodayExtension 用的逞带。

NSExtensionContext 中能看到幾個通知他們都是監(jiān)聽 host App 的狀態(tài)的。所以對于widget 來說纱新, host App 就是 Today 這個東西啦展氓。

最后

拋磚引玉,本文用Today Extension做了一個很簡單的功能脸爱。 當(dāng)然, 我們能用他做的事情可不止這些遇汞。這就需要我們發(fā)動我們的聰明才智了。

示例代碼下載鏈接由于使用swift寫的, 由于眾所周知的原因, 你發(fā)現(xiàn)編譯不過了阅羹∩滋郏可以聯(lián)系我, 我將做適配。

原文地址: 面向 Extension 開發(fā) ?? Today Extension

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捏鱼,一起剝皮案震驚了整個濱河市执庐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌导梆,老刑警劉巖轨淌,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異看尼,居然都是意外死亡递鹉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門藏斩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躏结,“玉大人,你說我怎么就攤上這事狰域∠彼” “怎么了黄橘?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長屈溉。 經(jīng)常有香客問我塞关,道長,這世上最難降的妖魔是什么子巾? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任帆赢,我火速辦了婚禮,結(jié)果婚禮上线梗,老公的妹妹穿的比我還像新娘椰于。我一直安慰自己,他們只是感情好缠导,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布廉羔。 她就那樣靜靜地躺著,像睡著了一般僻造。 火紅的嫁衣襯著肌膚如雪憋他。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天髓削,我揣著相機與錄音竹挡,去河邊找鬼。 笑死立膛,一個胖子當(dāng)著我的面吹牛揪罕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宝泵,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼好啰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了儿奶?” 一聲冷哼從身側(cè)響起框往,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闯捎,沒想到半個月后椰弊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡瓤鼻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年秉版,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茬祷。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡清焕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秸妥,我是刑警寧澤借卧,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站筛峭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏陪每。R本人自食惡果不足惜影晓,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望檩禾。 院中可真熱鬧挂签,春花似錦、人聲如沸盼产。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽戏售。三九已至侨核,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灌灾,已是汗流浹背搓译。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锋喜,地道東北人些己。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像嘿般,于是被迫代替她去往敵國和親段标。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容