#!/usr/bin/env bash set -euo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" package_dir="${repo_root}/apps/ios/TeleTuiIOS" out_dir="${1:-${repo_root}/build/ios-real-ffi-xcframework}" artifacts_dir="${package_dir}/BinaryArtifacts" swift_sources_dir="${package_dir}/Generated/tele_ios_ffi/Sources/tele_ios_ffi" framework_name="${IOS_FFI_FRAMEWORK_NAME:-tele_ios_ffi}" tdjson_framework_name="${IOS_TDJSON_FRAMEWORK_NAME:-tdjson}" targets="${IOS_RUST_TARGETS:-}" if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]]; then export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer fi if [[ -z "${targets}" ]]; then targets="x86_64-apple-ios aarch64-apple-ios-sim" fi cd "${repo_root}" case "${out_dir}" in "" | "/" | "/tmp" | "/private" | "/private/tmp") printf 'Refusing unsafe output directory: %s\n' "${out_dir}" >&2 exit 2 ;; esac rm -rf "${out_dir}" mkdir -p "${out_dir}/Swift" "${out_dir}/Headers" "${out_dir}/TdjsonHeaders" tdjson_args=() first_lib_path="" simulator_libs=() device_lib="" seen_simulator=0 seen_device=0 for target in ${targets}; do IOS_RUST_TARGET="${target}" "${repo_root}/scripts/build-ios-ffi-with-local-tdlib.sh" lib_path="${repo_root}/target/${target}/release/libtele_ios_ffi.a" if [[ -z "${first_lib_path}" ]]; then first_lib_path="${lib_path}" fi case "${target}" in aarch64-apple-ios) seen_device=1 device_lib="${lib_path}" ;; aarch64-apple-ios-sim | x86_64-apple-ios) seen_simulator=1 simulator_libs+=("${lib_path}") ;; *) printf 'Unsupported iOS Rust target for XCFramework packaging: %s\n' "${target}" >&2 exit 1 ;; esac done if [[ -z "${first_lib_path}" ]]; then printf 'No Rust targets selected for iOS FFI packaging\n' >&2 exit 1 fi cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Swift" --swift-sources cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Headers" --headers cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Headers" \ --modulemap \ --module-name tele_ios_ffiFFI \ --modulemap-filename module.modulemap cat > "${out_dir}/TdjsonHeaders/tdjson.h" <<'HEADER' void td_json_client_send(void *client, const char *request); const char *td_json_client_receive(void *client, double timeout); const char *td_json_client_execute(void *client, const char *request); void *td_json_client_create(void); void td_json_client_destroy(void *client); HEADER if [[ "${seen_simulator}" == "1" ]]; then tdjson_args+=( "-library" "${repo_root}/.build/tdlib-ios/iphonesimulator/lib/libtdjson.1.8.29.dylib" "-headers" "${out_dir}/TdjsonHeaders" ) fi if [[ "${seen_device}" == "1" ]]; then tdjson_args+=( "-library" "${repo_root}/.build/tdlib-ios/iphoneos/lib/libtdjson.1.8.29.dylib" "-headers" "${out_dir}/TdjsonHeaders" ) fi rm -rf "${artifacts_dir}/${framework_name}.xcframework" \ "${artifacts_dir}/${tdjson_framework_name}.xcframework" \ "${swift_sources_dir}" mkdir -p "${artifacts_dir}" "${swift_sources_dir}" ffi_args=() if [[ "${#simulator_libs[@]}" -gt 0 ]]; then simulator_lib="${out_dir}/libtele_ios_ffi-iphonesimulator.a" if [[ "${#simulator_libs[@]}" -eq 1 ]]; then cp "${simulator_libs[0]}" "${simulator_lib}" else xcrun lipo -create "${simulator_libs[@]}" -output "${simulator_lib}" fi ffi_args+=("-library" "${simulator_lib}" "-headers" "${out_dir}/Headers") fi if [[ -n "${device_lib}" ]]; then ffi_args+=("-library" "${device_lib}" "-headers" "${out_dir}/Headers") fi xcodebuild -create-xcframework \ "${ffi_args[@]}" \ -output "${artifacts_dir}/${framework_name}.xcframework" xcodebuild -create-xcframework \ "${tdjson_args[@]}" \ -output "${artifacts_dir}/${tdjson_framework_name}.xcframework" cp "${out_dir}/Swift/tele_ios_ffi.swift" "${swift_sources_dir}/tele_ios_ffi.swift" printf 'Generated real iOS FFI artifacts:\n' printf ' %s\n' "${artifacts_dir}/${framework_name}.xcframework" printf ' %s\n' "${artifacts_dir}/${tdjson_framework_name}.xcframework" printf ' %s\n' "${swift_sources_dir}/tele_ios_ffi.swift" printf 'Build Swift package with: TELE_IOS_USE_LOCAL_FFI=1 DEVELOPER_DIR=%s xcodebuild ...\n' "${DEVELOPER_DIR:-}"