- Install your Rust nightly environment: https://www.rust-lang.org/tools/install
- Install Xcode from the App Store.
- For Rust we suggest VS Code: https://code.visualstudio.com/
Following rust targets must be installed:
rustup +nightly target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
Create a new iOS application or open your existing project.
Copy Xcode build script from Examples/Rust/xcode_build_step.sh
into your project (in this guide we assume that it is copied to the sources root folder).
- Add
Run Script
phase to your target - Move it before
Build Sources
phase - Change script to
exec bash ${SRCROOT}/xcode_build_step.sh CApp app
. WhereCApp
is a name for the exported Swift module andapp
is a name of the rust library target in theCargo.toml
.
- Add Package Dependency to the project:
https://github.com/tessetact-one/Tesseract.swift
. - Add
TesseractTransportsClient
library dependency for application target.
cargo new app --lib
- Add the dependencies:
[dependencies]
tesseract-swift = { version = "0.5", features = ["client"] }
tesseract-one = { version = "0.5", features = ["client"] }
tesseract-protocol-test = { version = "0.5", features = ["client"] }
[build-dependencies]
cbindgen = "0.26"
- specify the type of library
[lib]
crate-type = ["staticlib"]
- create
build.rs
file for C headers generation
extern crate cbindgen;
use std::env;
use std::path::Path;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let profile = env::var("PROFILE").unwrap();
let name = env::var("CARGO_PKG_NAME").unwrap();
let header_path = Path::new(&crate_dir)
.join("target")
.join(&profile)
.join("include")
.join(format!("{}.h", name));
cbindgen::generate(&crate_dir)
.expect("Unable to generate bindings")
.write_to_file(&header_path);
}
- Create
cbindgen.toml
file with this contents
include_version = true
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
tab_width = 2
language = "C"
documentation_style = "doxy"
pragma_once = true
cpp_compat = true
after_includes = "@import CTesseractShared;"
[enum]
prefix_with_name = true
[parse]
parse_deps = true
include = ["tesseract-swift", "tesseract-swift-utils", "tesseract-swift-transport"]
[export]
exclude = [
"CFutureString", "SyncPtr_Void", "ClientTransport", "Void",
"CError", "CString", "CStringRef", "CAnyDropPtr"
]
Now you can export C functions, initialize Tesseract and start calling the Wallet.
Create application initialization function in Rust. Initialize Tesseract in it
use tesseract_one;
use tesseract_protocol_test;
use tesseract_swift::error::TesseractSwiftError;
use tesseract_swift::client::transport::*;
use tesseract_swift::utils::{error::CError, ptr::SyncPtr, Void};
use std::mem::ManuallyDrop;
use std::sync::Arc;
// Your application context. Put all needed data here.
// Rust only structure
struct AppContext {
service: Arc<dyn tesseract_one::client::Service<Protocol = tesseract_protocol_test::Test>>,
}
// Type-erased App Context pointer for Swift.
#[repr(C)]
pub struct AppContextPtr(SyncPtr<Void>);
// Helper methods for pointer
impl AppContextPtr {
fn new(ctx: AppContext) -> Self {
Self(SyncPtr::new(ctx).as_void())
}
unsafe fn unowned(&self) -> &AppContext {
self.0.as_typed_ref().unwrap()
}
unsafe fn owned(&mut self) -> AppContext {
self.0.take_typed()
}
}
// App init method
#[no_mangle]
pub unsafe extern "C" fn app_init(
alerts: AlertsDelegate, transport: ClientTransport,
value: &mut ManuallyDrop<AppContextPtr>,
error: &mut ManuallyDrop<CError>
) -> bool {
TesseractSwiftError::context(|| {
let tesseract = Tesseract::new(TransportDelegate::arc(alerts))
.transport(transport);
let service = tesseract.service(tesseract_protocol_test::Test::Protocol);
let context = AppContext { service };
Ok(AppContextPtr::new(context))
}).response(value, error)
}
import TesseractTransportsClient
import CApp
let rustApp = try! TResult<AppContextPtr>.wrap { value, error in
app_init(alerts.toCore(), IPCTransportIOS().toCore(), value, error)
}.get()
The rest of Tesseract APIs stay exacly the same everywhere. Please, consider to go through the docs in our Tesseract shared Core repo.
- Create a new iOS application or open your existing project.
- Add Action Extension target to the project.
- Configure Action Extension target: Wallet Docs
Copy Xcode build script from Examples/Rust/xcode_build_step.sh
into your project (in this guide we assume that it is copied to the sources root folder).
- Add
Run Script
phase to your Wallet and Extension targets - Move it before
Build Sources
phase - Change script to
exec bash ${SRCROOT}/xcode_build_step.sh CWallet wallet
. WhereCWallet
is a name for the exported Swift module andwallet
is a name of the rust library target in theCargo.toml
.
- Add Package Dependency to the project:
https://github.com/tessetact-one/Tesseract.swift
. - Add
TesseractTransportsService
library dependency for Extension target.
cargo new wallet --lib
- Add the dependencies:
[dependencies]
tesseract-swift = { version = "0.5", features = ["service"] }
tesseract-one = { version = "0.5", features = ["service"] }
tesseract-protocol-test = { version = "0.5", features = ["service"] }
[build-dependencies]
cbindgen = "0.26"
- specify the type of library
[lib]
crate-type = ["staticlib"]
- create
build.rs
file for C headers generation
extern crate cbindgen;
use std::env;
use std::path::Path;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let profile = env::var("PROFILE").unwrap();
let name = env::var("CARGO_PKG_NAME").unwrap();
let header_path = Path::new(&crate_dir)
.join("target")
.join(&profile)
.join("include")
.join(format!("{}.h", name));
cbindgen::generate(&crate_dir)
.expect("Unable to generate bindings")
.write_to_file(&header_path);
}
- Create
cbindgen.toml
file with this contents
include_version = true
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
tab_width = 2
language = "C"
documentation_style = "doxy"
pragma_once = true
cpp_compat = true
after_includes = "@import CTesseractShared;"
[enum]
prefix_with_name = true
[parse]
parse_deps = true
include = ["tesseract-swift", "tesseract-swift-utils", "tesseract-swift-transport"]
[export]
exclude = [
"CFutureBool", "SyncPtr_Void", "ServiceBoundTransport", "ServiceTransport",
"ServiceTransportProcessor", "Void", "CError", "CString", "CStringRef",
"CAnyDropPtr"
]
Now you can export C functions, initialize Tesseract and wait accept request.
Create Extension initialization function in Rust. Initialize Tesseract in it
use tesseract_one::service::Tesseract;
use tesseract_swift::error::TesseractSwiftError;
use tesseract_swift::service::transport::ServiceTransport;
use tesseract_swift::utils::{error::CError, ptr::SyncPtr, Void};
use std::mem::ManuallyDrop;
use std::sync::Arc;
// Your Extension application context. Put all needed data here.
// Rust only structure
struct ExtensionContext {
_tesseract: Tesseract
}
// Type-erased ExtensionContext pointer for Swift.
#[repr(C)]
pub struct ExtensionContextPtr(SyncPtr<Void>);
// Helper methods for pointer
impl ExtensionContextPtr {
fn new(ctx: ExtensionContext) -> Self {
Self(SyncPtr::new(ctx).as_void())
}
unsafe fn unowned(&self) -> &ExtensionContext {
self.0.as_typed_ref().unwrap()
}
unsafe fn owned(&mut self) -> ExtensionContext {
self.0.take_typed()
}
}
// Wallet extension init method
#[no_mangle]
pub unsafe extern "C" fn wallet_extension_init(
signature: CStringRef, ui: UI, transport: ServiceTransport,
value: &mut ManuallyDrop<ExtensionContextPtr>, error: &mut ManuallyDrop<CError>
) -> bool {
TesseractSwiftError::context(|| {
let service = TestService::new(ui, signature.try_as_ref()?.into());
let tesseract = Tesseract::new().transport(transport).service(service);
let context = ExtensionContext {
_tesseract: tesseract,
};
Ok(ExtensionContextPtr::new(context))
}).response(value, error)
}
import TesseractTransportsService
import CWallet
let transport = IPCTransportIOS(self).toCore()
let signature = "test"
let rustApp = try! TResult<ExtensionContextPtr>.wrap { value, error in
wallet_extension_init(signature,
NativeUI(delegate: self).toCore(),
transport, value, error)
}.get()
The rest of Tesseract APIs stay exacly the same everywhere. Please, consider to go through the docs in our Tesseract shared Core repo.