diff --git a/LanMountainDesktop.PluginIsolation.Ipc/InProcPluginIpcTransport.cs b/LanMountainDesktop.PluginIsolation.Ipc/InProcPluginIpcTransport.cs
new file mode 100644
index 0000000..a5a414d
--- /dev/null
+++ b/LanMountainDesktop.PluginIsolation.Ipc/InProcPluginIpcTransport.cs
@@ -0,0 +1,74 @@
+namespace LanMountainDesktop.PluginIsolation.Ipc;
+
+///
+/// 进程内 IPC 传输。将 的调度委托直接绑定到
+/// 的处理入口,不经过命名管道。
+/// 用于不支持子进程/命名管道的平台(如 Android),插件契约与序列化路径保持不变:
+/// 请求仍会经过 JsonElement 序列化/反序列化边界,与管道传输行为一致。
+///
+public sealed class InProcPluginIpcTransport : IDisposable
+{
+ private readonly PluginIpcClient _client;
+ private volatile bool _disposed;
+
+ private InProcPluginIpcTransport(PluginIpcClient client, PluginIpcServer server)
+ {
+ _client = client;
+ Server = server;
+
+ client.RequestDispatcher = (route, payload, cancellationToken) =>
+ {
+ ThrowIfDisposed();
+ return server.HandleRequestAsync(route, payload, cancellationToken);
+ };
+
+ client.NotificationDispatcher = (route, payload, cancellationToken) =>
+ {
+ ThrowIfDisposed();
+ return server.HandleNotificationAsync(route, payload, cancellationToken);
+ };
+ }
+
+ ///
+ /// 绑定后的服务端。
+ ///
+ public PluginIpcServer Server { get; }
+
+ ///
+ /// 绑定后的客户端。请求/通知将直接分发到 。
+ ///
+ public PluginIpcClient Client => _client;
+
+ ///
+ /// 将客户端与服务端以进程内直通方式连接。
+ ///
+ /// 插件侧客户端
+ /// 宿主侧服务端
+ /// 传输句柄;Dispose 后客户端调度将抛出 。
+ public static InProcPluginIpcTransport Connect(PluginIpcClient client, PluginIpcServer server)
+ {
+ ArgumentNullException.ThrowIfNull(client);
+ ArgumentNullException.ThrowIfNull(server);
+ return new InProcPluginIpcTransport(client, server);
+ }
+
+ ///
+ /// 断开传输。之后客户端的请求/通知将失败。
+ ///
+ public void Dispose()
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ _disposed = true;
+ _client.RequestDispatcher = null;
+ _client.NotificationDispatcher = null;
+ }
+
+ private void ThrowIfDisposed()
+ {
+ ObjectDisposedException.ThrowIf(_disposed, this);
+ }
+}
diff --git a/LanMountainDesktop.Tests/InProcPluginIpcTransportTests.cs b/LanMountainDesktop.Tests/InProcPluginIpcTransportTests.cs
new file mode 100644
index 0000000..70bb325
--- /dev/null
+++ b/LanMountainDesktop.Tests/InProcPluginIpcTransportTests.cs
@@ -0,0 +1,108 @@
+using System.Text.Json;
+using LanMountainDesktop.PluginIsolation.Ipc;
+using Xunit;
+
+namespace LanMountainDesktop.Tests;
+
+///
+/// 进程内 IPC 传输测试:验证与管道传输相同的契约语义
+/// (请求/响应往返、通知投递、错误传播、释放语义)。
+///
+public sealed class InProcPluginIpcTransportTests
+{
+ private static (PluginIpcClient Client, PluginIpcServer Server) CreatePair()
+ {
+ var server = new PluginIpcServer(new PluginIpcServerOptions
+ {
+ PipeName = "inproc-test"
+ });
+ var client = new PluginIpcClient(new PluginIpcClientOptions
+ {
+ PipeName = "inproc-test"
+ });
+ return (client, server);
+ }
+
+ [Fact]
+ public async Task RequestAsync_RoundTripsThroughServerHandler()
+ {
+ var (client, server) = CreatePair();
+ server.MapRequest("test/echo", (payload, _) => Task.FromResult($"echo:{payload}"));
+ using var transport = InProcPluginIpcTransport.Connect(client, server);
+
+ var response = await client.RequestAsync("test/echo", "hello");
+
+ Assert.Equal("echo:hello", response);
+ }
+
+ [Fact]
+ public async Task NotifyAsync_DeliversPayloadToServerHandler()
+ {
+ var (client, server) = CreatePair();
+ var received = new TaskCompletionSource();
+ server.MapNotification("test/notify", (payload, _) =>
+ {
+ received.TrySetResult(payload);
+ return Task.CompletedTask;
+ });
+ using var transport = InProcPluginIpcTransport.Connect(client, server);
+
+ await client.NotifyAsync("test/notify", "ping");
+
+ var payload = await received.Task.WaitAsync(TimeSpan.FromSeconds(5));
+ Assert.Equal("ping", payload);
+ }
+
+ [Fact]
+ public async Task RequestAsync_WhenHandlerThrows_PropagatesException()
+ {
+ var (client, server) = CreatePair();
+ server.MapRequest("test/fail", (_, _) => throw new InvalidOperationException("handler failed"));
+ using var transport = InProcPluginIpcTransport.Connect(client, server);
+
+ var ex = await Assert.ThrowsAsync(
+ () => client.RequestAsync("test/fail", "x"));
+ Assert.Equal("handler failed", ex.Message);
+ }
+
+ [Fact]
+ public async Task RequestAsync_WhenRouteNotRegistered_Throws()
+ {
+ var (client, server) = CreatePair();
+ using var transport = InProcPluginIpcTransport.Connect(client, server);
+
+ await Assert.ThrowsAsync(
+ () => client.RequestAsync("test/missing", "x"));
+ }
+
+ [Fact]
+ public async Task RequestAsync_AfterDispose_ThrowsObjectDisposed()
+ {
+ var (client, server) = CreatePair();
+ server.MapRequest("test/echo", (payload, _) => Task.FromResult(payload));
+ var transport = InProcPluginIpcTransport.Connect(client, server);
+ transport.Dispose();
+
+ // Dispose 后调度委托被摘除,客户端回落到未绑定状态。
+ await Assert.ThrowsAsync(
+ () => client.RequestAsync("test/echo", "x"));
+ }
+
+ [Fact]
+ public async Task RequestAsync_WithCancellation_PassesTokenToHandler()
+ {
+ var (client, server) = CreatePair();
+ using var cts = new CancellationTokenSource();
+ server.MapRequest("test/cancel", async (_, ct) =>
+ {
+ await Task.Delay(Timeout.Infinite, ct);
+ return "never";
+ });
+ using var transport = InProcPluginIpcTransport.Connect(client, server);
+
+ var task = client.RequestAsync("test/cancel", "x", cts.Token);
+ cts.Cancel();
+
+ await Assert.ThrowsAnyAsync(() => task);
+ }
+}
diff --git a/LanMountainDesktop.Tests/LanMountainDesktop.Tests.csproj b/LanMountainDesktop.Tests/LanMountainDesktop.Tests.csproj
index 763edb9..f59fcc1 100644
--- a/LanMountainDesktop.Tests/LanMountainDesktop.Tests.csproj
+++ b/LanMountainDesktop.Tests/LanMountainDesktop.Tests.csproj
@@ -19,6 +19,7 @@
+