來(lái)源: Cross platform native mobile development with Rust (sandigital.uk)
Cross platform native mobile development with Rust
使用 Rust 進(jìn)行跨平臺(tái)原生移動(dòng)開(kāi)發(fā)
San Digital have extensive experience of mobile development and the use of Android as an embedded operating system. We treated android as a deployment target target for Rust firmware as well as writing our intricate real time communications component for both iOS and Android. This approach has advantages, you can maintain a single code base for a complicated communications layer, while also taking advantage of the full native capabilities of each platform.
San Digital 擁有豐富的移動(dòng)開(kāi)發(fā)經(jīng)驗(yàn)和使用 Android 作為嵌入式操作系統(tǒng)的經(jīng)驗(yàn)狸相。我們將 Android 作為 Rust 固件的部署目標(biāo),同時(shí)也為 iOS 和 Android 編寫復(fù)雜的實(shí)時(shí)通信組件。這種方法有很多優(yōu)點(diǎn)蛔溃,您可以為復(fù)雜的通信層維護(hù)單一的代碼庫(kù)取试,同時(shí)還可以利用每個(gè)平臺(tái)的完全原生功能胸梆。
While building our Smart Home / Smart Energy platform for Presciense, we wanted to differentiate ourselves from the majority of products on the market that suffered from high latencies. Even while connected to the same network as many IoT gateways at the time, a simple operation like turning a light on and off could take multiple seconds to both perform and display on the application. The biggest contributor to these latencies (and also availability problems at scale) was the use of centralised, rather than peer to peer communications between the mobile handset and gateway. Along with this, most competitors used synchronous http or polling tricks to act on a device and receive data on its state. We came up with design utilising multiple factors to achieve low latency and reduce overall operational costs at high scales.
在為 Presciense 打造我們的智能家居/智能能源平臺(tái)時(shí)硼控,我們希望將自己與市場(chǎng)上大多數(shù)受到高延遲影響的產(chǎn)品區(qū)分開(kāi)來(lái)蚁飒。即使同時(shí)與許多物聯(lián)網(wǎng)網(wǎng)關(guān)連接到同一網(wǎng)絡(luò),像開(kāi)燈和關(guān)燈這樣的簡(jiǎn)單操作也可能需要數(shù)秒才能在應(yīng)用程序上執(zhí)行和顯示锅风。造成這些延遲(以及大規(guī)乃址蹋可用性問(wèn)題)的最大原因是在移動(dòng)手持設(shè)備和網(wǎng)關(guān)之間使用集中通信,而不是點(diǎn)對(duì)點(diǎn)通信皱埠。與此同時(shí)肮帐,大多數(shù)競(jìng)爭(zhēng)對(duì)手使用同步 http 或輪詢技巧來(lái)操作設(shè)備并接收其狀態(tài)的數(shù)據(jù)。我們提出了利用多種因素來(lái)實(shí)現(xiàn)低延遲并在高規(guī)模下降低整體運(yùn)營(yíng)成本的設(shè)計(jì)边器。
Secure, zero password p2p communications while on the same network as the gateway
Everything asynchronous, from invocations to state updates
Aggressive approach to packet sizes and overall data use
安全训枢,在同一網(wǎng)關(guān)網(wǎng)絡(luò)下的零密碼 p2p 通信
從調(diào)用到狀態(tài)更新,一切都是異步的
優(yōu)秀的數(shù)據(jù)包大小和整體數(shù)據(jù)使用
Achieving these features and NFRs set over 2 mobile platforms (along with our linux based command line tools for testing) is a challenge for a small team, as to do so we needed:
對(duì)于一個(gè)小型團(tuán)隊(duì)來(lái)說(shuō)忘巧,要在兩個(gè)移動(dòng)平臺(tái)上實(shí)現(xiàn)這些功能和 NFR(以及基于Linux的命令行工具進(jìn)行測(cè)試)是一個(gè)挑戰(zhàn)恒界,為此,我們需要:
Gateway discovery, LAN and internet connectivity
TLS 1.3, as it solved security issues that made our local PKI much simpler, but was not yet available on mobile platforms
Highly efficient binary protocol using Captain Protocol and shared dictionaries
Real time messaging utilising operational transformations within 50ms time windows to combine outgoing commands and state changes into their simplest possible representations
A memory efficient DOM, updated asynchronously as devices connected to the gateway changed state
網(wǎng)關(guān)發(fā)現(xiàn)砚嘴,局域網(wǎng)和互聯(lián)網(wǎng)連接
TLS 1.3十酣,它解決了安全問(wèn)題使我們本地 PKI 更簡(jiǎn)單,但在移動(dòng)平臺(tái)上還不可用
使用船長(zhǎng)協(xié)議和共享字典的高效二進(jìn)制協(xié)議
利用50毫秒時(shí)間窗口內(nèi)的操作轉(zhuǎn)換將傳出命令和狀態(tài)更改組合成最簡(jiǎn)單的可能表示的實(shí)時(shí)消息傳遞
一個(gè)內(nèi)存效率高的 DOM枣宫,當(dāng)連接到網(wǎng)關(guān)的設(shè)備狀態(tài)改變時(shí)異步更新
A component this intricate would be difficult to both develop, test and maintain over the 3 required platforms. Having this client functionality as a cross platform component that could also be tested on a non mobile platform independently of a user interface seemed to have a number of advantages, as did developing a client in the same language and ecosystem as our firmware - Rust.
如此復(fù)雜的組件在三個(gè)平臺(tái)上都很難開(kāi)發(fā)婆誓、測(cè)試和維護(hù)。將這種客戶端功能作為一個(gè)跨平臺(tái)組件也颤,可以在非移動(dòng)平臺(tái)上獨(dú)立于用戶界面進(jìn)行測(cè)試洋幻,這似乎有很多優(yōu)勢(shì),就像用我們的固件—— Rust 開(kāi)發(fā)相同語(yǔ)言和生態(tài)系統(tǒng)的客戶端一樣翅娶。
Rust's pros and cons as a general purpose or systems programming language are discussed at great length in other places, but any language that has a bidirectional, transparent C ABI is highly amenable to integration into other language ecosystems. In the end, almost everything in modern software will be able to call into a Rust library.
Rust 作為一種通用或系統(tǒng)編程語(yǔ)言的優(yōu)缺點(diǎn)在其他地方已經(jīng)詳細(xì)討論過(guò)了文留,但是任何具有雙向、透明的 C ABI 的語(yǔ)言都很容易集成到其他語(yǔ)言生態(tài)系統(tǒng)中竭沫。到最后燥翅,幾乎所有現(xiàn)代軟件都能調(diào)用 Rust 庫(kù)。
An architecture for native cross platform development
原生跨平臺(tái)開(kāi)發(fā)架構(gòu)
Cross compilation
交叉編譯
Rust, as a system programming language has supported native targets for a bewildering number of chip sets and platforms. Usefully, this includes iOS and 64 bit android - 32 bit android can be a little more difficult due to some interesting design choices in its LibC design but it only a common target in embedded systems rather than handsets or tablets nowadays.
Rust蜕提,作為一種系統(tǒng)編程語(yǔ)言森书,支持大量的芯片集和平臺(tái)的原生目標(biāo)。有用的是谎势,這包括 iOS 和 64 位 Android - 32 位 Android 可能有點(diǎn)困難凛膏,因?yàn)樗?LibC 設(shè)計(jì)中有一些有趣的設(shè)計(jì)選擇,但它只是嵌入式系統(tǒng)的一個(gè)常見(jiàn)目標(biāo)脏榆,而不是手機(jī)或平板電腦猖毫。
For Android, you will require a .so, which needs no additional tooling. For iOS, you will need a universal static library generated by the cargo-lipo tool.
對(duì)于 Android,您將需要 .so
须喂,它不需要額外的工具吁断。對(duì)于 iOS趁蕊,你需要一個(gè)由cargo-lipo 工具生成的通用靜態(tài)庫(kù)。
C ABI / Swift interface
C ABI / Swift 接口
Rust has a built in way of declaring functions to be accessible via a C ABI, but it is convenient to use additional tooling to generate and maintain a header file automatically for use by swift and other potential consumers. The sn-bingen crate is at the time of writing the most well maintained tool for this.
Rust 采用了一種內(nèi)置的方式來(lái)聲明可以通過(guò) C ABI 訪問(wèn)的函數(shù)仔役,但是使用額外的工具來(lái)自動(dòng)生成和維護(hù)頭文件很方便掷伙,供 Swift 和其他潛在使用者使用。sn-bingen 包是在編寫此工具時(shí)維護(hù)得最好的工具骂因。
Android / JNI interface
Android / JNI 借口
As Android uses Java, you cannot directly call standard C ABI functions and must implement a JNI interface. The painful way to do this was via traditional tooling like SWIG, on top of the C interface. There is however now mature support for exporting a JNI interface directly from a Rust library using the reliably named JNI crate.
由于 Android 使用 Java炎咖,您不能直接調(diào)用標(biāo)準(zhǔn)的 C ABI 函數(shù),必須實(shí)現(xiàn)一個(gè) JNI 接口寒波。要做到這一點(diǎn)乘盼,最痛苦的方法是在 C 接口之上通過(guò)傳統(tǒng)工具(如 SWIG)。不過(guò)俄烁,現(xiàn)在已經(jīng)有了成熟的支持绸栅,可以使用可靠的 JNI 包直接從 Rust 庫(kù)導(dǎo)出 JNI 接口。
Rust interface
Rust 借口
The two binding interfaces, C and JNI can be conditionally compiled depending on target architecture and share dispatch to a Rust API shared between them. Both binding interfaces require unsafe code due to raw pointer use, but this can be contained within the interface functions. Once you reach this point in the abstraction, you have the full power of standard rust and its ecosystem.
這兩個(gè)綁定接口 C 和 JNI 可以根據(jù)目標(biāo)體系結(jié)構(gòu)有條件地編譯页屠,并將分派共享到它們之間共享的 Rust API粹胯。由于原始指針的使用,兩個(gè)綁定接口都需要不安全的代碼辰企,但這可以包含在接口函數(shù)中风纠。一旦你達(dá)到了這個(gè)抽象點(diǎn),你就擁有了標(biāo)準(zhǔn) Rust 及其生態(tài)系統(tǒng)的全部力量牢贸。