日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

Rust?搭建一個小程序運(yùn)行環(huán)境的方法詳解_相關(guān)技巧

作者:Finbird ? 更新時間: 2022-07-20 編程語言

搭建一個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

欄目分類
最近更新