天天看點

在 Flutter 中玩轉 Objective-C Block

雲栖号資訊:【 點選檢視更多行業資訊

在這裡您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

dart_native 作為一條比 Channel 性能更高開發成本更低的超級通道,通過 C++ 調用 Native 的 API,深入底層且考慮全面。很多 Objective-C 接口的參數和傳回值是 Block,是以這就需要支援用 Dart 語言建立和調用 Objective-C Block。

Dart 調用 Objective-C 帶 Block 的 API

Dart 語言支援協程,這樣就無需傳遞閉包來作為異步調用的回調。而 Objective-C 大量 API 都使用 Block 作為回調,當 Dart 調用這類異步 API 的時候,就需要 Dart 側建立 Block 并傳遞給 Objective-C。

Dart 語言中的 Function 可以當做閉包,可以實作下面這樣的效果:

在 Flutter 中玩轉 Objective-C Block

而對應的 Objective-C 接口如下:

在 Flutter 中玩轉 Objective-C Block

下面就講下 dart_native 是如何做到把 Dart Function 當做 Block 傳給 Objective-C 的。

函數簽名

首先要確定的是 Dart Function 的簽名跟 Objective-C Block 是一緻的,這樣二者才能轉換。在 Dart 裡一切皆為對象,Function 也不例外。那麼拿到 Function 的 runtimeType 即可,然後解析其内容。不過 runtimeType 的内容都是 Dart 類名,如何能與 Objective-C 類型對應上呢?dart_native 的政策是提供與 Native 同名的類,這樣使用這些同名類定義 Dart Function,就可以把函數簽名映射到 Native 上了。

列舉一些 Dart 聲明的基礎類型:

在 Flutter 中玩轉 Objective-C Block

動态建立 Block

有了函數簽名,如何構造對應的 Block 對象呢?首先要知道 Block 是什麼,而這是就又個老生常談的話題了。我十分建議你先了解下 BlockHook 及其相關文章,這樣會對了解這部分内容有很大幫助。

廢話不多說,上硬核:

在 Flutter 中玩轉 Objective-C Block
在 Flutter 中玩轉 Objective-C Block
在 Flutter 中玩轉 Objective-C Block

簡單來說,動态建立 Block 的流程封裝在了一個 Wrapper 類中,步驟如下:

• 用 libffi 動态建立相同簽名的函數,

• 準備好建立 Block 需要的 flag、description、signature 和 wrapper 對象等

• 根據 Block 的記憶體模型建立對應的結構體(棧上)

• 把 Block 對象 copy 到堆上,并發送 autorelease 消息

這上面每一步其實都不簡單,單獨拆出來都能寫一段。但因為 bang 大佬已經寫過文章介紹過了,我這裡就不再贅述了。我隻是站在巨人的肩膀上,增加了一些改進和對 Dart 的适配(如支援結構體、x86 相容等)。很慚愧,就做了一點微小的工作。

映射 Block 和 Dart Function

Block 對象建立好了,需要跟 Dart Function 映射起來,然後當 Block 被執行的時候才會調用到對應的 Dart 邏輯。

關于回調這塊,我在 Dart 側維護一個 Map 來管理 Native 到 Dart 的回調映射。基本思路是,Key 為 Native 對象的位址,Value 為 Dart 側的 Block 類。

Dart 版的 Block 類構造方法裡會将映射建立起來:

在 Flutter 中玩轉 Objective-C Block

在 Block 類的 dealloc 方法裡會移除映射,防止造成 Dart 版的『野指針』。

在 Flutter 中玩轉 Objective-C Block

Dart 調用 Objective-C 傳回的 Block

結合對 Block 的了解以及實踐過 Dart 調用 OC 方法的經驗,很容易在 Dart 版的 Block 中實作個 invoke 方法:

在 Flutter 中玩轉 Objective-C Block
在 Flutter 中玩轉 Objective-C Block

簡單來說上面的實作做了如下幾步:

• 擷取 Block 的函數簽名

• 校驗 Dart 測傳入的參數清單是否符合函數簽名

• 将 Dart 參數轉為 Native 對應的類型,寫入堆中

• 調用 C 函數 blockInvoke,将 Block 指針和參數清單二級指針傳過去

• 釋放二級指針(其指向的對象類型和堆上的結構體會自動釋放)

• 将 blockInvoke 傳回的指針内容轉為 Dart 對象

後續

關于 Block 這塊其實還有很多技術細節沒有叙述完整,包括 copy 方法的實作,回調映射的細節,類型自動轉換的細節等。因為篇幅原因,感興趣的可以直接看源碼:

https://github.com/dart-native/dart_native

其實我期望的是使用 Dart 的協程來完成處理異步回調,這樣更現代更優雅。日後會基于此方案再次封裝上層接口,支援協程。

dart_native 作為一條深入底層且考慮全面的 Dart 到 Native 超級通道,未來還要做的事情還有很多。

【雲栖号線上課堂】每天都有産品技術專家分享!

課程位址:

https://yqh.aliyun.com/live

立即加入社群,與專家面對面,及時了解課程最新動态!

【雲栖号線上課堂 社群】

https://c.tb.cn/F3.Z8gvnK

原文釋出時間:2020-04-15

本文作者:楊蕭玉

本文來自:“

玉令天下的部落格

”,了解相關資訊可以關注“玉令天下的部落格”