網(wǎng)站首頁 編程語言 正文
搭建一個FinClip社區(qū)版docker運(yùn)行環(huán)境,安裝設(shè)置Rust開發(fā)編譯iOS代碼的環(huán)境,設(shè)置xcode的項(xiàng)目配合,集成FinClip SDK,準(zhǔn)備好實(shí)現(xiàn)從FinClip小程序到Rust算法邏輯的端到端融合。
本篇以 iOS 為例介紹開發(fā)環(huán)境的準(zhǔn)備。
從零到一:構(gòu)建一個能運(yùn)行小程序的App
我們先從FinClip官網(wǎng)下載最新的FinClip SDK,解壓后應(yīng)獲得 FinApplet.framework、FinAppletExt.framework、FinAppletWebRTC.framework、FinAppletBLE.framework 等一系列庫。
用 xcode 創(chuàng)建一個新項(xiàng)目,簡單起見我們建一個基于 Objective-C 的 Storyboard。
此處注意,我們要小心命名這個 App 并記住它的 Bundle ID,如下圖,我們這個App 的 Bundle ID 是 com.finogeeks.rustful.clip。
然后把 FinClip SDK 解壓包里的 FinApplet.framework 添加至工程里,注意勾選“Copy items if needed”。
在macOS 11.1以上使用xcode較新的版本(筆者所用版本為13.0)編譯上述項(xiàng)目,會出現(xiàn)報錯無法繼續(xù),如果你有這個情況,可在項(xiàng)目Build Settings處作以下配置。
clip.xcodeproj Building for iOS Simulator, but the linked and embedded framework 'FinApplet.framework' was built for iOS + iOS Simulator
報錯信息
Apple 從 Xcode 12.3 開始推薦使用 xcframework 替代 Framework,本文所依賴的FinClip SDK 2.36.5 尚未提供 xcframework 版本,所以有上述問題,編譯過程且有系列warning,但不影響運(yùn)行。在未來版本應(yīng)會被解決。
FinClip SDK 中包含 x86_64 架構(gòu),便于我們開發(fā)時用模擬器調(diào)試。本文主要目的是試驗(yàn)在 iOS 上 FinClip 小程序和 Rust 代碼的集成,以能運(yùn)行在 simulator 為要。但是x86_64 架構(gòu)的 SDK,打包上傳應(yīng)用市場時會報錯,如何打包時自動去除模擬器架構(gòu)的腳本,可以讓我們既可以用模擬器開發(fā)調(diào)試,又能正常提交應(yīng)用市場,不在本文探討范圍,詳情可參考官網(wǎng)iOS集成。
FinClip 安全沙箱的初始化
FinClip SDK 代碼庫成功編譯構(gòu)建至 App后,是時候進(jìn)行代碼集成。這里包括注冊生成 SDK Key 和 SDK Secret,用最少至僅 4 行代碼即可在 App 中把 FinClip SDK 初始化,準(zhǔn)備好加載運(yùn)行 FinClip 小程序。
獲得 SDK Key 以及 SDK Secret 的兩種方式
FinClip 技術(shù)分成端側(cè)和云(服務(wù)器)側(cè)兩大部分,端側(cè)即 FinClip SDK,云(服務(wù)器)側(cè)則是 FinClip 小程序管理中心/小程序商店,用于實(shí)時、動態(tài)管理小程序的上下架以及小程序開發(fā)者的管理(正如你所熟悉的互聯(lián)網(wǎng)小程序平臺一樣)。凡泰極客提供整套方案的兩種部署使用方式:
- FinClip.com Managed Service 方式:即由凡泰極客運(yùn)行云側(cè),開發(fā)者把小程序的上下架管理托管。從而降低自己在服務(wù)器端的運(yùn)維成本
- On-Premise 方式:即由開發(fā)者或開發(fā)者所在的機(jī)構(gòu),自行部署運(yùn)維FinClip服務(wù)器側(cè),自行管理自己的開發(fā)者,自行管控自己的小程序開發(fā)生態(tài)。普通開發(fā)者也可以自行免費(fèi)體驗(yàn)和使用社區(qū)版(功能和企業(yè)版版無異),在一臺個人電腦即可以運(yùn)行完整環(huán)境。
取決于我們打算用誰的服務(wù)器端,則 SDK Key 和SDK Secret 需要在該服務(wù)器生成,因?yàn)樽罱K App 所嵌入的 SDK 需要被所連接的目標(biāo)服務(wù)器作安全授權(quán)。
方式一:采用 FinClip.com 托管服務(wù)
這是最簡單直接的方式,也就是說我們準(zhǔn)備開發(fā)的小程序,將上架至 FinClip.com。(注意:本系列所描述內(nèi)容的驗(yàn)證,需要使用自己部署安裝的社區(qū)版。FinClip.com服務(wù)在此為了完整起見作簡單介紹)。
首先,需到 FinClip.com?注冊一個開發(fā)者賬戶。
其次,登錄后在管理頁面「應(yīng)用管理-新增合作應(yīng)用」,添加要集成 SDK 的目標(biāo)應(yīng)用。
具體操作詳情見關(guān)聯(lián)移動端應(yīng)用
你將獲得類似以下的 Key 和 Secret:
準(zhǔn)備把它們粘貼、復(fù)制至初始化的代碼中。
方式二:自行部署 FinClip 社區(qū)版
如果閣下按捺不止自己動手搭建一套 FinClip、擁有一個自己掌控的小程序商店,那么也可以輕而易舉的在自己的開發(fā)環(huán)境部署個社區(qū)版(作為前置條件,注意先安裝好 docker 相關(guān)工具):
mkdir my-finclip
cd my-finclip
sudo sh -c "$(curl -fsSL https://static.finogeeks.club/deploy/mop/release/install.sh)"
成功安裝后,在上述目錄下運(yùn)行:
docker-compose up -d
假如你用 MacOS 上的 Docker Desktop,打開 Dashboard 應(yīng)能看到下圖,其中每一個 container 都應(yīng)該處于 running 狀態(tài)(除了mop-init "EXITED(0)" 為正常)。
此時 FinClip 管理后臺(分成面向開發(fā)者的“企業(yè)端”以及面向運(yùn)營管理者的“運(yùn)營端”)可通過以下 URL 訪問:
- 企業(yè)端:“http://127.0.0.1:8000/mop/mechanism/#/login
- 運(yùn)營端:http://127.0.0.1:8000/mop/operate/#/login
登錄企業(yè)端與運(yùn)營端的默認(rèn)用戶名為“finclip@finogeeks.com”,密碼為“123Abc”。
首先,我們自己扮演管理角色,在運(yùn)營端登記自己準(zhǔn)備開發(fā)移動端應(yīng)用的 Bundle ID,Bundle ID 是你在 Apple App Store 或者某個 Android 應(yīng)用商店準(zhǔn)備發(fā)布的 App 的應(yīng)用標(biāo)識。
在這里作為例子,我們新增了一個 Bundle ID "com.finogeeks.rustful.clip"(記得之前在 Xcode 創(chuàng)建 App 的時候所定義的名字):
輸入后在 FinClip 也關(guān)聯(lián)了同樣的 Bundle ID
其次,我們扮演開發(fā)者角色,到企業(yè)端中,添加一款合作應(yīng)用,姑且稱之為 rust-ios,并關(guān)聯(lián)相應(yīng)的 Bundle ID:
至此,我們把以下信息關(guān)聯(lián)了起來:
- 我們要開發(fā)的 App 名稱,在這個例子里,叫“rust-ios”
- 這個 App 的 Bundle ID 是:com.finogeeks.rustful.clip,它將適用于iOS和Android,雖然在本文我們只針對 iOS 作開發(fā)。我們首先是在xcode創(chuàng)建項(xiàng)目的時候采用了這個 ID,現(xiàn)在我們把它登記到 FinClip,目的是讓平臺知道一個小程序可以運(yùn)行在什么 App 中;
- FinClip SDK 嵌入到這個 App 時,需要使用一對指定的 Key 以及 Secret 去對接服務(wù)器端
- 服務(wù)器端,取決于你用的是 FinClip.com的托管/SaaS 服務(wù),還是用自己部署的社區(qū)版。前者的 API Server是api.finclip.com;后者的話,缺省是127.0.0.1:8000。
FinClip SDK 在 App 中的初始化
現(xiàn)在我們準(zhǔn)備好在 Xcode 創(chuàng)建的 clip 項(xiàng)目中寫初始化 SDK 的代碼。在AppDelegate.m,加入以下代碼:
//
// AppDelegate.m
// clip
//
#import "AppDelegate.h"
#import <FinApplet/FinApplet.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *appKey = @"22LyZEib0gLTQdU3MUauARgvo5OK1UkzIY2eR+LFy28NAKxKlxHnzqdyifD+rGyG";
FATConfig *config = [FATConfig configWithAppSecret:@"8fe39ccd4c9862ae" appKey:appKey];
config.apiServer = @"http://127.0.0.1:8000";
[[FATClient sharedClient] initWithConfig:config error:nil];
[[FATClient sharedClient] setEnableLog:YES];
return YES;
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
@end
Rust 開發(fā)環(huán)境的準(zhǔn)備
安裝R ust 環(huán)境比較簡單,例如在 Mac/Linux上,一行腳本即可:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
其他相關(guān)內(nèi)容可參考官網(wǎng)。
為了能把 Rust 代碼編譯成 iOS、Android 的組件庫,我們需要安裝一些平臺架構(gòu)的target:
# Android targets
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
# iOS targets
rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios x86_64-apple-ios i386-apple-ios
此外,我們還需要安裝兩個工具,用于構(gòu)建 iOS 的 universal library,以及從 Rust 代碼生成 C/C++ 頭文件,供 Objective-C/Swift 的項(xiàng)目在導(dǎo)入靜態(tài)庫時使用:
# 安裝 Xcode build tools(如果已經(jīng)安裝,請忽略)
xcode-select --install
# 這個cargo subcommand用于構(gòu)建iOS上的universal library
cargo install cargo-lipo
# 這個工具用于自動生成 C/C++11 頭文件
cargo install cbindgen
# 在Android環(huán)境,請先安裝Android Studio和NDK,但不在本文討論范圍
cargo install cargo-ndk
關(guān)于 cargo-lip 的介紹,可以看這里,關(guān)于 cbindgen,可以參考這里。但實(shí)際上你也可以以后有興趣慢慢看,知其然不知其所然在這里沒毛病,不影響使用。
Rust 代碼編譯成 iOS 靜態(tài)庫的驗(yàn)證
在開始正式的開發(fā)前,我們可以寫一個簡單的“Hello World”驗(yàn)證一下上述環(huán)境。首先用 cargo 創(chuàng)建一個新的 Rust 的 Library 工程類型的項(xiàng)目,原因是我們會把這個library 導(dǎo)入到 iOS 的項(xiàng)目中并把其中函數(shù)注冊至 FinClip SDK 供小程序側(cè)通過 JavaScript 接口調(diào)用。
cargo new --lib hello
Cargo 自動生成以下目錄:
hello
|--src
| |--lib.rs
|--Cargo.toml
我們的 Cargo.toml 如下:
[package]
name = "rustylib"
version = "0.1.0"
authors = ["me <finclip@finogeeks.com>"]
edition = "2021"
[lib]
name = "rustylib"
# 構(gòu)建iOS和Android版本需要的兩個crate
crate-type = ["staticlib", "lib"]
# 編譯Android版時需要,本文不涉及,但列出在此供Android開發(fā)者參考
[target.'cfg(target_os = "android")'.dependencies]
jni = { version = "0.19.0", default-features = false }
現(xiàn)在我們修訂一下 lib.rs。因?yàn)檫@個實(shí)驗(yàn)項(xiàng)目并不是為了簡單跑一個 Rust 'Hello World',而是為了驗(yàn)證輸出一個可以供異構(gòu)語言調(diào)用的 C Library,所以在這里我們用了 Rust FFI(Foreign Function Interface)來寫(看上去比“正常”的'Hello World'復(fù)雜):
// lib.rs
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
#[cfg(target_os = "android")]
mod android;
#[no_mangle]
pub unsafe extern "C" fn hello(to: *const c_char) -> *mut c_char {
let c_str = CStr::from_ptr(to);
let recipient = match c_str.to_str() {
Ok(s) => s,
Err(_) => "you",
};
CString::new(format!("From Rust: {}", recipient))
.unwrap()
.into_raw()
}
#[no_mangle]
pub unsafe extern "C" fn hello_release(s: *mut c_char) {
if s.is_null() {
return;
}
drop(CString::from_raw(s));
}
#[no_mangle]
pub extern "C" fn hello_world() {
println!("Hello, World");
}
Rust 編譯器編譯代碼時,會修改我們定義的函數(shù)名稱,增加一些用于其編譯過程的額外信息。為了使 Rust 函數(shù)能在其它語言(例如Objective-C、Swift)中被調(diào)用,必須禁用 Rust 編譯器的名稱修改功能。所以我們使用了 no_mangle 的函數(shù)屬性聲明去指示編譯這些準(zhǔn)備注冊到 FinClip SDK 的函數(shù)。
另外,我們還使用了 extern "C"的聲明,以告知編譯器這些被如此聲明的函數(shù)是為了供 Rust 以外的其他語言代碼調(diào)用,編譯器需要保證按C語言的標(biāo)準(zhǔn)規(guī)范去編譯輸出。
其他更多關(guān)于 FFI(Foreign Function Interface)以及 unsafe 等 Rust 語言的能力,不是本文焦點(diǎn),可參考 Rust 相關(guān)方面的內(nèi)容。在本系列后面的章節(jié)也會繼續(xù)涉及。
為了能驗(yàn)證一下上述函數(shù)能否運(yùn)行,我們編寫一個測試?yán)樱?/p>
cd hello
mkdir examples
touch examples/test.rs
一個簡單的測試如下:
// test.rs
use std::ffi::{CStr, CString};
use rustylib::{hello, hello_release};
fn main() {
let input = CString::new("Hello, world!").unwrap();
unsafe {
let c_buf = hello(input.as_ptr());
let slice = CStr::from_ptr(c_buf);
println!("{}", slice.to_str().unwrap());
hello_release(c_buf);
}
}
在 hello 項(xiàng)目的根目錄下,運(yùn)行測試:
cargo run --example test
應(yīng)產(chǎn)生如下結(jié)果:
Blocking waiting for file lock on build directory
Compiling rustylib v0.1.0 (/Users/myself/projects/hello)
Finished dev [unoptimized + debuginfo] target(s) in 5.89s
Running `target/debug/examples/test`
From Rust: Hello, world!
現(xiàn)在可以嘗試為 iOS 進(jìn)行編譯:
$ cargo lipo --release
我們可以檢查一下生成的靜態(tài)庫:
lipo -info target/aarch64-apple-ios/release/librustylib.a Non-fat file: target/aarch64-apple-ios/release/librustylib.a is architecture: arm64
ipo -info target/x86_64-apple-ios/release/librustylib.a
Non-fat file: target/x86_64-apple-ios/release/librustylib.a is architecture: x86_64
但我們用于開發(fā)的是一個合并了上述兩個架構(gòu)的通用庫 Fat library,在以下目錄中:
ls -l target/universal/release/librustylib.a
要在 iOS 驗(yàn)證這部分代碼,可以先生成一個 C 的頭文件,在 hello 這個 Rust 項(xiàng)目的根:
cbindgen src/lib.rs -l c > rustylib.h
然后把這個頭文件添加至AppDelegate.m,再對其進(jìn)行修訂,把'hello'和'hello_release'直接按C的方式調(diào)用一下即可。代碼非常簡單,不在此贅述。但是在xcode中需要把上述生成的librustylib.a以及rustylib.h添加至項(xiàng)目中(如果不是iOS開發(fā)者不熟悉xcode,可以跳過本部分驗(yàn)證,繼續(xù)閱讀本系列后續(xù)篇章的詳細(xì)介紹)。
至此,我們把iOS Native App、FinClip SDK和Rust library三個部分集成起來,接下來的內(nèi)容,將是聚焦開發(fā)一個比“Hello World”復(fù)雜點(diǎn)的、確實(shí)適合用Rust實(shí)現(xiàn)的library,并讓它通過FinClip小程序來展現(xiàn)人機(jī)交互的界面。開發(fā)過程所用到的工具有點(diǎn)多,你需要:
- xcode:用于編譯構(gòu)建“殼”應(yīng)用,以及通過simulator測試你的應(yīng)用
- FinClip IDE:用于開發(fā)調(diào)試小程序
- FinClip.com(或者運(yùn)行在你本地電腦上的FinClip社區(qū)版)的企業(yè)端和運(yùn)營端
- vscode以及一些有助于開發(fā)測試Rust代碼的extension(當(dāng)然,你也可以用其他vscode替代工具)
對于首次開發(fā)Rust的朋友,在vscode推薦安裝以下extension:
- Better TOML,用于支持Cargo.toml文件的syntax highlight
- crates,用于支持Cargo.toml中crate的版本依賴關(guān)系管理
- rust-analyzer,似乎優(yōu)于官方的rust extension
- CodeLLDB,能支持C++、Rust等編譯語言的debugger
- Tabnine AI Auto-complete,一句話,智能好使
原文鏈接:https://juejin.cn/post/7099009847865114632
相關(guān)推薦
- 2022-10-05 Android?Flutter實(shí)現(xiàn)原理淺析_Android
- 2022-06-27 Python利用re模塊實(shí)現(xiàn)簡易分詞(tokenization)_python
- 2022-12-24 C++中STL容器的主要使用及含義說明_C 語言
- 2023-01-07 Python數(shù)據(jù)類型轉(zhuǎn)換實(shí)現(xiàn)方法_python
- 2022-02-03 ionic4 ngFor中使用ngIf
- 2022-07-15 Golang配置解析神器go?viper使用詳解_Golang
- 2023-01-29 Python??序列化反序列化和異常處理的問題小結(jié)_python
- 2022-10-22 C#中的屬性解析(get、set、value)_C#教程
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支