WebAppHarness.App 1.0.14

dotnet add package WebAppHarness.App --version 1.0.14
                    
NuGet\Install-Package WebAppHarness.App -Version 1.0.14
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="WebAppHarness.App" Version="1.0.14" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="WebAppHarness.App" Version="1.0.14" />
                    
Directory.Packages.props
<PackageReference Include="WebAppHarness.App" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add WebAppHarness.App --version 1.0.14
                    
#r "nuget: WebAppHarness.App, 1.0.14"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package WebAppHarness.App@1.0.14
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=WebAppHarness.App&version=1.0.14
                    
Install as a Cake Addin
#tool nuget:?package=WebAppHarness.App&version=1.0.14
                    
Install as a Cake Tool

WebApp Harness

A cross-platform WebView harness for hosting web applications as native apps. Built with .NET MAUI, targeting Windows (WebView2), Android, iOS, and Mac Catalyst.

Features

  • Full-page WebView hosting with configurable app URL
  • DevTools support on all platforms (F12 on Windows, Chrome DevTools on Android, Safari Web Inspector on iOS/Mac Catalyst)
  • CDP remote debugging port for UI automation (Windows/Android)
  • postMessage-based native bridge (window.nativeBridge) with request/response and event semantics
  • Pluggable telemetry pipeline with console and file sinks
  • JSON configuration (harness-config.json)

Quickstart

dotnet restore
dotnet build harness/dotnet/WebAppHarness.Core/WebAppHarness.Core.csproj               # core library (no MAUI needed)
dotnet test harness/tests/WebAppHarness.Core.Tests/WebAppHarness.Core.Tests.csproj      # run core tests
dotnet build harness/dotnet/WebAppHarness.App/WebAppHarness.App.csproj -f net10.0-windows10.0.19041.0   # MAUI app (Windows)

Prerequisites

  • .NET 10 SDK (LTS). The repo pins the 10.0 band via global.json.
  • MAUI workload for any native shell build: dotnet workload install maui
    • Or run the bootstrap script: ./scripts/setup.sh (macOS/Linux) or ./scripts/setup.ps1 (Windows).
  • Node.js 22+ for the web layer.

Per-platform native prerequisites (only what you actually build/run):

Target Requires
Windows (net10.0-windows10.0.19041.0) Windows host + Windows 10 SDK (19041+)
Android (net10.0-android) Android SDK
iOS (net10.0-ios) macOS + Xcode
Mac Catalyst (net10.0-maccatalyst) macOS + Xcode

The WebAppHarness.Core library targets plain net10.0 and needs no MAUI workload.

Build

Build everything (requires MAUI workload):

dotnet build WebAppHarness.sln

Build just the Core library (no MAUI needed):

dotnet build harness/dotnet/WebAppHarness.Core/WebAppHarness.Core.csproj

Build the MAUI app for Windows only:

dotnet build harness/dotnet/WebAppHarness.App/WebAppHarness.App.csproj -f net10.0-windows10.0.19041.0

Running on Apple platforms (Mac Catalyst and iOS)

Windows (WebView2) is Windows-only, so on a Mac the native shell runs through the Apple WebView targets, which share a single WKWebView handler. From a Mac with Xcode + the MAUI workload:

Mac Catalyst (runs as a desktop app):

./scripts/setup.sh                                                                   # one-time: install maui workload
dotnet build samples/SampleHost.App/SampleHost.App.csproj -f net10.0-maccatalyst -t:Run

iOS Simulator:

xcodebuild -downloadPlatform iOS                                                     # one-time: install a simulator runtime (if none present)
xcrun simctl boot "iPhone 16 Pro"                                                    # boot a simulator (create one via `simctl create` if needed)
open -a Simulator
dotnet build samples/SampleHost.App/SampleHost.App.csproj \
  -f net10.0-ios -p:RuntimeIdentifier=iossimulator-arm64 -p:HarnessTargetFrameworks=net10.0-ios
xcrun simctl install booted samples/SampleHost.App/bin/Debug/net10.0-ios/iossimulator-arm64/SampleHost.App.app
xcrun simctl launch booted com.webappharness.samples

The web assets are bundled into the app and served from local wwwroot — no dev server needed. WKWebView has no WebView2-style host mapping and cannot host a Vite build over file:// (WebKit blocks cross-origin ES modules on file://), so the harness registers a custom harness:// URL scheme handler that serves wwwroot under a real origin (harness://app.harness.local). Set appUrl to https://app.harness.local/index.html exactly as on Windows; the shared Apple handler rewrites it onto the harness:// scheme automatically.

Troubleshooting (local builds):

  • Xcode version mismatch — the iOS/maccatalyst SDKs pin an exact Xcode version. If your installed Xcode is newer, add -p:ValidateXcodeVersion=false to build against it (safe within the same SDK major version).
  • Packing / single-platform builds on a Mac — the App/host csprojs list every platform TFM (incl. Windows/Android, which can't build on macOS). To pack or build a single platform, pass -p:HarnessTargetFrameworks=net10.0-maccatalyst (or net10.0-ios).

Run Tests

Run all tests:

dotnet test

Run only Core tests (no MAUI needed):

dotnet test harness/tests/WebAppHarness.Core.Tests/WebAppHarness.Core.Tests.csproj

Sample App

Reference sample apps are available in samples/. See samples/README.md for details.

Build the samples' web layer (and optionally the .NET host) with:

./samples/build.ps1            # web only -> SampleHost.App/wwwroot/
./samples/build.ps1 -DotNet    # also packs harness packages to ./local-feed
                               # and builds SampleHost.App against them

SampleHost.App is not part of WebAppHarness.sln: it consumes the harness as NuGet packages (from ./local-feed), just like an external app would.

The sample demonstrates:

  • System Info -- query harness version, platform, and runtime details
  • Echo -- request/response round-trip through the bridge
  • Key-Value Storage -- read, write, delete, and list keys via native storage
  • Telemetry -- fire events and errors through the native pipeline
  • Event Log -- observe native events (e.g. harness.ready) as they arrive

Configuration

Edit harness-config.json (copied to the output directory alongside the app):

{
  "appUrl": "https://your-app.example.com",
  "devTools": true,
  "cdpPort": 9222,
  "window": { "width": 1280, "height": 800, "title": "My App" },
  "telemetry": {
    "sinks": ["console", "file"],
    "fileSink": { "path": "logs/", "maxSizeMb": 50 }
  }
}

Bridge API (JavaScript)

The harness injects window.nativeBridge into every page:

// Request/response (returns Promise)
const result = await nativeBridge.request('echo', { message: 'hello' });

// Fire-and-forget
nativeBridge.invoke('telemetry.trackEvent', { name: 'click', props: {} });

// Listen for native events
const unsubscribe = nativeBridge.on('harness.ready', (data) => { ... });

// Built-in telemetry
nativeBridge.telemetry.trackEvent('page.loaded', { route: '/home' });
nativeBridge.telemetry.trackError(new Error('something broke'));

Built-in Capabilities

Prefix Method Description
echo (direct) Returns whatever args you send (for testing)
system getInfo Harness version, .NET runtime, OS, architecture
system getPlatform Current platform (windows/android/ios/maccatalyst)
storage get, set, delete, keys In-memory key-value storage
telemetry trackEvent, trackError Route telemetry through the native pipeline

Virtual Host Mapping

Place your web app files in wwwroot/ and set appUrl to https://app.harness.local/index.html. Each platform serves that folder under a stable origin so relative asset paths and ES modules resolve correctly:

  • Windows (WebView2): maps https://app.harness.local/ to wwwroot/ via SetVirtualHostNameToFolderMapping.
  • Apple — iOS and Mac Catalyst (WKWebView): WKWebView has no host-mapping API and cannot host a Vite build over file://, so a single shared Apple handler registers a custom harness:// URL scheme handler that serves wwwroot under harness://app.harness.local/. The configured appUrl is rewritten onto the harness:// scheme automatically. The scheme handler returns proper HTTP 200 responses so fetch/response.ok-based loaders (e.g. PixiJS textures) work.

Project Structure

harness/
  dotnet/
    WebAppHarness.Core/       .NET class library (no MAUI dependency)
      Bridge/                  postMessage protocol, router, capabilities
      Config/                  JSON config model and loader
      Telemetry/               Event pipeline, sinks (console, file)
      Logging/                 Structured logging interface
    WebAppHarness.App/         .NET MAUI app shell
      Platforms/               Platform-specific WebView handlers (Windows, Android)
      WebView/                 Shared Apple (iOS + Mac Catalyst) WebView handler
      Resources/Raw/           Injected JS bridge shim
      wwwroot/                 Build output (bundled web app)
  web/                         Vite build system + shared JS utilities
  tests/
    WebAppHarness.Core.Tests/  xUnit tests for Core library
samples/                       Reference sample apps

Consuming as a Dependency

The harness publishes three artifacts. Your web app is the "base app": you build it into wwwroot/ using the harness toolchain, and the MAUI shell hosts it.

NuGet Packages (.NET shell)

  • WebAppHarness.Core — bridge/telemetry/config library (net10.0).
  • WebAppHarness.App — the MAUI hosting shell, packaged as a library. Reference it, then provide a thin app head: derive App : HarnessApp and call .UseMauiApp<App>().UseWebAppHarness() in your MauiProgram.
dotnet add package WebAppHarness.Core
dotnet add package WebAppHarness.App

npm Package (web toolchain + shared utilities)

npm install webappharness

Then drive your Vite build from the factory and use the shared utilities:

// vite.config.ts
import { createViteConfig } from 'webappharness/vite'
export default createViteConfig({ appDir: __dirname })
import { useBridge } from '@shared/BridgeContext'   // alias injected by the factory

Local dogfooding (how the sample host consumes it)

samples/SampleHost.App consumes the harness exactly like an external app, but from local build artifacts instead of the public registries:

  • .NET: build.ps1 -DotNet packs WebAppHarness.Core/.App into ./local-feed (registered in nuget.config) and builds the host against those packages.
  • web: samples/apps/bridge-demo declares a file: dependency on webappharness and imports the factory by package name.

This means CI and the sample build exercise the exact published surface.

Product Compatible and additional computed target framework versions.
.NET net10.0-android36.0 is compatible.  net10.0-ios26.0 is compatible.  net10.0-maccatalyst26.0 is compatible.  net10.0-windows10.0.19041 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.14 127 7/4/2026
1.0.13 131 7/4/2026