1
0
Fork 0
mirror of https://gitlab.com/futo-org/fcast.git synced 2025-08-24 00:02:50 +00:00

Sender SDK

This commit is contained in:
Marcus Hanestad 2025-08-21 14:49:52 +00:00
parent fdbefc63e0
commit afc46f3022
147 changed files with 17638 additions and 114 deletions

View file

@ -0,0 +1,14 @@
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.5.40", features = [ "derive" ] }
xshell = "0.2.7"
serde = { version = "1.0.219", features = [ "derive" ] }
serde_json = "1.0.140"
anyhow = "1.0.98"
camino = { version = "1.1.10", features = [ "serde1" ] }
# uniffi_bindgen = "0.29.4"
uniffi_bindgen = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "c66ce860d2832c42b4b24052bbb0608c419f5503" }

View file

@ -0,0 +1,121 @@
use anyhow::Result;
use camino::{Utf8Path, Utf8PathBuf};
use clap::{Args, Subcommand};
use uniffi_bindgen::{
bindings::KotlinBindingGenerator, library_mode::generate_bindings, EmptyCrateConfigSupplier,
};
use xshell::cmd;
use crate::{sh, workspace};
#[derive(Subcommand)]
pub enum KotlinCommand {
BuildAndroidLibrary {
#[clap(long)]
release: bool,
#[clap(long)]
src_dir: Utf8PathBuf,
},
}
#[derive(Args)]
pub struct KotlinArgs {
#[clap(subcommand)]
pub cmd: KotlinCommand,
}
fn build_for_android_target(
target: &str,
profile: &str,
dest_dir: &str,
package_name: &str,
) -> Result<Utf8PathBuf> {
let sh = sh();
let _p = sh.push_dir(workspace::root_path()?);
cmd!(
sh,
"cargo ndk --target {target} -o {dest_dir} build --profile {profile} -p {package_name} --no-default-features --features _android_defaults"
)
.run()?;
let profile_dir_name = if profile == "dev" { "debug" } else { profile };
let package_camel = package_name.replace('-', "_");
let lib_name = format!("lib{package_camel}.so");
Ok(workspace::target_path()?
.join(target)
.join(profile_dir_name)
.join(lib_name))
}
fn generate_uniffi_bindings(library_path: &Utf8Path, ffi_generated_dir: &Utf8Path) -> Result<()> {
let config_path = workspace::root_path()?.join("sdk/sender/fcast-sender-sdk/uniffi.toml");
generate_bindings(
library_path,
None,
&KotlinBindingGenerator,
&EmptyCrateConfigSupplier,
Some(&config_path),
ffi_generated_dir,
false,
)?;
Ok(())
}
fn build_android_library(release: bool, src_dir: Utf8PathBuf) -> Result<()> {
let package_name = "fcast-sender-sdk";
let jni_libs_dir = src_dir.join("jniLibs");
let sh = sh();
let _p = sh.push_dir(workspace::root_path()?);
sh.create_dir(&jni_libs_dir)?;
let jni_libs_dir_str = jni_libs_dir.as_str();
let kotlin_generated_dir = src_dir.join("kotlin");
sh.create_dir(&kotlin_generated_dir)?;
let profile = if release { "release" } else { "dev" };
build_for_android_target(
"x86_64-linux-android",
profile,
jni_libs_dir_str,
package_name,
)?;
build_for_android_target(
"i686-linux-android",
profile,
jni_libs_dir_str,
package_name,
)?;
build_for_android_target(
"armv7-linux-androideabi",
profile,
jni_libs_dir_str,
package_name,
)?;
let uniffi_lib_path = build_for_android_target(
"aarch64-linux-android",
profile,
jni_libs_dir_str,
package_name,
)?;
generate_uniffi_bindings(&uniffi_lib_path, &kotlin_generated_dir)?;
Ok(())
}
impl KotlinArgs {
pub fn run(self) -> Result<()> {
let sh = sh();
let _p = sh.push_dir(workspace::root_path()?);
match self.cmd {
KotlinCommand::BuildAndroidLibrary { release, src_dir } => {
build_android_library(release, src_dir)
}
}
}
}

View file

@ -0,0 +1,15 @@
use std::rc::Rc;
use xshell::Shell;
pub mod kotlin;
pub mod swift;
pub mod workspace;
thread_local! {
static SH: Rc<Shell> = Rc::new(Shell::new().unwrap())
}
pub fn sh() -> Rc<Shell> {
SH.with(|sh| sh.clone())
}

View file

@ -0,0 +1,41 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use xshell::cmd;
use xtask::{
kotlin,
swift::{self, SwiftArgs, SwiftCommand},
};
#[derive(Subcommand)]
enum Command {
Kotlin(kotlin::KotlinArgs),
Swift(swift::SwiftArgs),
GenerateIos,
Hack,
}
#[derive(Parser)]
struct Xtask {
#[clap(subcommand)]
cmd: Command,
}
fn main() -> Result<()> {
match Xtask::parse().cmd {
Command::Kotlin(cmd) => cmd.run(),
Command::Hack => {
let sh = xtask::sh();
cmd!(sh, "cargo hack check --each-feature").run()?;
Ok(())
}
Command::Swift(cmd) => cmd.run(),
Command::GenerateIos => {
SwiftArgs {
cmd: SwiftCommand::BuildIosLibrary { release: true },
}
.run()?;
Ok(())
}
}
}

View file

@ -0,0 +1,89 @@
use std::fs::rename;
use anyhow::Result;
use camino::Utf8Path;
use clap::{Args, Subcommand};
use uniffi_bindgen::{
bindings::SwiftBindingGenerator, library_mode::generate_bindings, EmptyCrateConfigSupplier,
};
use xshell::cmd;
use crate::{sh, workspace};
#[derive(Subcommand)]
pub enum SwiftCommand {
BuildIosLibrary {
#[clap(long)]
release: bool,
},
}
#[derive(Args)]
pub struct SwiftArgs {
#[clap(subcommand)]
pub cmd: SwiftCommand,
}
fn generate_uniffi_bindings(library_path: &Utf8Path, ffi_generated_dir: &Utf8Path) -> Result<()> {
generate_bindings(
library_path,
None,
&SwiftBindingGenerator,
&EmptyCrateConfigSupplier,
None,
ffi_generated_dir,
false,
)?;
Ok(())
}
fn build_ios_library(release: bool) -> Result<()> {
let package_name = "fcast-sender-sdk";
let sh = sh();
let _p = sh.push_dir(workspace::root_path()?);
let profile = if release { "release" } else { "dev" };
for target in ["aarch64-apple-ios-sim", "aarch64-apple-ios"] {
cmd!(
sh,
"cargo build -p {package_name} --profile={profile} --target={target} --no-default-features --features _ios_defaults"
)
.run()?;
}
let package_camel = package_name.replace('-', "_");
generate_uniffi_bindings(
Utf8Path::new(&format!(
"target/aarch64-apple-ios-sim/{}/lib{package_camel}.dylib",
if release { "release" } else { "debug" }
)),
"ios-bindings/uniffi/".into(),
)?;
rename(
format!("ios-bindings/uniffi/{package_camel}FFI.modulemap"),
format!("ios-bindings/uniffi/{package_camel}.modulemap"),
)?;
sh.remove_path(format!("ios-bindings/{package_camel}.xcframework"))?;
let profile = if release { "release" } else { "debug" };
cmd!(
sh,
"xcodebuild -create-xcframework -library target/aarch64-apple-ios-sim/{profile}/lib{package_camel}.a -library target/aarch64-apple-ios/{profile}/lib{package_camel}.a -headers ios-bindings/uniffi -output ios-bindings/{package_camel}.xcframework"
).run()?;
Ok(())
}
impl SwiftArgs {
pub fn run(self) -> Result<()> {
let sh = sh();
let _p = sh.push_dir(workspace::root_path()?);
match self.cmd {
SwiftCommand::BuildIosLibrary { release } => build_ios_library(release),
}
}
}

View file

@ -0,0 +1,30 @@
use std::env;
use crate::sh;
use anyhow::Result;
use camino::Utf8PathBuf;
use xshell::cmd;
pub fn root_path() -> Result<Utf8PathBuf> {
#[derive(serde::Deserialize)]
struct Metadata {
workspace_root: Utf8PathBuf,
}
let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_owned());
let sh = sh();
let metadata_json = cmd!(sh, "{cargo} metadata --no-deps --format-version 1").read()?;
Ok(serde_json::from_str::<Metadata>(&metadata_json)?.workspace_root)
}
pub fn target_path() -> Result<Utf8PathBuf> {
#[derive(serde::Deserialize)]
struct Metadata {
target_directory: Utf8PathBuf,
}
let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_owned());
let sh = sh();
let metadata_json = cmd!(sh, "{cargo} metadata --no-deps --format-version 1").read()?;
Ok(serde_json::from_str::<Metadata>(&metadata_json)?.target_directory)
}