Skip to content

Latest commit

 

History

History
272 lines (204 loc) · 10.1 KB

File metadata and controls

272 lines (204 loc) · 10.1 KB

Agent Notes

This file is the single source of project context for AI agents. See also docs/domain/ for product-specific behavior rules and common/docs/ for business logic (account types, subscriptions, feature access).

Project Overview

Blokada 6 is a cross-platform mobile ad blocker and privacy app with cloud-based blocking and WireGuard VPN integration. The codebase builds two distinct apps:

  • Blokada 6 – Full VPN and cloud-based blocking for individual users.
  • Blokada Family – Simplified family/parental protection.

Both share a Flutter module (common/) embedded into native Android (Kotlin) and iOS (Swift) shells. Platform channels are generated by Pigeon; state management uses MobX; payments use Adapty.

Project Structure

  • common/ – Shared Flutter module (UI + business logic)
    • lib/common.dart – Public package surface (entrypoints and shared types)
    • lib/src/core/ – Core utilities, dependency injection, persistence
    • lib/src/features/ – Feature-first modules (<feature>/{domain,ui}), including tiered features like plus
    • lib/src/app_variants/ – Variant-specific overrides (v6, family)
    • lib/src/shared/ – Shared UI, navigation, automation ids
    • lib/src/platform/ – Platform channel interfaces (generated by Pigeon)
    • lib/src/util/ – Shared utilities
  • android/ – Gradle project (flavors: family, six; build types: debug, release)
  • ios/ – Xcode project (schemes: FamilyProd, FamilyDev, Prod, Dev, Mocked)
  • scripts/ – Build and utility scripts
  • metadata/ – App store metadata for all platforms

Development Workflow

Iterative process:

  1. Make code changes
  2. Regenerate interfaces (if modified libgen/*.dart): make regen-ios (iOS only) or make regen (all platforms)
  3. Check linting: fvm flutter analyze – fix issues immediately
  4. Ensure tests pass: make test – iterate 1-4 until all tests pass
  5. Test on device: Manual verification on physical device

Prerequisites

git submodule update --init --recursive

In a fresh worktree, the command above re-fetches every submodule from origin (~20 s and ~340 MB for this repo, dominated by landing-github-pages). Faster alternative: copy the already-populated submodule directories from your main checkout. On APFS (macOS), cp -cR is near-instant and uses copy-on-write to avoid duplicating disk:

cp -cR /path/to/main-checkout/deps/* deps/

Use plain cp -R on non-APFS filesystems. Either path leaves the worktree buildable; pick whichever fits your workflow.

Build & Install Commands

Debug Builds

# Android
make build-android-family-debug
make build-android-six-debug
make build-android-family-debug-quick  # if common lib unchanged
make build-android-six-debug-quick

# iOS
make build-ios-six-debug

Release Builds

# Android
make build-android           # all
make build-android-family
make build-android-six

# iOS
make build-ios               # all
make build-ios-family
make build-ios-six

Installing on Device

make install-family          # release
make install-family-debug    # debug
make install-six             # release
make install-six-debug       # debug
make uninstall               # remove all

Device Testing

# iOS: build, install and run with console output (BLOCKING – run as background task)
make -C ios run-six [DEVICE_NAME="device name"] [CONFIG="Release|Debug"]
make -C ios run-family [DEVICE_NAME="device name"] [CONFIG="Release|Debug"]
# Default: CONFIG=Release (required for iOS 14+ to launch without Xcode/Flutter tooling)

# Android
make install-family-debug    # or make install-six-debug

Simulator Testing (iOS)

# iOS Mocked scheme on an auto-cloned per-worktree simulator (NetxServiceMock
# substitutes the real NetworkExtension — no DNS/VPN entitlement needed).
# Each worktree gets its own sim, so parallel checkouts don't contend.
make -C ios run-six-mocked          # or run-family-mocked
make -C ios appium-install-six-mocked  # install only, prints UDID for Appium

# Pre-warm onboarding/login state once, reuse across clones:
make -C ios run-six-mocked SIM_TEMPLATE="warm template"

# Status / cleanup
make -C ios sim-status sim-clean sim-gc

Use for UX/notifications/state work; use run-six/run-family on a real device when you need actual DNS/VPN behaviour. See ios/SIMULATOR.md for overrides, warm-template setup, and caveats.

Testing & Linting

make test           # safe default: refreshes pub, Pigeon Dart outputs via gen-android,
                    # and build_runner before running the Flutter test suite
make test-local     # fast local path: fvm flutter test --no-pub (assumes deps available)
fvm flutter analyze # linting

Code Generation

make regen          # generate all platform interfaces and mocks
make gen            # generate just platform interfaces
make regen-android  # clean and regenerate for Android
make regen-ios      # clean and regenerate for iOS

Version Management

Versions are YY.M.BUILD and are computed by CI, not chosen by hand. See docs/release-pipeline.md.

# CODE is the raw build number; VERSION_CODE_OFFSET (669000000) is added for you
make version NAME=26.7.1042 CODE=1042
# Or via env vars: BLOKADA_VERSION_NAME / BLOKADA_VERSION_CODE

Never pass a CODE far above the current build counter: store codes must increase monotonically, so an inflated value permanently strands every later release below it.

Platform Build Notes

If platform bindings changed and a build or install step starts failing, rerun the matching regeneration target before retrying:

  • make regen-ios for iOS build flows
  • make regen-android for Android build flows

This commonly fixes generated-signature mismatches after API changes.

Platform-Specific Notes

iOS

  • Fastlane for automation and deployment. Native dependencies use Swift Package Manager (Firebase, Factory, CodeScanner); the Flutter module is consumed as a local Swift package (common/build/ios-spm/FlutterNativeIntegration) from make -C common build-ios. App schemes flip Debug/Release via a flutter_integration.sh prebuild pre-action. The host has no CocoaPods; the module build still runs a vestigial pods pass (flutter/flutter#184590) served by the stub podspec in common/vendor/adapty_flutter.
  • iOS 14+ Flutter Debug Limitation: Flutter debug mode apps cannot launch directly on device without Xcode/Flutter tooling. The make -C ios run target defaults to Release mode to bypass this.

Mac Support ("Designed for iPad")

If you get provisioning profile errors when selecting Mac as target:

  1. Register Mac device (requires OTP – must be run manually):
    cd ios
    fastlane run register_device name:"Mac Name" udid:"$(system_profiler SPHardwareDataType | grep 'Provisioning UDID' | awk '{print $3}')" team_id:"HQH5AFGB68"
  2. Regenerate profiles: make fastlane-match

Localization

English source strings live in the translate submodule (deps/translate), keyed by the English phrase itself; new strings are authored there and translated via Crowdin, never extracted from the app. Everything under common/assets/translations/ (and the iOS/Android equivalents) is generated by make translate, so never hand-edit it.

CI/CD

GitHub Actions for CI. See make ci-* targets for CI-specific builds.

Domain Knowledge

Consult docs/domain/ whenever a domain topic needs better understanding — exploring, planning, reviewing, or changing onboarding, startup, protection, subscriptions, home-state, browser-extension flows, or flavor-specific behavior.

Start with:

  • docs/domain/domain-knowledge.md

Then open only the area relevant to the task:

  • docs/domain/shared/ for behavior shared across flavors
  • docs/domain/v6/ for Blokada 6-specific behavior
  • docs/domain/family/ for Family-specific behavior

Keep AGENTS.md as a pointer only. Durable product rules belong in docs/domain/, not duplicated here.

Code Documentation

All code components should carry documentation that explains why the component exists, not only what it does. Apply the same rule to any function or method whose purpose is not obvious from its name and local context.

When adding new code:

  • add or update the relevant doc comment so it captures the component's reason for existing
  • include "why" documentation for non-obvious functions and methods

When modifying existing code:

  • bring the touched code up to this standard as part of the same change
  • update stale comments so they still explain why the code has to exist

Treat this as a required maintenance rule for all newly added code and all code that is modified.

iOS Appium Smoke Test

  • The WebdriverIO + Appium harness lives under automation/appium/wdio/.
  • Device/WebDriverAgent setup steps are documented in automation/appium/README.md (UI testing toggle, installing Appium + xcuitest driver, opening WDA in Xcode, setting the development team, and running the initial install).
  • Run the launch smoke test with make appium-test. Optional overrides:
    • IOS_DEVICE_NAME=<name> to select a connected device by name.
    • IOS_UDID=<udid> to target a specific device directly.
  • The test spawns the global Appium CLI; when executed from automations or assistants, be prepared to request elevated permission so the process can access the device and CoreSimulator services.
  • The harness takes roughly a minute end-to-end. If make appium-test is launched through the CLI tools, bump the command timeout (e.g. timeout_ms: 180000) so the wrapper does not abort at the default 90 s.
  • Test artifacts (screenshots and UI XML dumps) are written to automation/appium/output/ after each run: wdio-launch-foreground.png, wdio-after-power.png, and wdio-launch-foreground.xml.
  • The reusable flows live under automation/appium/wdio/src/flows/ and the primary smoke spec is automation/appium/wdio/src/specs/smoke/dns-onboarding.spec.ts. Assistants can invoke these specs to validate behaviour on a real device (notification handling, DNS provisioning, screenshots, etc.) before or after making code changes.