Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copilot Instructions

## Project

This is a .NET MAUI class library (`Com.Bnotech.ExtendedWebView`) providing an extended WebView control with JavaScript interop, navigation events, cookie management, and URL change detection. It targets `net10.0-android` and `net10.0-ios`.

## Code Style

- Use file-scoped namespaces (`namespace X;`)
- Use primary constructors where applicable (see `SourceChangedEventArgs`, `UrlChangedEventArgs`)
- Nullable reference types are enabled — respect nullability annotations
- Platform-specific code lives under `Platforms/{Android,iOS}/Handlers/` and uses `#if ANDROID` / `#elif IOS` conditional compilation in shared files
- All public types and members must have XML doc comments in English

## Architecture Rules

- All public API surfaces go through the `IExtWebView` interface (`Interfaces/IExtWebView.cs`) — add new members there first, then implement in `ExtWebView`
- EventArgs classes go in `Events/` as individual files, one class per file
- Platform handlers extend `ViewHandler<IExtWebView, TNativeView>` with `CreatePlatformView`, `ConnectHandler`, `DisconnectHandler`
- JS bridge classes must use `WeakReference<ExtWebViewHandler>` to avoid preventing GC of the handler
- Event subscriptions in `ConnectHandler` must be unsubscribed in `DisconnectHandler`
- Register new handlers in `AppBuilderExtensions.cs` behind platform `#if` directives
- New cross-platform methods follow the event-driven pattern: method on `ExtWebView` fires a `Request*` event, platform handler subscribes and executes via `SynchronizationContext.Post`

## Build

```bash
dotnet build ExtendedWebView/ExtendedWebView.csproj
dotnet pack ExtendedWebView/ExtendedWebView.csproj -c Release
```

## .NET Skills

This project benefits from the following skills from [dotnet/skills](https://github.com/dotnet/skills):

- **dotnet-maui** — `dotnet-maui-doctor`, `maui-app-lifecycle`, `maui-dependency-injection`
- **dotnet-msbuild** — `msbuild-antipatterns`

Install via Copilot CLI: `/plugin marketplace add dotnet/skills` then `/plugin install dotnet-maui@dotnet-agent-skills`
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 9.0.x
dotnet-version: 10.0.x

- name: Install MAUI workload
run: dotnet workload install maui
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 9.0.x
dotnet-version: 10.0.x

- name: Install MAUI workload
run: dotnet workload install maui
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 9.0.x
dotnet-version: 10.0.x

- name: Install MAUI workload
run: dotnet workload install maui
Expand Down
56 changes: 56 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# AGENTS.md

## Project Overview

.NET MAUI library (`Com.Bnotech.ExtendedWebView`) providing an enhanced WebView control with JavaScript interop, navigation events, cookie management, and URL change detection for Android and iOS. Published as NuGet package.

## Architecture

- **`Interfaces/IExtWebView.cs`** — Public API contract. All new members must be added here first.
- **`ExtWebView.cs`** — Cross-platform control implementing `IExtWebView`. Extends MAUI `View` with `BindableProperty` for `Source`, event-driven JS bridge (`InvokeAction`/`JavaScriptAction`), navigation events, and cookie management (`SetCookieAsync`/`UpdateCookieAsync`/`RemoveCookieAsync`/`RemoveAllCookiesAsync`).
- **`Events/`** — EventArgs classes, one per file: `SourceChangedEventArgs`, `UrlChangedEventArgs`, `JavaScriptActionEventArgs`, `SetCookieRequestEventArgs`, `RemoveCookieRequestEventArgs`, `RemoveAllCookiesRequestEventArgs`.
- **`Platforms/Android/Handlers/ExtWebViewHandler.cs`** — Android handler using `Android.Webkit.WebView`. JS bridge via `@JavascriptInterface` + `AddJavascriptInterface`. URL changes detected via `DoUpdateVisitedHistory`. Cookie management via `CookieManager`. Includes `MultiWindowWebChromeClient` for popup/multi-window support (renders child WebView in an `AlertDialog`). Enables `WebContentsDebuggingEnabled` in `DEBUG` builds.
- **`Platforms/iOS/Handlers/ExtWebViewHandler.cs`** — iOS handler using `WKWebView`. JS bridge via `WKScriptMessageHandler`. URL changes detected via KVO observer on `"URL"` property. Cookie management via `WKHttpCookieStore` + `NSHttpCookieStorage.SharedStorage`. Includes `NavigationDelegate` (cookie syncing, navigation events, and a keep-alive timer via `Dispatcher.StartTimer` with `EvaluateJavaScript("1+1;")` every 500ms in `DidFinishNavigation`).
- **`AppBuilderExtensions.cs`** — Registration via `builder.UseExtendedWebView()` using `#if ANDROID`/`#elif IOS` conditional compilation.

## Key Patterns

- **Handler pattern**: Each platform has a `ViewHandler<IExtWebView, NativeView>` subclass with `CreatePlatformView`, `ConnectHandler`, `DisconnectHandler` lifecycle.
- **JS → C# bridge**: Web page calls `invokeCSharpAction(data)` which routes to `IExtWebView.InvokeAction(data)` → `JavaScriptAction` event. The JS function is injected differently per platform (Android: `OnPageStarted`, iOS: `WKUserScript` at document end).
- **C# → JS**: Use `EvaluateJavaScriptAsync(EvaluateJavaScriptAsyncRequest)` which fires `RequestEvaluateJavaScript` event, handled by platform handler via `SynchronizationContext.Post`.
- **Source changes** propagate through `BindableProperty.propertyChanged` → `SourceChanged` event → handler loads URL/HTML. iOS handler deduplicates identical source updates.
- **Cookie management**: `SetCookieAsync`/`UpdateCookieAsync`/`RemoveCookieAsync`/`RemoveAllCookiesAsync` follow the same event-driven pattern as `EvaluateJavaScriptAsync`. `UpdateCookieAsync` delegates to `SetCookieAsync` (setting a cookie with the same name/domain/path overwrites it). On Android, removal sets an expired cookie; on iOS, cookies are matched and deleted from both `WKHttpCookieStore` and `NSHttpCookieStorage`.

## Build & Configuration

- **Targets**: `net10.0-android;net10.0-ios` (MAUI 10.0.41)
- **Namespace**: `Com.Bnotech.ExtendedWebView`
- **Build**: `dotnet build ExtendedWebView/ExtendedWebView.csproj`
- **Pack**: `dotnet pack -c Release` → produces `Com.Bnotech.ExtendedWebView.{version}.nupkg`
- No test project exists in the solution.

## Recommended .NET Skills

Install relevant skills from [dotnet/skills](https://github.com/dotnet/skills) for enhanced AI agent support:

- **`dotnet-maui`** — `dotnet-maui-doctor` (environment diagnostics), `maui-app-lifecycle` (handler lifecycle patterns), `maui-dependency-injection` (service registration via `MauiAppBuilder`)
- **`dotnet-msbuild`** — `msbuild-antipatterns` (csproj hygiene)

Install: `/plugin marketplace add dotnet/skills` → `/plugin install dotnet-maui@dotnet-agent-skills`

## Code Style

- Use file-scoped namespaces (`namespace X;`)
- Use primary constructors where applicable (see `SourceChangedEventArgs`, `UrlChangedEventArgs`)
- Nullable reference types are enabled — respect nullability annotations
- All public types and members must have XML doc comments in English

## When Making Changes

- Any new platform handler must follow the existing `ViewHandler<IExtWebView, T>` pattern and be registered in `AppBuilderExtensions.cs` behind the appropriate `#if` directive.
- New events/methods must be added to both `IExtWebView` interface and `ExtWebView` class, then handled in each platform handler.
- New cross-platform methods follow the event-driven pattern: method on `ExtWebView` fires a `Request*` event, platform handler subscribes and executes via `SynchronizationContext.Post`.
- The `JSBridge` classes use `WeakReference<ExtWebViewHandler>` to avoid preventing GC of the handler — maintain this pattern.
- Resource cleanup happens in `DisconnectHandler` — always unsubscribe events and dispose native resources there.
- New EventArgs classes go in `Events/` as individual files with the same namespace (`Com.Bnotech.ExtendedWebView`).
- All public types and members must have XML doc comments in English.
15 changes: 15 additions & 0 deletions ExtendedWebView/Events/JavaScriptActionEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Com.Bnotech.ExtendedWebView;

/// <summary>
/// Event data for <see cref="IExtWebView.JavaScriptAction"/>. Contains the string payload
/// sent from JavaScript via <c>invokeCSharpAction(data)</c>.
/// </summary>
public class JavaScriptActionEventArgs : EventArgs
{
public string Payload { get; private set; }

public JavaScriptActionEventArgs(string payload)
{
Payload = payload;
}
}
8 changes: 8 additions & 0 deletions ExtendedWebView/Events/RemoveAllCookiesRequestEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Com.Bnotech.ExtendedWebView;

/// <summary>
/// Event data for <see cref="IExtWebView.RequestRemoveAllCookies"/>. Signals the platform handler
/// to remove all cookies from both the WebView cookie store and shared storage.
/// </summary>
public class RemoveAllCookiesRequestEventArgs : EventArgs;

12 changes: 12 additions & 0 deletions ExtendedWebView/Events/RemoveCookieRequestEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Com.Bnotech.ExtendedWebView;

/// <summary>
/// Event data for <see cref="IExtWebView.RequestRemoveCookie"/>. Identifies a specific cookie
/// by name, domain, and path for removal from the platform WebView's cookie store.
/// </summary>
public class RemoveCookieRequestEventArgs(string name, string domain, string path) : EventArgs
{
public string Name { get; private set; } = name;
public string Domain { get; private set; } = domain;
public string Path { get; private set; } = path;
}
16 changes: 16 additions & 0 deletions ExtendedWebView/Events/SetCookieRequestEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Com.Bnotech.ExtendedWebView;

/// <summary>
/// Event data for <see cref="IExtWebView.RequestSetCookie"/>. Contains all properties
/// needed to create a cookie on the platform WebView's cookie store.
/// </summary>
public class SetCookieRequestEventArgs(string name, string value, string domain, string path, DateTimeOffset? expires = null, bool isSecure = false, bool isHttpOnly = false) : EventArgs
{
public string Name { get; private set; } = name;
public string Value { get; private set; } = value;
public string Domain { get; private set; } = domain;
public string Path { get; private set; } = path;
public DateTimeOffset? Expires { get; private set; } = expires;
public bool IsSecure { get; private set; } = isSecure;
public bool IsHttpOnly { get; private set; } = isHttpOnly;
}
13 changes: 13 additions & 0 deletions ExtendedWebView/Events/SourceChangedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Com.Bnotech.ExtendedWebView;

/// <summary>
/// Event data for <see cref="IExtWebView.SourceChanged"/>. Contains the new <see cref="WebViewSource"/>.
/// </summary>
public class SourceChangedEventArgs(WebViewSource source) : EventArgs
{
public WebViewSource Source
{
get;
private set;
} = source;
}
14 changes: 14 additions & 0 deletions ExtendedWebView/Events/UrlChangedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Com.Bnotech.ExtendedWebView;

/// <summary>
/// Event data for <see cref="IExtWebView.UrlChanged"/>. Contains the new URL string
/// detected via platform-specific URL change observation (SPA/PWA route changes).
/// </summary>
public class UrlChangedEventArgs(string url) : EventArgs
{
public string Url
{
get;
private set;
} = url;
}
Loading
Loading