日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS 10 的一个重要更新-开发 iMessage 的第三方插件

發布時間:2024/8/26 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS 10 的一个重要更新-开发 iMessage 的第三方插件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

蘋果官方的 Messages 在 iOS 10 推出了非常重大的更新,可能主要是想從其他 IM 巨頭手里搶點市場份額回來,包括 Facebook Messenger, Wechat 和 Snapchat。

?

一個重要的新功能是,用戶可以直接在 Messages 里使用第三方開發者開發的擴展插件了。這個功能是在 iOS 8 引入的 Extension 技術基礎上實現的,可以參考我們往年系列里 Sam Davies 寫的文章。Messages 插件的一大好處是,它是可以獨立于 app 存在的,不用跟父 app 打包在一起。今年晚些時候 iOS 10 將會發布一個小巧的 Messages App Store,里面會有一堆插件供用戶挑選。

?

為了演示一下這個令人興奮的插件功能,我們看一個簡單的例子吧,這個插件可以讓兩個用戶玩一個簡化版的流行游戲 Battleships。為了讓約束布局方面簡單一些,我們只考慮豎屏的情況。為方便大家下載這個 demo,我把它放到Github上了。

http://t.cn/RcLmZ0e

?

游戲規則是這樣的:

?

  • 玩家 A 發起游戲,在棋盤上布置兩個『戰艦』,然后隱藏起來

  • 另一個玩家 B 要猜測戰艦的位置

  • 如果猜中了兩艘隱藏戰艦的位置,玩家 B 就贏了;但是如果猜錯 3 次,玩家 B 就輸了。

?

建工程

?

用 Xcode 新建一個插件工程非常簡單。只需點擊 File -> New Project,然后在窗口中選擇 iMessage Application。

給工程起個名字,然后語言選擇 Swift(本系列均使用 Swift 語言示例),這就完事了。因為有一個自動生成的MessagesExtensiontarget ,然后默認的Info.plist里帶有必需的配置(插件界面的 storyboard 以及插件的類型等),所以只要運行工程,Messages 就能自動識別出我們的插件了。

?

改 Display Name

?

如果在模擬器里運行MessagesExtension這個 target,它會讓你選擇在哪個 app 里運行這個插件。我們選擇Messages。

?

在 Messages 里運行

?

Messages 打開的時候,應該能在輸入框下方看到我們的插件。如果看不到,可能需要點擊 “Applications” icon,然后再點 4 個橢圓的 icon,從里面選擇我們的插件。

?

現在里面啥也沒有,不過我們將很快改變這一點。眼下最迫切的是要把我們插件的 display name 改改:現在顯示的是 “MessagesExtension”(實際上是 “MessagesEx…” 后面被截掉了)。下面我們點擊 target,然后把Display Name輸入框里的名字改一改。

?

改 display name

?

棋盤

?

我們需要展示的是 3×3 的棋盤。有很多實現方法,我用的是 UICollectionView。在本教程里,畫界面這一塊并不重要,因此實現細節不再詳述了。

?

數據模型

?

為了記錄一局游戲本身以及游戲的狀態,我們定義以下兩個結構體:

?

struct GameConstants {

????/// 一共需要布置的戰艦數

????static let totalShipCount = 2

????/// 允許玩家 B 失敗的次數

????static let incorrectAttemptsAllowed = 3

}

?

struct GameModel {

????/// 戰艦的位置

????let shipLocations: [Int]

????/// 游戲是否已經結束

????var isComplete: Bool

}

?

MessagesViewController

?

MessagesViewController 是我們插件的入口點。它是MSMessagesAppViewController的子類,相當于是 Messages 插件的 root View Controller。自動生成的模板里面包含了一些供我們重寫的方法,比如插件啟動狀態下用戶收到消息的回調函數。待會我們就要用到其中的一部分方法。

?

第一點要注意的是,我們的插件啟動之后有兩種可能的 presentation style:

?

  • compact

  • expanded

?

compact是用戶從應用托盤里打開插件的模式,插件顯示在鍵盤區域里。expanded則多給了一些喘息的空間,插件占據大部分的屏幕。

?

為了讓代碼整潔一些,我們會用不同的 view controller 來分別實現兩種模式,并且把這些 view Controller 都加為MessagesViewController的子 view controller。

?

幾個子 View Controller

?

本文不會花太長篇幅來描述這些 controller 的實現細節,只會重點關注在收發信息的過程,游戲狀態和數據是怎么變化的。關于具體實現,請自行閱讀 Github 上的源碼。

?

GameStartViewController

?

我們的插件剛啟動的時候處于compact狀態。這點空間并不夠展示游戲的棋盤,在 iPhone 上尤其不夠。我們可以簡單粗暴地立即切換成expanded狀態,但是蘋果官方警告不要這么做,畢竟還是應該把控制權交給用戶。

?

于是,我們來顯示一個簡單的歡迎界面,里面有一個 label 和一個 button。按下 button 的時候,再切換到游戲的主界面,用戶就可以開始放置『戰艦』了。

?

Ship Location View Controller

?

這個 view controller 是玩家 A 布置戰艦的界面。

?

我們實現gameBoard的onCellSelection方法來控制 cell 的樣式:上面有戰艦的 cell 顯示為綠色,空白的顯示為藍色。

?

shipsLeftToPosition返回 0 時,結束按鈕會變得可點。這個按鈕的點擊事件是一個叫completedShipLocationSelection:的IBAction方法,它會新建一個游戲 model,然后使用 UIImage 的 extension 來創建一張游戲棋盤的截圖(我們會先reset()棋盤,所以截圖的時候戰艦的位置是隱藏的——現在可不是揭曉謎底的時候!)。這張截圖在待會發消息的時候會用到。

?

Ship Destroy View Controller

?

當玩家 B 點擊對話中的消息時,我們希望他能看到一個略微不同的 view controller —— 一個能讓他尋找隱藏戰艦的界面。

?

我們還是實現棋盤的onCellSelection方法。這一次我們把選擇的 cell 位置與玩家 A 布置的位置匹配的(『擊中戰艦』)標為綠色,如果沒有擊中就標為紅色。

?

游戲結束后,不管是因為 3 條命用完了,還是因為兩條戰艦都找出來了,我們都會相應地記錄在數據模型中,然后調起游戲結束的回調。

?

添加子 Controller

?

回到我們的MessagesViewController,我們現在可以把子 controller 們加進去了。

?

class MessagesViewController: MSMessagesAppViewController {

????override func willBecomeActive(with conversation: MSConversation) {

????????configureChildViewController(for: presentationStyle, with: conversation)

????}

?

????override func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) {

????????guard let conversation = self.activeConversation else { return }

????????configureChildViewController(for: presentationStyle, with: conversation)

????}

}

?

這兩個方法是繼承自MSMessagesAppViewController的,分別提醒我們插件啟動了(比如被用戶打開了)以及要變換到另一種 presentation style 了。我們利用這兩個方法來配置子 view controller。

?

上面這個方法決定了我們該向當前的用戶展示哪個子 view controller。如果處于compact 模式,那么應該顯示 “start game” 界面。

?

如果處于expanded模式,我們需要判斷是 A 玩家還是 B 玩家。如果是 B 玩家在對話界面中點擊消息,此時conversation.selectedMessage就不會是 nil,這說明游戲已經開始了,所以我們要展示ShipDestroyViewController。否則就展示ShipLocationViewController。

?

切換界面模式

?

在GameStartViewController點擊 “start game” 按鈕,我們希望插件能切換到expanded模式,好讓我們展示棋盤。

?

// 在 'createGameStartViewController' 里

controller.onButtonTap = {

????[unowned self] in

????self.requestPresentationStyle(.expanded)

}

?

?

切換到 expanded 模式

?

創建『可以更新』的消息

?

之前在 Messages 里面,任何新的內容——不管是新的短信還是表情——都會以一條新消息的形式出現在對話的底部,跟之前的所有消息都不相干。

?

然而,這一點可能帶來很多麻煩:比如,一個下國際象棋的游戲插件會造成每走一步棋都要發一條新消息。而我們理想中的情況應該是更新后的消息能代替之前的消息。

?

謝天謝地,蘋果也想到了這一點,給我們提供了一個類MSSession——這個類沒有屬性也沒有方法,只是用來更新消息的。

?

我們發一條消息的時候,就用這個 session 來告訴 Messages,要覆蓋此前 session 相同的信息。前一條信息會被從聊天記錄中移除,然后新的信息插入到底部。

?

使用聯系人姓名

?

最近幾年,蘋果一直說要把保護用戶隱私當做頭等大事。對 Messages framework 來說確實如此:你并不能得到用戶的身份,只能得到一個每個設備不同的UUID。也就是說,你不能在消息里加入發消息的用戶的身份 ID,然后指望收消息的用戶能通過這個 ID 識別出發消息的是誰。

?

另外,你只能訪問到用戶點擊的那條消息的內容,不能訪問到對話中任何其他消息的內容(而且點擊的這條消息還必須是從你的插件發出來的)。

?

MSConversation 這個類有兩個屬性localParticipantIdentifier和remoteParticipantIdentfiers,可以用來顯示對話雙方的名字。要加一個前綴$。

?

let player = "$\(conversation.localParticipantIdentifier)"

?

把它放在消息里發出去,Messages 會解析這個 UUID,然后顯示出對應的聯系人姓名。

?

顯示聯系人姓名

?

收發應用數據

?

游戲狀態的數據是以 URL 的形式傳遞的。你的插件裝在任意一臺手機上,都應該有能力解析這個 URL,展示相關的內容。

?

使用 URL 的另一個好處是,它還能為 MacOS 用戶提供一個備用方案。不幸的是,MacOS 上的 Messages 應用并不支持插件功能。文檔里是這樣說的:

?

如果在 macOS 上點擊這條信息,系統會轉到 web 瀏覽器打開這個 URL。所以這個 URL 應該定向到你自己的 web service,基于 URL 里 encode 的數據為用戶呈現合理的結果。

?

要構建這個 URL,我們可以使用URLComponents,組合一個 base url 和一群URLQueryItems(都是有效的鍵值對)。

?

extension GameModel {

????func encode() -> URL {

????????let baseURL = "www.shinobicontrols.com/battleship"

?

????????guard var components = URLComponents(string: baseURL) else {

????????????fatalError("Invalid base url")

????????}

?

????????var items = [URLQueryItem]()

?

????????// 戰艦的位置

????????let locationItems = shipLocations.map {

????????????location in

????????????URLQueryItem(name: "Ship_Location", value: String(location))

????????}

?

????????items.append(contentsOf: locationItems)

?

????????// 游戲結束

????????let complete = isComplete ? "1" : "0"

?

????????let completeItem = URLQueryItem(name: "Is_Complete", value: complete)

????????items.append(completeItem)

?

????????components.queryItems = items

?

????????guard let url = components.url else {

????????????fatalError("Invalid URL components")

????????}

?

????????return url

????}

}

?

最后得出的 url 結果形如:www.shinobicontrols.com/battleship?Ship_Location=0&Ship_Location=1&Is_Complete=0

?

而解碼基本與此過程相反:先得到 url,取出每個鍵值對,由每個對應的值來構建游戲的數據模型。

?

在聊天對話中插入信息

?

經過前面的艱苦努力,我們終于創建出了這條消息,準備好讓玩家在對話中發給其他玩家了。

?

/// 構建一條消息,然后插入到對話中

func insertMessageWith(caption: String,

?????????????????? _ model: GameModel,

?????????????????? _ session: MSSession,

?????????????????? _ image: UIImage,

?????????????????? in conversation: MSConversation) {

????let message = MSMessage(session: session)

????let template = MSMessageTemplateLayout()

????template.image = image

????template.caption = caption

????message.layout = template

????message.url = model.encode()

?

????// 我們構建好這條消息之后,把它插入對話中

????conversation.insert(message)

}

?

就像前面說過的那樣,這條消息是用一個 session 創建的,這樣我們就可以覆蓋對話中同一個 session 的信息了。

?

為了修改消息的外觀,我們要用到MSMessageTemplateLayout。它能讓我們修改消息的一系列屬性,在這個例子里主要用到caption(文字)和image(圖片)。

?

修改完消息的外觀,配置好 session 和 URL 屬性,我們終于可以把消息插進對話中了。最后這行代碼會把消息放進 Messages 的輸入框里。注意:我們沒有權限直接把這條消息發出去——只能放進輸入框里。

?

結束啦

?

插入完這條消息之后,我們的插件也沒有必要再在這閑待著了。用戶可以手動把它關掉,不過為了讓他們體驗好一點,所以我們調用這行代碼,自己結束掉MessagesViewController的生命:

?

self.dismiss()

?

?

擴展閱讀

?

謝謝你看完這么長一篇文章,希望能讓你對于 iOS 10 Message 應用的強大功能略窺一二。

目前的 beta 版肯定少不了一些小問題:iOS 模擬器啟動 Messages 應用速度很慢,而且有時就是加載不出來插件——我經常需要從 Messages 的應用托盤里手動重啟我的插件。而且 Messages framework 非常『絮叨』:打出來的 log 簡直多到極點。當然,在 iOS 10 結束 beta 之后這些問題都會得到解決,不過目前這種狀態下你還是需要一雙火眼金睛,從大量 debug 信息里尋找跟你插件有關的內容,比如 AutoLayout constraint 沖突之類。

?

轉載于:https://www.cnblogs.com/fengmin/p/6006622.html

總結

以上是生活随笔為你收集整理的iOS 10 的一个重要更新-开发 iMessage 的第三方插件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。