# WinterGram Build & Install Guide This guide covers how to build WinterGram from source, run it in the iOS Simulator, install it on a physical iPhone without a paid Apple Developer Program, and sideload the resulting IPA. ## Requirements - macOS with Xcode (the project is tested on Xcode 26.x) - Python 3 - ~60 GB of free disk space (Bazel cache + build artifacts) - A free Apple ID (for on-device installation) ## 1. Clone the repository ```sh git clone --recursive https://github.com/reekeer/WinterGram.git cd WinterGram ``` If you cloned without `--recursive`: ```sh git submodule update --init --recursive ``` ## 2. Configure build credentials WinterGram needs a development configuration with your own credentials. 1. Copy the example file: ```sh cp build-system/wintergram-development-configuration.example.json \ build-system/wintergram-development-configuration.json ``` 2. Edit `build-system/wintergram-development-configuration.json`: - `bundle_id` — a unique bundle identifier (e.g. `dev.you.wintergram`). - `api_id` / `api_hash` — obtain from . - `team_id` — your Apple Developer Team ID (a 10-character string). For a free Apple ID, create an Apple Development certificate in Xcode → Settings → Accounts, then find the Team ID in Keychain Access under the certificate's **Organizational Unit** field. - `app_specific_url_scheme` is `wnt` by default. > **Important:** `api_id` and `api_hash` are baked into the app at build time. You cannot change them after installation because your Telegram session is tied to the `api_id` used when logging in. The committed example uses public test values (`api_id: 2040`). Replace them with your own before installing on a personal device. ## 3. Build an unsigned IPA ### Convenience wrapper (recommended) `scripts/build-wintergram.sh` wraps the Bazel/Make.py invocations and emits WinterGram-named IPAs in `build/`: ```sh ./scripts/build-wintergram.sh sim # simulator -> build/WinterGram-Simulator.ipa ./scripts/build-wintergram.sh --install # build sim + install into the booted Simulator (sim only) ./scripts/build-wintergram.sh --install --run # also launch it ./scripts/build-wintergram.sh sideload # device IPA -> build/WinterGram.ipa ./scripts/build-wintergram.sh livecontainer # unsigned IPA -> build/WinterGram-LiveContainer.ipa ./scripts/build-wintergram.sh all # all of the above ``` `--clean` wipes `build/` first; `--open-build-dir` reveals the output in Finder; `--help` lists everything. The raw commands below are equivalent if you prefer to invoke Make.py directly. The fastest path to a device IPA is a terminal build: ```sh python3 build-system/Make/Make.py --overrideXcodeVersion \ --cacheDir ~/telegram-bazel-cache \ build \ --configurationPath build-system/wintergram-development-configuration.json \ --xcodeManagedCodesigning \ --buildNumber=1 \ --configuration=debug_arm64 ``` The finished `.ipa` is written to `bazel-bin/Telegram/`. For a simulator build, use `debug_sim_arm64` and fake codesigning files (the Simulator does not validate signatures, but Bazel still requires provisioning profiles): ```sh python3 build-system/Make/Make.py --overrideXcodeVersion \ --cacheDir ~/telegram-bazel-cache \ build \ --configurationPath build-system/wintergram-development-configuration.json \ --codesigningInformationPath build-system/fake-codesigning \ --buildNumber=1 \ --configuration=debug_sim_arm64 ``` Add `--continueOnError` after `build` to see every error in one pass. `--xcodeManagedCodesigning` is intended for `generateProject`; for terminal builds with extensions, use `--codesigningInformationPath build-system/fake-codesigning`. ## 4. Install on a physical iPhone (free Apple ID) ### With AltStore / SideStore 1. Build a device IPA (`debug_arm64` or `release_arm64`) with your Team ID in the config. 2. Install AltStore on your phone (via AltServer on your Mac). 3. In AltStore, tap **+**, select the built `.ipa`, and let AltStore re-sign and install it. 4. A free Apple ID must re-sign the app every 7 days. AltStore and SideStore can refresh this automatically in the background. ### With Xcode directly 1. Generate the Xcode project (see below). 2. Select the **Telegram** scheme and your connected iPhone as the destination. 3. In the target's **Signing & Capabilities**, choose your Personal Team. 4. Press ⌘R. The first time, trust the developer on the device in Settings → General → VPN & Device Management. Free provisioning profiles last 7 days and are limited to 3 apps per Apple ID. Push notifications via APNs, Siri, and iCloud are unavailable with a free account, so the dev config has `enable_siri` and `enable_icloud` disabled. ## 5. Generate an Xcode project ```sh python3 build-system/Make/Make.py --overrideXcodeVersion \ --cacheDir ~/telegram-bazel-cache \ generateProject \ --configurationPath build-system/wintergram-development-configuration.json \ --xcodeManagedCodesigning ``` To generate a simulator-only project without provisioning profiles, add `--disableProvisioningProfiles`. The command opens the generated `Telegram.xcodeproj` automatically. If it does not, the project is in the repository root. ## 6. Run in the Simulator 1. Open the generated `Telegram.xcodeproj`. 2. Select the **Telegram** scheme and any iPhone Simulator. 3. Press ⌘R. The first build is slow (40–90 minutes) because WebRTC and ffmpeg are compiled from source. Incremental builds are much faster. If Xcode hangs on "build-request.json not updated yet", cancel and run again; this is a known rules_xcodeproj quirk. ## App icons All WinterGram app-icon assets are generated from source PNGs in `branding/` by a single script: ```sh ./scripts/generate-app-icons.sh ``` Each source named `branding/wnt-app-icon-.png` (square, ≥1024×1024) becomes an alternate icon `WinterGram`. The two shipping icons are `wnt-app-icon-dark.png` (also the primary home-screen icon) and `wnt-app-icon-light.png`. The script regenerates the `.alticon` folders, the primary `WinterGramDarkIcon.appiconset`, and the in-app preview imagesets in one pass. A brand-new variant is generated but must still be registered manually — the script prints the three spots: `Telegram/BUILD` (`alternate_icon_folders`), `AppDelegate.getAvailableAlternateIcons()`, and the preview-imageset mapping in `applicationBindings`. ## Repository layout ``` WinterGram/ ├── Telegram/ ← App entry point and extensions │ ├── Telegram-iOS/ ← Info.plist, assets, xcconfig │ ├── Share / SiriIntents / NotificationService / ... │ └── WatchApp/ ← watchOS client snapshot ├── submodules/ ← Functionality split into Bazel modules │ ├── TelegramUIPreferences/Sources/WinterGramSettings.swift │ └── SettingsUI/Sources/WinterGramSettingsController.swift ├── branding/ ← Source art: app-icon PNGs (wnt-app-icon-*.png) + badge/snowflake shapes ├── scripts/ ← Build + tooling │ ├── build-wintergram.sh ← Convenience build wrapper (sim / sideload / livecontainer) │ └── generate-app-icons.sh ← App-icon generator (reads branding/wnt-app-icon-*.png) ├── docs/ ← Documentation ├── build-system/ ← Bazel wrapper and configs │ └── wintergram-development-configuration.json ← your dev config ├── third-party/ ← External dependencies └── Tests/ ← Bazel test app targets ``` ## Troubleshooting - **"No .mobileprovision targets for extensions"** when using `--xcodeManagedCodesigning` in a terminal build: use `--codesigningInformationPath build-system/fake-codesigning` instead, or use `generateProject` for Xcode-managed signing. - **Build fails on the first try:** ensure submodules are fully initialized and you have enough disk space. - **App crashes on launch after re-signing:** make sure the `bundle_id` in your config is unique and the `team_id` matches the certificate used to sign.