Files
vnidrop/apple
cdricms 4448822bfa refactor(l10n): default strings to all targets
Most strings were imported with a platform-specific `targets` (usually
apple-only) just because that's where they happen to be used today. Drop the
restriction so they default to all targets and are available to KMP too; only
the four literal `%@…` format-composition keys stay apple-only.

Also fix the placeholder parser to tolerate C length modifiers (`%lld`), and
give progress_sending_to_count a proper int arg so it emits `%1$d` on both
platforms instead of a literal `%lld`.
2026-07-20 10:24:54 +02:00
..

VniDrop — native Apple app (iOS / iPadOS / macOS)

A native SwiftUI app for Apple platforms, sharing the existing Rust transfer core (crates/vnidrop) through UniFFI-generated Swift bindings. The Rust crate is not modified; the Kotlin/Compose app layer is ported to Swift and mirrors the Compose UI screen-for-screen. Android and desktop JVM continue to use shared/ + Compose.

Layout

apple/
  scripts/build-core.sh     # builds the Rust core + generates Swift bindings + xcframework
  VnidropCore/              # local SwiftPM package: xcframework + generated Vnidrop.swift
  VniDrop/                  # SwiftUI app sources
    App/                    # entry point, object graph, root view, environment
    Core/                   # repository, models, preferences, notifications, progress
    Features/Send|Receive|Approvals|Settings/
    UI/Theme|Components|Navigation|Feedback|Shell/
    Platform/               # pickers, QR, NFC, share/export, per-OS file services
    Resources/              # Localizable.xcstrings, Info.plist, entitlements, assets
  Tests/                    # XCTest (ported progress-derivation assertions)
  Package.swift             # builds VniDrop/ as a library for CLI build/test
  project.yml               # XcodeGen spec for the iOS/macOS app target

Build & run

Prerequisites: Xcode, Rust with the Apple targets (aarch64-apple-ios, aarch64-apple-ios-sim, x86_64-apple-ios, aarch64-apple-darwin), and xcodegen (brew install xcodegen).

# 1. Build the Rust core and generate the Swift bindings + xcframework.
apple/scripts/build-core.sh debug        # or: release (see note below)

# 2. Generate the Xcode project.
cd apple && xcodegen generate

# 3. Open and run, or build from the CLI:
open VniDrop.xcodeproj
#   macOS:
xcodebuild -project VniDrop.xcodeproj -scheme VniDrop -destination 'platform=macOS' build
#   iOS simulator:
xcodebuild -project VniDrop.xcodeproj -scheme VniDrop \
  -destination 'platform=iOS Simulator,name=iPhone 15' build

Command-line typecheck & tests

Package.swift builds the same sources as a library (minus the @main entry), so the shared logic can be checked and unit-tested without Xcode:

cd apple
swift build                       # macOS
swift test                        # runs Tests/ (ported progress-derivation assertions)
# iOS typecheck:
swift build --triple arm64-apple-ios16.0-simulator --sdk "$(xcrun --sdk iphonesimulator --show-sdk-path)"

Generated / ignored artifacts

build-core.sh produces build outputs that are gitignored (see apple/.gitignore): VnidropCore/vnidrop.xcframework/, VnidropCore/Sources/VnidropCore/Vnidrop.swift, and .build-core/. A clean checkout must run build-core.sh before generating or opening the Xcode project. VniDrop.xcodeproj itself is generated by XcodeGen from project.yml and does not need to be committed.

Build profile note

The default is debug. The workspace [profile.release] uses thin LTO, which the current macOS toolchain miscompiles into corrupt host proc-macro dylibs ("mis-aligned LINKEDIT string pool"). build-core.sh sets CARGO_PROFILE_DEV_STRIP=none (matching the existing Gobley Xcode run-script) so debug builds succeed. For a release core, disable LTO for proc-macros/build scripts (e.g. add a [profile.release.build-override] lto = false locally) — the Rust crate itself is never changed.

System frameworks

The Rust core (iroh network stack) links SystemConfiguration, Security, and libresolv. These are declared in both Package.swift (for CLI build/test) and project.yml (for the app target).

Parity & scope

Screens mirror the Compose UI in shared/. Two deliberate simplifications:

  • Empty-state Lottie animations are rendered as SF Symbols (no lottie-ios dependency); swap in lottie-ios if exact-parity animation is required.
  • The full diagnostics/telemetry stack (diagnostics/*) is stubbed behind BugReportService / DiagnosticsBuildConfig and lands in a later phase; the UI hides the diagnostics toggle when not compiled in.