桥接机制 #
一、桥接概述 #
1.1 什么是桥接 #
桥接(Bridge)是Capacitor的核心机制,它负责在JavaScript代码和原生平台代码之间建立通信通道。通过桥接,Web应用可以调用原生功能,原生代码也可以向JavaScript发送事件。
text
┌─────────────────────────────────────────────────────────────┐
│ Bridge │
│ │
│ JavaScript ◀──────────────────────▶ Native Code │
│ │
│ - 调用原生方法 - 执行原生功能 │
│ - 接收原生事件 - 返回结果 │
│ - 传递参数 - 发送事件 │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 桥接类型 #
| 类型 | 方向 | 用途 |
|---|---|---|
| 方法调用 | JS → Native | 调用原生功能 |
| 结果返回 | Native → JS | 返回调用结果 |
| 事件通知 | Native → JS | 原生事件通知 |
| 回调触发 | Native → JS | 异步回调 |
二、通信协议 #
2.1 消息格式 #
typescript
// 调用请求格式
interface BridgeCall {
pluginId: string; // 插件标识
methodName: string; // 方法名称
options: any; // 调用参数
callbackId?: string; // 回调标识
}
// 响应格式
interface BridgeResponse {
callbackId?: string; // 回调标识
success: boolean; // 是否成功
data?: any; // 返回数据
error?: { // 错误信息
message: string;
code?: string;
};
}
// 事件格式
interface BridgeEvent {
pluginId: string; // 插件标识
eventName: string; // 事件名称
data: any; // 事件数据
}
2.2 序列化 #
typescript
// 参数序列化
function serialize(options: any): string {
// 处理特殊类型
const processed = JSON.stringify(options, (key, value) => {
// 处理Date对象
if (value instanceof Date) {
return { __type: 'Date', value: value.toISOString() };
}
// 处理ArrayBuffer
if (value instanceof ArrayBuffer) {
return { __type: 'ArrayBuffer', value: arrayBufferToBase64(value) };
}
return value;
});
return processed;
}
// 反序列化
function deserialize(json: string): any {
return JSON.parse(json, (key, value) => {
if (value?.__type === 'Date') {
return new Date(value.value);
}
if (value?.__type === 'ArrayBuffer') {
return base64ToArrayBuffer(value.value);
}
return value;
});
}
三、iOS桥接实现 #
3.1 WKWebView消息处理 #
swift
// iOS桥接核心
class CapacitorBridge: NSObject, WKScriptMessageHandler {
private var webView: WKWebView!
private var messageHandlerName = "capacitorBridge"
func setupWebView() {
// 注册消息处理器
let contentController = webView.configuration.userContentController
contentController.add(self, name: messageHandlerName)
// 注入Capacitor运行时
let capacitorJS = """
window.Capacitor = {
nativeCallback: function(pluginName, methodName, options, callback) {
window.webkit.messageHandlers.capacitorBridge.postMessage({
pluginName: pluginName,
methodName: methodName,
options: options,
callbackId: callback ? this.generateCallbackId() : null
});
}
};
"""
let script = WKUserScript(source: capacitorJS,
injectionTime: .atDocumentStart,
forMainFrameOnly: true)
contentController.addUserScript(script)
}
// 接收来自JavaScript的消息
func userContentController(_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let body = message.body as? [String: Any] else { return }
let pluginName = body["pluginName"] as? String ?? ""
let methodName = body["methodName"] as? String ?? ""
let options = body["options"] as? [String: Any] ?? [:]
let callbackId = body["callbackId"] as? String
// 调用插件方法
handlePluginCall(pluginName: pluginName,
methodName: methodName,
options: options,
callbackId: callbackId)
}
}
3.2 插件调用处理 #
swift
extension CapacitorBridge {
func handlePluginCall(pluginName: String,
methodName: String,
options: [String: Any],
callbackId: String?) {
// 获取插件实例
guard let plugin = plugins[pluginName] else {
sendError(callbackId: callbackId,
error: "Plugin not found: \(pluginName)")
return
}
// 执行方法
do {
let result = try plugin.execute(methodName: methodName, options: options)
// 返回结果
if let callbackId = callbackId {
sendSuccess(callbackId: callbackId, data: result)
}
} catch {
sendError(callbackId: callbackId, error: error.localizedDescription)
}
}
// 发送成功结果到JavaScript
func sendSuccess(callbackId: String, data: Any?) {
let js = """
window.Capacitor.handleCallback('\(callbackId)', true, \(data ?? "null"));
"""
webView.evaluateJavaScript(js)
}
// 发送错误到JavaScript
func sendError(callbackId: String, error: String) {
let js = """
window.Capacitor.handleCallback('\(callbackId)', false, { message: '\(error)' });
"""
webView.evaluateJavaScript(js)
}
}
3.3 事件发送 #
swift
extension CapacitorBridge {
// 从原生向JavaScript发送事件
func sendEvent(pluginName: String, eventName: String, data: [String: Any]) {
let jsonData = try? JSONSerialization.data(withJSONObject: data)
let jsonString = jsonData.flatMap { String(data: $0, encoding: .utf8) } ?? "{}"
let js = """
window.Capacitor.triggerEvent('\(pluginName)', '\(eventName)', \(jsonString));
"""
DispatchQueue.main.async {
self.webView.evaluateJavaScript(js)
}
}
}
// 使用示例
class NetworkPlugin: CAPPlugin {
func notifyNetworkChange(connected: Bool) {
bridge?.sendEvent(
pluginName: "Network",
eventName: "networkStatusChange",
data: ["connected": connected]
)
}
}
四、Android桥接实现 #
4.1 WebView JavaScript接口 #
java
// Android桥接核心
public class CapacitorBridge {
private WebView webView;
private static final String BRIDGE_NAME = "CapacitorAndroidBridge";
public void setupWebView(WebView webView) {
this.webView = webView;
// 启用JavaScript
webView.getSettings().setJavaScriptEnabled(true);
// 添加JavaScript接口
webView.addJavascriptInterface(new BridgeInterface(), BRIDGE_NAME);
// 注入Capacitor运行时
String js = "window.Capacitor = {" +
"nativeCallback: function(pluginName, methodName, options, callback) {" +
" var result = window." + BRIDGE_NAME + ".callPlugin(" +
" pluginName, methodName, JSON.stringify(options));" +
" return JSON.parse(result);" +
"}" +
"};";
webView.evaluateJavascript(js, null);
}
// JavaScript接口类
private class BridgeInterface {
@JavascriptInterface
public String callPlugin(String pluginName, String methodName, String optionsJson) {
try {
JSONObject options = new JSONObject(optionsJson);
Plugin plugin = plugins.get(pluginName);
if (plugin == null) {
return errorResponse("Plugin not found: " + pluginName);
}
JSONObject result = plugin.execute(methodName, options);
return successResponse(result);
} catch (Exception e) {
return errorResponse(e.getMessage());
}
}
}
}
4.2 异步调用处理 #
java
public class CapacitorBridge {
private Map<String, PluginCall> savedCalls = new HashMap<>();
// 保存异步调用
public void saveCall(PluginCall call) {
savedCalls.put(call.getCallbackId(), call);
}
// 获取保存的调用
public PluginCall getSavedCall(String callbackId) {
return savedCalls.get(callbackId);
}
// 释放保存的调用
public void releaseCall(PluginCall call) {
savedCalls.remove(call.getCallbackId());
}
// 异步返回结果
public void resolveCall(PluginCall call, JSObject data) {
String js = String.format(
"window.Capacitor.handleCallback('%s', true, %s);",
call.getCallbackId(),
data.toString()
);
webView.post(() -> webView.evaluateJavascript(js, null));
releaseCall(call);
}
}
// 插件异步调用示例
public class CameraPlugin extends Plugin {
@PluginMethod
public void getPhoto(PluginCall call) {
// 保存调用以便后续返回结果
bridge.saveCall(call);
// 启动相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_REQUEST_CODE) {
PluginCall call = bridge.getSavedCall(callId);
JSObject result = new JSObject();
result.put("dataUrl", imageDataUrl);
bridge.resolveCall(call, result);
}
}
}
4.3 事件发送 #
java
public class CapacitorBridge {
// 发送事件到JavaScript
public void sendEvent(String pluginName, String eventName, JSObject data) {
String js = String.format(
"window.Capacitor.triggerEvent('%s', '%s', %s);",
pluginName, eventName, data.toString()
);
// 确保在UI线程执行
webView.post(() -> webView.evaluateJavascript(js, null));
}
}
// 使用示例
public class NetworkPlugin extends Plugin {
private BroadcastReceiver networkReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean connected = isNetworkConnected();
JSObject data = new JSObject();
data.put("connected", connected);
bridge.sendEvent("Network", "networkStatusChange", data);
}
};
}
五、JavaScript桥接接口 #
5.1 核心接口 #
typescript
// Capacitor核心对象
interface CapacitorGlobal {
// 平台标识
platform: 'ios' | 'android' | 'web';
isNative: boolean;
// 插件注册
registerPlugin<T>(pluginName: string, options?: PluginRegistrationOptions): T;
// 原生调用
nativeCallback(
pluginName: string,
methodName: string,
options?: any,
callback?: (result: any) => void
): void;
// 原生Promise调用
nativePromise<T>(
pluginName: string,
methodName: string,
options?: any
): Promise<T>;
// 事件触发
triggerEvent(pluginName: string, eventName: string, data: any): void;
// 回调处理
handleCallback(callbackId: string, success: boolean, data: any): void;
// 事件监听
addEventListener(eventName: string, listener: Function): void;
removeEventListener(eventName: string, listener: Function): void;
// 已注册插件
Plugins: { [pluginName: string]: any };
}
declare global {
interface Window {
Capacitor: CapacitorGlobal;
}
}
5.2 插件代理实现 #
typescript
// 插件代理
class PluginProxy implements ProxyHandler<any> {
private pluginName: string;
constructor(pluginName: string) {
this.pluginName = pluginName;
}
get(target: any, property: string) {
// 返回方法调用函数
return async (...args: any[]) => {
const options = args[0] || {};
return new Promise((resolve, reject) => {
// 调用原生方法
window.Capacitor.nativeCallback(
this.pluginName,
property,
options,
(result: any) => {
if (result.success) {
resolve(result.data);
} else {
reject(new Error(result.error?.message || 'Unknown error'));
}
}
);
});
};
}
}
// 创建插件实例
function createPlugin<T>(pluginName: string): T {
return new Proxy({}, new PluginProxy(pluginName)) as T;
}
5.3 事件处理 #
typescript
// 事件管理器
class EventManager {
private listeners = new Map<string, Set<Function>>();
// 添加监听器
addListener(eventName: string, callback: Function): () => void {
if (!this.listeners.has(eventName)) {
this.listeners.set(eventName, new Set());
}
this.listeners.get(eventName)!.add(callback);
// 返回移除函数
return () => {
this.listeners.get(eventName)?.delete(callback);
};
}
// 触发事件
trigger(eventName: string, data: any): void {
const callbacks = this.listeners.get(eventName);
callbacks?.forEach(callback => {
try {
callback(data);
} catch (error) {
console.error(`Event callback error: ${error}`);
}
});
}
}
// 全局事件处理
window.Capacitor.triggerEvent = (pluginName: string, eventName: string, data: any) => {
const fullEventName = `${pluginName}:${eventName}`;
eventManager.trigger(fullEventName, data);
};
六、数据传输 #
6.1 基本类型映射 #
| JavaScript | iOS (Swift) | Android (Java) |
|---|---|---|
| string | String | String |
| number | Double/Int | Double/Integer |
| boolean | Bool | Boolean |
| null | nil | null |
| undefined | nil | null |
| Array | [Any] | JSONArray |
| Object | [String: Any] | JSONObject |
6.2 特殊类型处理 #
typescript
// Base64数据传输
function toBase64(data: ArrayBuffer): string {
const bytes = new Uint8Array(data);
let binary = '';
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
function fromBase64(base64: string): ArrayBuffer {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes.buffer;
}
// 使用示例
const imageData = await Camera.getPhoto({ resultType: 'base64' });
const arrayBuffer = fromBase64(imageData.base64String);
6.3 大数据传输 #
typescript
// 分块传输大数据
class ChunkedTransfer {
private chunkSize = 1024 * 1024; // 1MB
async sendLargeData(pluginName: string, methodName: string, data: ArrayBuffer) {
const totalChunks = Math.ceil(data.byteLength / this.chunkSize);
const transferId = generateUUID();
// 发送分块
for (let i = 0; i < totalChunks; i++) {
const start = i * this.chunkSize;
const end = Math.min(start + this.chunkSize, data.byteLength);
const chunk = data.slice(start, end);
await window.Capacitor.nativePromise(pluginName, methodName, {
transferId,
chunkIndex: i,
totalChunks,
data: toBase64(chunk)
});
}
}
}
七、错误处理 #
7.1 错误类型 #
typescript
// Capacitor错误类
class CapacitorException extends Error {
constructor(
message: string,
public code?: string,
public data?: any
) {
super(message);
this.name = 'CapacitorException';
}
}
// 常见错误码
enum CapacitorErrorCode {
// 插件错误
PLUGIN_NOT_FOUND = 'PLUGIN_NOT_FOUND',
METHOD_NOT_FOUND = 'METHOD_NOT_FOUND',
// 权限错误
PERMISSION_DENIED = 'PERMISSION_DENIED',
// 参数错误
INVALID_ARGUMENT = 'INVALID_ARGUMENT',
// 系统错误
UNAVAILABLE = 'UNAVAILABLE',
TIMEOUT = 'TIMEOUT'
}
7.2 错误传递 #
typescript
// JavaScript错误处理
async function safeNativeCall<T>(
pluginName: string,
methodName: string,
options: any
): Promise<T> {
try {
const result = await window.Capacitor.nativePromise(
pluginName,
methodName,
options
);
if (!result.success) {
throw new CapacitorException(
result.error.message,
result.error.code,
result.error.data
);
}
return result.data;
} catch (error) {
// 转换原生错误
if (error instanceof CapacitorException) {
throw error;
}
throw new CapacitorException(
error.message || 'Unknown error',
CapacitorErrorCode.UNAVAILABLE
);
}
}
7.3 原生错误处理 #
swift
// iOS错误处理
class CapacitorError: Error {
let code: String
let message: String
let data: [String: Any]?
init(code: String, message: String, data: [String: Any]? = nil) {
self.code = code
self.message = message
self.data = data
}
func toJSON() -> [String: Any] {
var json: [String: Any] = [
"code": code,
"message": message
]
if let data = data {
json["data"] = data
}
return json
}
}
// 使用示例
func execute(methodName: String, options: [String: Any]) throws -> [String: Any] {
switch methodName {
case "getPhoto":
guard options["quality"] != nil else {
throw CapacitorError(
code: "INVALID_ARGUMENT",
message: "quality is required"
)
}
return try getPhoto(options)
default:
throw CapacitorError(
code: "METHOD_NOT_FOUND",
message: "Method \(methodName) not found"
)
}
}
八、性能优化 #
8.1 减少桥接调用 #
typescript
// 批量操作
class BatchOperation {
private operations: Array<() => Promise<any>> = [];
add(operation: () => Promise<any>) {
this.operations.push(operation);
}
async execute(): Promise<any[]> {
return Promise.all(this.operations.map(op => op()));
}
}
// 使用示例
const batch = new BatchOperation();
batch.add(() => Storage.set({ key: 'name', value: 'John' }));
batch.add(() => Storage.set({ key: 'age', value: '30' }));
batch.add(() => Storage.set({ key: 'city', value: 'New York' }));
await batch.execute();
8.2 缓存机制 #
typescript
// 桥接调用缓存
class BridgeCache {
private cache = new Map<string, { data: any; timestamp: number }>();
private ttl = 60000; // 1分钟
async get<T>(
pluginName: string,
methodName: string,
options: any,
fetcher: () => Promise<T>
): Promise<T> {
const key = `${pluginName}:${methodName}:${JSON.stringify(options)}`;
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.data;
}
const data = await fetcher();
this.cache.set(key, { data, timestamp: Date.now() });
return data;
}
}
九、调试技巧 #
9.1 桥接日志 #
typescript
// 启用桥接调试
if (import.meta.env.DEV) {
const originalNativeCallback = window.Capacitor.nativeCallback;
window.Capacitor.nativeCallback = function(...args) {
console.log('[Bridge] Call:', args);
return originalNativeCallback.apply(this, args);
};
const originalTriggerEvent = window.Capacitor.triggerEvent;
window.Capacitor.triggerEvent = function(...args) {
console.log('[Bridge] Event:', args);
return originalTriggerEvent.apply(this, args);
};
}
9.2 性能监控 #
typescript
// 桥接性能监控
class BridgeProfiler {
private metrics = new Map<string, number[]>();
async profile<T>(
pluginName: string,
methodName: string,
call: () => Promise<T>
): Promise<T> {
const key = `${pluginName}.${methodName}`;
const start = performance.now();
try {
return await call();
} finally {
const duration = performance.now() - start;
if (!this.metrics.has(key)) {
this.metrics.set(key, []);
}
this.metrics.get(key)!.push(duration);
console.log(`[Bridge] ${key} took ${duration.toFixed(2)}ms`);
}
}
getStats(pluginName: string, methodName: string) {
const key = `${pluginName}.${methodName}`;
const durations = this.metrics.get(key) || [];
return {
count: durations.length,
avg: durations.reduce((a, b) => a + b, 0) / durations.length,
max: Math.max(...durations),
min: Math.min(...durations)
};
}
}
十、总结 #
10.1 桥接核心 #
| 要点 | 说明 |
|---|---|
| 通信方向 | 双向:JS ↔ Native |
| 消息格式 | JSON序列化 |
| 调用方式 | Promise异步 |
| 事件机制 | 观察者模式 |
10.2 最佳实践 #
- 减少不必要的桥接调用
- 使用批量操作合并调用
- 合理使用缓存
- 做好错误处理
10.3 下一步 #
了解桥接机制后,让我们学习 配置系统!
最后更新:2026-03-28