Skip to main content

Prerequisites

Before building Ora Browser, ensure you have the following installed:
  • macOS 14.0 or later
  • Xcode 15 or later (Swift 5.9)
  • Homebrew (for developer tooling)
The current minimum deployment target is macOS 15.0. The project uses Swift 5.9 and requires Xcode 15 or later.

Initial Setup

1

Clone the repository

Clone the Ora Browser repository to your local machine:
git clone https://github.com/the-ora/browser.git
cd browser
2

Run the setup script

The setup script will install all required tools and configure your development environment:
./scripts/setup.sh
This script automatically:
  • Installs required Homebrew packages (xcodegen, swiftlint, swiftformat, xcbeautify, lefthook)
  • Installs git hooks for code formatting and linting
  • Generates the Xcode project from project.yml
3

Open in Xcode

Open the generated Xcode project:
open Ora.xcodeproj

Development Builds

Building in Xcode

To build and run Ora Browser for development:
  1. Select the ora scheme in Xcode
  2. Choose your target device (Mac)
  3. Press ⌘R to build and run
The Debug configuration includes:
  • Developer icon variant (OraIconDev)
  • Hot reloading support via InjectionIII
  • Interposable linking for runtime code replacement
  • No code signing requirements

Building from Command Line

For a quick debug build without Xcode:
./scripts/xcbuild-debug.sh
This script builds the Debug configuration with:
  • No code signing (CODE_SIGN_IDENTITY="")
  • Pretty-printed output via xcbeautify
  • Faster iteration for testing
#!/bin/bash
set -o pipefail && xcodebuild build \
  -scheme ora \
  -destination "platform=macOS" \
  -configuration Debug \
  CODE_SIGN_IDENTITY="" \
  CODE_SIGNING_REQUIRED=NO | xcbeautify

Hot Reloading

Ora supports live UI updates during development using InjectionIII.
1

Install InjectionIII

Download InjectionIII from the Mac App Store
2

Connect to your project

  1. Launch InjectionIII
  2. Click the menu bar icon
  3. Select Open Project
  4. Navigate to your browser folder
3

Build and run

Build and run from Xcode in Debug mode. You should see a green status indicator in the InjectionIII menu bar icon.

Using Hot Reload

Once connected, edit any Swift file and save—changes will appear instantly without rebuilding. To add hot reload support to a new view:
import Inject

struct MyView: View {
    @ObserveInjection var inject

    var body: some View {
        Text("Hello, Ora!")
            .enableInjection()
    }
}
Hot reloading has limitations:
  • Cannot add, remove, or reorder stored properties
  • private members in extensions may not inject correctly
  • Debug-only feature with zero impact on Release builds

How It Works

The Debug build configuration enables hot reloading through:
project.yml
configs:
  Debug:
    EMIT_FRONTEND_COMMAND_LINES: YES
    OTHER_LDFLAGS: "-Xlinker -interposable"
  • EMIT_FRONTEND_COMMAND_LINES exposes compiler flags for InjectionIII
  • -Xlinker -interposable makes functions replaceable at runtime
  • Root views use @ObserveInjection to re-evaluate after injection

Project Configuration

Ora uses XcodeGen to generate the Xcode project from a YAML specification.

Regenerating the Project

After modifying project.yml, regenerate the Xcode project:
xcodegen
Always edit project.yml instead of Xcode project settings. The .xcodeproj is regenerated and should not be manually modified.

Project Structure

The project.yml defines:
packages:
  Sparkle:
    url: https://github.com/sparkle-project/Sparkle
    from: 2.6.0
  Inject:
    url: https://github.com/krzysztofzablocki/Inject
    from: 1.5.2
  FaviconFinder:
    url: https://github.com/will-lumley/FavIconFinder
    exactVersion: 5.1.5

Build Scripts

The project includes automated build scripts in the scripts/ directory:

setup.sh

Installs dependencies, configures git hooks, and generates the Xcode project

xcbuild-debug.sh

Quick debug build from command line without code signing

build-release.sh

Full release build with signing, notarization, and DMG creation

create-release.sh

End-to-end release process with versioning and deployment

Code Quality

Automatic Formatting

Code formatting and linting are enforced via git hooks:
lefthook.yml
pre-commit:
  parallel: true
  commands:
    swiftformat:
      glob: "**/*.swift"
      run: swiftformat {staged_files} --quiet
      stage_fixed: true
    swiftlint:
      glob: "**/*.swift"
      run: swiftlint lint --fix --use-alternative-excluding {staged_files}
      stage_fixed: true

pre-push:
  commands:
    build:
      run: ./scripts/xcbuild-debug.sh

Manual Formatting

Run formatting tools manually:
# Format all Swift files
swiftformat . --quiet

# Lint and auto-fix issues
swiftlint --quiet
Git hooks are installed automatically by ./scripts/setup.sh using lefthook. They run before every commit and push.

Troubleshooting

Xcode Build Errors

If you encounter build errors:
  1. Clean the build folder: Product → Clean Build Folder (⇧⌘K)
  2. Regenerate the project: Run xcodegen in the project root
  3. Reset Package Cache: File → Packages → Reset Package Caches

Missing Dependencies

If Homebrew packages are missing, run:
./scripts/setup.sh

Hot Reload Not Working

  1. Verify InjectionIII shows green status
  2. Ensure Debug configuration is selected
  3. Check that the project path is correct in InjectionIII
  4. Rebuild the project (⌘B)

Next Steps

Testing

Learn how to run tests and write new test cases

Releases

Understand the release process and distribution

Build docs developers (and LLMs) love