# How FlClash Integrates the ClashMeta Core with Flutter on Android and Desktop

> Discover how FlClash integrates ClashMeta core with Flutter on Android and desktop using JNI and IPC, accessed via a unified CoreController API. Explore the technical details.

- Repository: [chen08209/FlClash](https://github.com/chen08209/FlClash)
- Tags: how-to-guide
- Published: 2026-05-31

---

**FlClash bridges its Flutter UI to the native ClashMeta Go core using JNI on Android and JSON-over-IPC on desktop, exposing both platforms through a unified `CoreController` API.**

FlClash is an open-source proxy client maintained by chen08209 that combines the ClashMeta core with a cross-platform Flutter interface. The integration relies on two distinct native communication patterns to deliver the same Dart-level functionality across mobile and desktop operating systems.

## Platform-Specific Integration Architecture

### Android FFI and JNI Layer

On Android, the ClashMeta core compiles into a C shared library (`libclash.so`) using **CGO**. The Flutter layer communicates with this native library through a **MethodChannel** (`com.follow.clash/service`) that forwards calls to Kotlin/Java code, which then invokes the Go functions via **JNI**.

The entry point for these calls resides in [`android/core/src/main/java/com/follow/clash/core/Core.kt`](https://github.com/chen08209/FlClash/blob/main/android/core/src/main/java/com/follow/clash/core/Core.kt), where `external` declarations map to Go-exported C functions such as `init` and `invokeAction`. The Go side exposes these functions in [`core/lib.go`](https://github.com/chen08209/FlClash/blob/main/core/lib.go) and [`core/main_cgo.go`](https://github.com/chen08209/FlClash/blob/main/core/main_cgo.go), allowing the Dart layer to execute core actions within the same process.

### Desktop IPC Process Model

For macOS, Linux, and Windows, FlClash spawns the ClashMeta core as a **separate process**. Flutter communicates through a **JSON-over-IPC** channel using Unix domain sockets on Unix-like systems and named pipes on Windows.

The `CoreService` class launches the Go binary (`appPath.corePath`) with the IPC address as an argument via `Process.start`. The `IPCCoreTransport` class in `lib/core/transport.dart` manages the socket or pipe connection, sending JSON-encoded `Action` objects and receiving `ActionResult` responses. The Go process, implemented in [`core/hub.go`](https://github.com/chen08209/FlClash/blob/main/core/hub.go), reads these messages and dispatches them to the appropriate ClashMeta handlers.

## The CoreController Abstraction

At the heart of the integration sits `CoreController`, a singleton defined in `lib/core/controller.dart` that abstracts platform differences behind a common interface. At runtime, it selects the appropriate implementation based on the host operating system.

```dart
if (system.isAndroid) {
  _interface = coreLib!;          // Android FFI path
} else {
  _interface = coreService!;      // Desktop IPC path
}

```

Both `CoreLib` (Android) and `CoreService` (desktop) implement `CoreHandlerInterface`, ensuring that methods like `init()`, `getProxiesGroups()`, and `changeProxy()` behave identically regardless of the underlying transport mechanism.

## Android Implementation Details

The Android pathway follows a four-step delegation chain from Dart to Go:

1. **Flutter MethodChannel** – The `Service` class in `lib/plugins/service.dart` sends a JSON `Action` through the `com.follow.clash/service` channel.
2. **Kotlin JNI Bridge** – The `Core` object in [`android/core/src/main/java/com/follow/clash/core/Core.kt`](https://github.com/chen08209/FlClash/blob/main/android/core/src/main/java/com/follow/clash/core/Core.kt) receives the JSON and calls the native `invokeAction` C function.
3. **Go Shared Library** – The compiled `libclash.so` (built from [`core/lib.go`](https://github.com/chen08209/FlClash/blob/main/core/lib.go)) dispatches the call to Go handlers such as `handleGetProxies`.
4. **Result Propagation** – The native code returns a JSON string, which Kotlin passes back through the MethodChannel to resolve the original Dart `Future`.

## Desktop Implementation Details

The desktop flow establishes a persistent IPC connection between the Flutter UI and the Go binary:

1. **Process Spawning** – `CoreService.start()` in `lib/core/service.dart` launches the Go executable with the IPC address as a command-line argument.
2. **Transport Initialization** – `IPCCoreTransport` opens the socket or pipe and signals readiness to the Flutter layer.
3. **Action Invocation** – `CoreService.invoke` serializes the `Action` object to JSON and writes it to the transport.
4. **Go Processing** – The Go process reads the message in [`core/hub.go`](https://github.com/chen08209/FlClash/blob/main/core/hub.go), executes the requested action (e.g., `handleChangeProxy`), and writes an `ActionResult` back to the socket.
5. **Dart Completion** – The transport reads the response and completes the awaiting Dart `Future` with the result.

## Practical Code Examples

Initialize the core and preload native resources:

```dart
await coreController.init(version);
await coreController.preload();

```

Fetch proxy groups with latency sorting:

```dart
final groups = await coreController.getProxiesGroups(
  sortType: ProxiesSortType.latency,
  delayMap: {},
  selectedMap: {},
  defaultTestUrl: 'https://www.gstatic.com/generate_204',
);

```

Change the active proxy selection:

```dart
await coreController.changeProxy(
  ChangeProxyParams(groupName: 'Proxy', proxyName: 'US-01'),
);

```

Gracefully shutdown the core:

```dart
await coreController.shutdown(isUser: true);

```

## Summary

- **FlClash** uses **JNI/CGO** on Android to load `libclash.so` directly within the app process, satisfying platform restrictions for VPN services.
- **Desktop platforms** use **JSON-over-IPC** to communicate with a separate Go process via sockets or named pipes, simplifying sandboxing and privilege separation.
- The **`CoreController`** singleton in `lib/core/controller.dart` provides a unified Dart API that transparently selects the correct transport mechanism at runtime.
- Key source files include [`android/core/src/main/java/com/follow/clash/core/Core.kt`](https://github.com/chen08209/FlClash/blob/main/android/core/src/main/java/com/follow/clash/core/Core.kt) for Android JNI, [`core/lib.go`](https://github.com/chen08209/FlClash/blob/main/core/lib.go) for Go exports, and `lib/core/transport.dart` for desktop IPC management.

## Frequently Asked Questions

### Why does FlClash use different integration methods for Android and Desktop?

Android requires in-process execution to satisfy platform restrictions and allow the VPN/TUN service to be driven directly via the FFI layer. Desktop systems can safely launch the core as a stand-alone process, simplifying sandboxing and allowing the core to run with its own privileges, particularly on Windows where helper services may be used.

### How does the Dart layer handle platform detection?

The `CoreController` singleton checks `system.isAndroid` during initialization. If true, it instantiates `CoreLib` for FFI communication; otherwise, it instantiates `CoreService` for IPC communication. Both classes implement the same `CoreHandlerInterface`, ensuring the rest of the application remains platform-agnostic.

### Can the FlClash core run independently of the Flutter UI on desktop?

Yes. On desktop platforms, the core runs as a separate Go binary spawned by `CoreService` via `Process.start`. It listens on a Unix domain socket or named pipe and can persist independently until explicitly shut down through the IPC channel.

### What is the role of the `Action` and `ActionResult` classes in FlClash?

These classes define the JSON message protocol used across both platforms. `Action` encapsulates method calls and parameters sent from Dart to Go, while `ActionResult` wraps return values and errors sent back to Dart. This unified message format allows the same Go handlers in [`core/hub.go`](https://github.com/chen08209/FlClash/blob/main/core/hub.go) to service requests from both Android (via JNI delegation) and desktop (via IPC).