BUILDING.md
Rama main · réplica de lectura del repositorio original.
# Building Hollow
Hollow is a Flutter app (Dart, `lib/`) on top of a Rust core (`rust/hollow_core/`), joined by flutter_rust_bridge. You don't build the Rust core separately. Cargokit compiles it inside every `flutter run` and `flutter build`, and it installs the Rust targets it needs through rustup on the first build.
Run every command below from the repository root.
## Every platform
- Flutter SDK, stable channel. We build with 3.47.0.
- Rust toolchain, stable, through [rustup](https://rustup.rs).
- flutter_rust_bridge_codegen 2.11.1, only if you change the Rust API.
The generated bindings in `lib/src/rust/` are committed, so a fresh clone builds without codegen. After changing anything in `rust/hollow_core/src/api/`, regenerate them:
```bash
flutter_rust_bridge_codegen generate --rust-input "crate::api" --rust-root "rust/hollow_core" --dart-output "lib/src/rust"
```
The app doesn't need git submodules. Only the relay does (`relay-uws/`).
### The patched WebRTC
Desktop builds ship a patched libwebrtc that encodes screen shares as screen content instead of webcam video, which is why text stays sharp. The patched binaries and headers are vendored at `packages/flutter_webrtc/third_party/libwebrtc/`, so a normal clone builds with no extra downloads. Only maintainers bumping the upstream milestone need to rebuild it, and [BUILDING.md](packages/flutter_webrtc/third_party/libwebrtc/BUILDING.md) in that folder has the reproducible recipe.
## Windows
You need:
- Visual Studio 2022 with the "Desktop development with C++" workload.
- OpenSSL 3, 64-bit, installed at `C:\Program Files\OpenSSL-Win64` (the Win64 OpenSSL installer from slproweb.com puts it there). SQLCipher links against it, and the build copies `libcrypto-3-x64.dll` and `libssl-3-x64.dll` from that exact path next to `hollow.exe`. Point the Rust build at it with three system variables:
```powershell
# In an elevated PowerShell, then open a new terminal
setx /M OPENSSL_DIR "C:\Program Files\OpenSSL-Win64"
setx /M OPENSSL_LIB_DIR "C:\Program Files\OpenSSL-Win64\lib\VC\x64\MD"
setx /M OPENSSL_INCLUDE_DIR "C:\Program Files\OpenSSL-Win64\include"
```
- NASM. The `webcrypto` package builds BoringSSL with CMake before any Hollow code compiles, and BoringSSL's assembly needs it.
If Strawberry Perl is installed, its `cmake` and `ninja` sit ahead of Visual Studio's on `PATH` and that BoringSSL step fails with `CMAKE_C_COMPILER not set`. Run Flutter through `scripts\flutter_win.ps1` instead. It fixes `PATH` for that one process and borrows Strawberry's `nasm.exe`. It expects Visual Studio 2022 Community in its default location.
```powershell
powershell -File scripts\flutter_win.ps1 run -d windows
```
Two native helpers ship next to the app. Without them the build still succeeds, but video thumbnails and screen-share audio are off. Fetch and build them once:
```powershell
pwsh scripts\fetch_ffmpeg.ps1 # ffmpeg, for video thumbnails
pwsh scripts\build_screen_audio.ps1 # screen-share system audio
```
Then:
```bash
flutter run -d windows # debug
flutter build windows # release
```
## macOS
Install Xcode from the App Store, the command line tools and CocoaPods:
```bash
xcode-select --install
sudo gem install cocoapods # or: brew install cocoapods
```
Build the screen audio capturer first. The Xcode build only copies it into the app, and without it screen-share audio is off:
```bash
bash scripts/build_screen_audio.sh
```
Then:
```bash
flutter pub get
flutter build macos --release
```
The app lands in `build/macos/Build/Products/Release/Hollow.app`, a universal x86_64 and arm64 bundle. It runs on macOS 12 and later. Screen-share audio and call recording need macOS 13, because Apple has no system-audio API below it.
For a signed build, copy `macos/Flutter/LocalSigning.xcconfig.example` to `LocalSigning.xcconfig` and put your Team ID in it. That file is gitignored. Without it the project still builds for local use, with no team.
## Linux
On Ubuntu or Debian:
```bash
sudo apt install -y clang cmake ninja-build pkg-config libgtk-3-dev libsecret-1-dev libssl-dev libnotify-dev libayatana-appindicator3-dev libpulse-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly lld curl build-essential
flutter pub get
flutter build linux
```
The binary lands in `build/linux/x64/release/bundle/hollow`. For screen-share audio, run `bash scripts/build_screen_audio.sh` before `flutter build linux`.
## Android
You need the Android SDK with NDK 28.2.13676358, the version Flutter 3.47 asks for. Install it from Android Studio's SDK Manager under SDK Tools, with "Show Package Details" ticked.
### OpenSSL for SQLCipher
The NDK has no OpenSSL, and SQLCipher needs it. Static OpenSSL 3.5.8 libraries for every ABI are committed in `rust/hollow_core/.cargo/android-openssl-headers/`, and the README there explains how they were built. The build finds them through system environment variables, because cargokit never reads `rust/hollow_core/.cargo/config.toml`.
On Windows, from the repository root in an elevated PowerShell:
```powershell
$ssl = "$PWD\rust\hollow_core\.cargo\android-openssl-headers"
setx /M HOLLOW_ANDROID_OPENSSL_INCLUDE "$ssl\include"
setx /M HOLLOW_ANDROID_OPENSSL_LIB "$ssl\lib"
$abis = @{ AARCH64_LINUX_ANDROID = 'aarch64'; ARMV7_LINUX_ANDROIDEABI = 'armv7';
X86_64_LINUX_ANDROID = 'x86_64'; I686_LINUX_ANDROID = 'i686' }
foreach ($t in $abis.Keys) {
setx /M "${t}_OPENSSL_INCLUDE_DIR" "$ssl\include"
setx /M "${t}_OPENSSL_LIB_DIR" "$ssl\lib\$($abis[$t])"
setx /M "${t}_OPENSSL_STATIC" 1
}
```
Open a new terminal afterwards. On Linux or macOS, export the same variables from your shell profile.
### Firebase
The Android build applies the Google Services plugin, so it fails until `android/app/google-services.json` exists. That file is gitignored. Create a Firebase project, add an Android app with the package name `com.anonlisten.hollow`, and save its `google-services.json` there. With your own project the app builds and runs. Only push notifications from the official relay won't reach it, since they go through Hollow's Firebase project.
### Build
```bash
flutter devices # list emulators and phones
flutter run -d <device-id> # debug
flutter build apk --release # one APK for every ABI, as releases ship
```
If the Rust build fails, `flutter build apk` can still report success and package the `libhollow_core.so` left over from the previous build. Check the output for `error occurred in cc-rs` or `warning: build failed` before trusting an APK.
## iOS
iOS builds need a Mac with Xcode and CocoaPods. No OpenSSL is involved, because on Apple platforms SQLCipher uses CommonCrypto.
- The Xcode project expects `ios/Runner/GoogleService-Info.plist`, which is gitignored. Add one from your Firebase project (an iOS app with the bundle ID `com.anonlisten.hollow`), or the build stops on the missing file.
- Copy `ios/Flutter/LocalSigning.xcconfig.example` to `LocalSigning.xcconfig`. Fill in your Team ID only for a real device or TestFlight. The Simulator needs none.
- On an Apple Silicon Mac, add these two lines to that same `LocalSigning.xcconfig`. Otherwise BoringSSL fails to link the x86_64 Simulator slice, which nothing on that Mac would run anyway:
```
EXCLUDED_ARCHS[sdk=iphonesimulator*] = x86_64
ONLY_ACTIVE_ARCH = YES
```
Then build for the Simulator:
```bash
flutter build ios --simulator --debug
```
Device and TestFlight builds go through Xcode. Open `ios/Runner.xcworkspace` and use Product > Archive. The notification service extension links the Rust core through CocoaPods, so there's nothing to wire up by hand. The project targets iOS 15.0, while TestFlight builds need iOS 16.
### iOS dev variant
"Hollow Dev" is a debug build that installs next to the TestFlight app on the same iPhone and shares nothing with it. Use it for any test on a phone that also carries a real Hollow install:
```bash
flutter run --flavor dev -d <device-udid>
```
- The `dev` scheme builds the `Debug-dev`, `Release-dev` and `Profile-dev` configurations. Only `Debug-dev` is meant to be used.
- Every id comes from `ios/Flutter/Variant-dev.xcconfig`: bundle `com.anonlisten.hollow.dev` (extensions `.NotificationService` and `.BroadcastExtension` under it), App Group `group.com.anonlisten.hollow.dev`, keychain group `$(AppIdentifierPrefix)com.anonlisten.hollow.dev`, URL scheme `hollow-dev`, APNs `development`. Production takes the same settings from `Variant-prod.xcconfig`, and builds without `--flavor` stay production.
- It signs with its own team (`HOLLOW_DEV_TEAM` in `Variant-dev.xcconfig`, overridable in `LocalSigning.xcconfig`), so Xcode registers the dev ids the first time it builds for a connected device. On a free Personal Team, also set `HOLLOW_DEV_CAPABILITIES = personal`: such a team grants no App Groups and no push, so the build drops those entitlements and runs without rich banners, push or screen share.
- Push needs a Firebase iOS app for `com.anonlisten.hollow.dev`. Put its config at `ios/GoogleService-Info-dev.plist` (gitignored). Without it the dev build ships no Firebase config at all, so it can never register under the production app.