Files
openclaw/apps/shared/OpenClawKit/Sources/OpenClawKit/WebViewJavaScriptSupport.swift
Peter Steinberger c6dc5bc764 fix(canvas): hosted pages fail on macOS with scoped Gateway auth (#105336)
* fix(canvas): harden hosted Canvas on macOS

Resolve Gateway-hosted Canvas and A2UI targets through refreshed node capabilities, keep bridge and live-reload behavior correct, and restrict native action dispatch to the exact trusted main-frame document.

Preserve scalar evaluation results, secure action IDs, and hidden state-directory watching.

Co-authored-by: GuoJiaming <804436395@qq.com>
Co-authored-by: Lucenx9 <185146821+Lucenx9@users.noreply.github.com>
Co-authored-by: zeng-weihan <ceng.weihan@xydigit.com>

* chore(canvas): defer release note

* chore(canvas): refresh native i18n inventory

* refactor(canvas): isolate hosted surface resolution

---------

Co-authored-by: GuoJiaming <804436395@qq.com>
Co-authored-by: Lucenx9 <185146821+Lucenx9@users.noreply.github.com>
Co-authored-by: zeng-weihan <ceng.weihan@xydigit.com>
2026-07-12 13:02:27 +01:00

69 lines
2.2 KiB
Swift

import CoreFoundation
import Foundation
#if canImport(WebKit)
import WebKit
public enum WebViewJavaScriptSupport {
@MainActor
public static func applyDebugStatus(
webView: WKWebView,
enabled: Bool,
title: String?,
subtitle: String?)
{
let js = """
(() => {
try {
const api = globalThis.__openclaw;
if (!api) return;
if (typeof api.setDebugStatusEnabled === 'function') {
api.setDebugStatusEnabled(\(enabled ? "true" : "false"));
}
if (!\(enabled ? "true" : "false")) return;
if (typeof api.setStatus === 'function') {
api.setStatus(\(self.jsValue(title)), \(self.jsValue(subtitle)));
}
} catch (_) {}
})()
"""
webView.evaluateJavaScript(js) { _, _ in }
}
@MainActor
public static func evaluateToString(webView: WKWebView, javaScript: String) async throws -> String {
try await withCheckedThrowingContinuation { cont in
webView.evaluateJavaScript(javaScript) { result, error in
if let error {
cont.resume(throwing: error)
return
}
cont.resume(returning: self.evaluationResultString(result))
}
}
}
static func evaluationResultString(_ result: Any?) -> String {
guard let result else { return "" }
// WebKit bridges JavaScript booleans and numbers through NSNumber.
// Preserve the Boolean contract before generic numeric description.
if let number = result as? NSNumber,
CFGetTypeID(number) == CFBooleanGetTypeID()
{
return number.boolValue ? "true" : "false"
}
return String(describing: result)
}
public static func jsValue(_ value: String?) -> String {
guard let value else { return "null" }
if let data = try? JSONSerialization.data(withJSONObject: [value]),
let encoded = String(data: data, encoding: .utf8),
encoded.count >= 2
{
return String(encoded.dropFirst().dropLast())
}
return "null"
}
}
#endif