EasyCord LogoDocs
Core Architecture

Bridge Communication

Understand how EasyCord routes messages between JavaScript and native Dart environments without serialization overhead.

Overview

The EasyCord Bridge facilitates bidirectional communication between the web frontend and the native mobile environment. It establishes a persistent, high-performance message port when the application loads.

Use the Bridge to:

  • Execute native Dart functions from JavaScript.
  • Pass JSON payloads between environments.
  • Transfer raw binary data (e.g. images) seamlessly via zero-copy ArrayBuffer payloads.
  • Stream continuous sensor data from native hardware to the web UI.

Example

The most common operation is invoking a native Dart method from JavaScript and awaiting its response.

try {
  const result = await window.easycord.call('getBatteryLevel', {
    detailed: true
  });
  console.log(`Battery level: ${result.level}%`);
} catch (error) {
  console.error('Failed to read battery:', error.message);
}

How It Works

When EasyCord.initialize() runs in Dart, it injects the window.easycord JavaScript object into the WebView.

When JavaScript calls window.easycord.call(), the payload routes through a native JavaScriptChannel. Dart processes the request, checks permissions against easycord_permissions.yaml, executes the registered handler, and returns a stringified JSON response directly into the pending JavaScript Promise.

Advanced Features

Multi-WebView Concurrency

EasyCord's native bridge is designed to support multiple simultaneous WebViews within the same application (for example, a primary application window and a Picture-in-Picture background worker).

The native EasyCordBridge dynamically routes messages, events, and native streams (like GPS tracking) to the exact EasyCordWebView instance that requested them. Each webview is securely isolated using a generated webviewOffset injected at initialization, ensuring streamId tokens remain globally unique across your enterprise application.

Strict JS Payload Validation

To prevent malformed bridge payloads from reaching the native layer and causing unhandled Dart casting exceptions, EasyCord injects a strict runtime schema validator directly into the JavaScript SDK.

Core plugins (like easycord_fs and easycord_sqlite) validate JavaScript argument types (strings, integers, booleans) locally inside the WebView before passing the serialization boundary. If validation fails, the native bridge is bypassed entirely, and your JavaScript promise immediately rejects with a clear, readable validation error.

Next Steps

API

call()

Executes a registered native Dart method.

Parameters

NameTypeRequiredDescription
methodstringYesThe exact string name registered in Dart.
payloadobjectNoJSON-serializable arguments to pass to the native handler.

Returns

Promise<any> containing the JSON response from Dart.

Throws

  • MethodNotAllowedError: The method is not whitelisted in easycord_permissions.yaml.
  • MethodNotFoundError: The method is not registered via EasyCordBridge.register().
  • NativeExecutionError: The Dart handler threw an exception during execution.

stream()

Subscribes to a continuous stream of events from Dart.

Parameters

NameTypeRequiredDescription
namestringYesThe exact stream name registered in Dart.
callbackfunctionYesFunction invoked every time Dart emits a new event payload.

Returns

function: An unsubscribe function. Calling it terminates the native stream.

Examples

Registering a Dart Handler

Before JavaScript can call a method, you must register it in Dart.

import 'package:easycord/easycord.dart';
import 'package:flutter/material.dart';

void main() {
  EasyCordBridge.register('getBatteryLevel', (Map<String, dynamic> payload) async {
    final bool detailed = payload['detailed'] ?? false;
    final int batteryLevel = await getNativeBatteryLevel();
    
    return { 
      'level': batteryLevel,
      'status': detailed ? 'charging' : 'unknown'
    };
  });

  runApp(const MyApp());
}

Streaming Native Data to JavaScript

Register a stream in Dart to continuously push data.

import 'package:easycord/easycord.dart';

void registerLocationStream() {
  EasyCordBridge.createStream('locationUpdates', (emit) {
    final subscription = NativeGPS.getPositionStream().listen((position) {
      emit({ 'lat': position.latitude, 'lng': position.longitude });
    });
    
    return () => subscription.cancel();
  });
}

Subscribe to the stream in JavaScript.

const unsubscribe = window.easycord.stream('locationUpdates', (position) => {
  console.log(`Lat: ${position.lat}, Lng: ${position.lng}`);
});

// Stop receiving updates and cancel the Dart stream
unsubscribe();

Developers often call a method in JavaScript without registering it in Dart or adding it to easycord_permissions.yaml.

Cause: Security restrictions prevent arbitrary method execution.

Solution:

  1. Verify EasyCordBridge.register('myMethod', ...) runs in Dart.
  2. Add myMethod to the allowed list in easycord_permissions.yaml.