Direct native WebView embedding for MoonBit.
Dependencies
moon add Nanaloveyuki/moonview@0.1.0-beta.8import {
"Nanaloveyuki/moonview",
}| Platform | parent_handle passed to WebView::create |
|---|---|
| Windows | A caller-owned HWND on an STA UI thread |
| macOS | A caller-owned NSView* on the main thread |
| Linux | A caller-owned GtkFixed* on the GTK UI thread |
| OpenHarmony | An ArkUI-owned Web component identified by webTag |
let options = @moonview.WebViewOptions::new(
bounds=@moonview.Rect::new(x=0, y=0, width=800, height=600),
initial_url="https://example.com",
initialization_script="console.log('moonview initialized')",
on_event=event => match event {
@moonview.WebViewEvent::Ready => println("webview ready")
@moonview.WebViewEvent::CreationFailed(_error) => println("create failed")
@moonview.WebViewEvent::ProcessFailed(_error) => println("browser process failed")
_ => ()
},
on_navigation=_url => @moonview.NavigationDecision::Allow,
on_new_window=_url => @moonview.NewWindowDecision::Deny,
)
match @moonview.WebView::create(parent_handle, options) {
Ok(view) => ignore(view.set_visible(true))
Err(_error) => abort("WebView creation rejected")
}ignore(view.set_bounds(@moonview.Rect::new(x=0, y=0, width=1024, height=768)))
ignore(view.navigate("https://example.com/docs"))
ignore(view.destroy())let context = @moonview.WebContext::persistent(data_directory="F:/app-data/moonview")
match @moonview.WebView::create_in_context(context, parent_handle, options) {
Ok(view) => ignore(view.set_visible(true))
Err(_error) => abort("WebView creation rejected")
}let options = @moonview.OhosAttachOptions::new(
on_event=event => match event {
@moonview.WebViewEvent::Ready => println("ArkWeb controller attached")
_ => ()
},
)
match @moonview.WebView::attach_ohos("main-web", options) {
Ok(view) => {
ignore(view.reload())
// API 12 executes this without a ScriptResult callback.
ignore(view.eval("console.log('from MoonBit')", "startup"))
}
Err(_error) => abort("ArkWeb attach rejected")
}match event {
@moonview.WebViewEvent::PageMessage(message) => println("page: \{message}")
@moonview.WebViewEvent::ScriptResult(id, value) => println("\{id}: \{value}")
_ => ()
}
ignore(view.post_message("host-ready"))
ignore(view.eval("document.title", "document-title"))window.moonview.onmessage = event => {
console.log(event.data)
}let limits = @moonview.WebViewResourceLimits::new(
max_pending_commands=64,
max_pending_command_bytes=1024 * 1024,
max_protocol_request_body_bytes=1024 * 1024,
)
let options = @moonview.WebViewOptions::new(
bounds=@moonview.Rect::new(x=0, y=0, width=800, height=600),
resource_limits=limits,
)ignore(@moonview.register_custom_scheme("app"))
let response = @moonview.ProtocolResponse::new(
status=200,
headers=[@moonview.HttpHeader::new(name="Content-Type", value="text/html")],
body=b"<!doctype html><title>moonview</title>",
)
// In the WebView event callback:
// @moonview.WebViewEvent::ProtocolRequest(request) =>
// ignore(view.respond_protocol(request.id, response))match view.show_file_dialog(
@moonview.FileDialogOptions::new(
kind=@moonview.FileDialogKind::OpenFile,
title=Some("Open document"),
filters=[
@moonview.FileDialogFilter::new(
name="Text files",
extensions=["txt", "md"],
),
],
),
) {
Ok(@moonview.FileDialogResult::Cancelled) => ()
Ok(@moonview.FileDialogResult::Selected(paths)) => println(paths)
Err(error) => println(error)
}$env:MOONVIEW_FILE_DIALOG_SMOKE = "1"
moon run src/examples/windows_smokemoon fmt --check
moon check --target native
moon test --target native
node --test tests/build.test.js
.\scripts\test-windows.ps1
.\scripts\test-windows.ps1 -WebView2Sdk F:\path\to\Microsoft.Web.WebView2.1.0.xlet options = WebViewOptions::new(
bounds=Rect::new(x=0, y=0, width=800, height=600),
initial_html="<!doctype html><title>moonview</title>",
on_event=event => match event {
WebViewEvent::Ready => println("ready")
WebViewEvent::CreationFailed(_error) => println("failed")
WebViewEvent::ProcessFailed(_error) => println("browser process failed")
_ => ()
},
)
match WebView::create(parent_handle, options) {
Ok(view) => ignore(view.post_message("host-ready"))
Err(_error) => abort("create rejected")
}///|
let options = WebViewOptions::new(
bounds=Rect::new(x=0, y=0, width=800, height=600),
resource_limits=WebViewResourceLimits::new(
max_pending_commands=64,
max_pending_command_bytes=1024 * 1024,
max_protocol_request_body_bytes=1024 * 1024,
),
)let context = @moonview.WebContext::persistent(data_directory="F:/app-data/moonview")
match @moonview.WebView::create_in_context(context, parent_handle, options) {
Ok(view) => ignore(view.set_visible(true))
Err(_error) => abort("WebView creation rejected")
}let options = OhosAttachOptions::new(
on_event=event => match event {
WebViewEvent::Ready => println("ArkWeb attached")
_ => ()
},
)
match WebView::attach_ohos("main-web", options) {
Ok(view) => {
ignore(view.reload())
ignore(view.eval("console.log('moonview')", "startup"))
}
Err(_error) => abort("ArkWeb attach rejected")
}match view.show_file_dialog(
FileDialogOptions::new(
kind=FileDialogKind::OpenFile,
title=Some("Open document"),
filters=[
FileDialogFilter::new(
name="Text files",
extensions=["txt", "md"],
),
],
),
) {
Ok(FileDialogResult::Cancelled) => ()
Ok(FileDialogResult::Selected(paths)) => println(paths)
Err(error) => println(error)
}pub(all) struct FileDialogOptions {
kind : FileDialogKind
title : String?
filters : Array[FileDialogFilter]
default_name : String?
initial_directory : String?
} derive(Eq, Debug)fn FileDialogOptions::new(kind~ : FileDialogKind, title? : String?, filters? : Array[FileDialogFilter], default_name? : String?, initial_directory? : String?) -> FileDialogOptionspub(all) struct MediaPermissionRequest {
kind : MediaPermissionKind
origin : String
} derive(Eq, Debug)fn NavigationState::new(url? : String, can_go_back? : Bool, can_go_forward? : Bool) -> NavigationStatepub(all) struct ProtocolRequest {
id : String
scheme : String
http_method : String
uri : String
headers : Array[HttpHeader]
body : Bytes
} derive(Eq, Debug)pub(all) struct ProtocolResponse {
status : Int
headers : Array[HttpHeader]
body : Bytes
} derive(Eq, Debug)fn ProtocolResponse::new(status~ : Int, headers? : Array[HttpHeader], body? : Bytes) -> ProtocolResponsepub struct WebView {
// private fields
}fn WebView::attach_ohos(web_tag : String, options : OhosAttachOptions) -> Result[WebView, WebViewError]fn WebView::create(parent_handle : UInt64, options : WebViewOptions) -> Result[WebView, WebViewError]fn WebView::create_in_context(context : WebContext, parent_handle : UInt64, options : WebViewOptions) -> Result[WebView, WebViewError]fn WebView::eval(self : WebView, script : String, request_id : String) -> Result[Unit, WebViewError]fn WebView::respond_protocol(self : WebView, request_id : String, response : ProtocolResponse) -> Result[Unit, WebViewError]fn WebView::show_file_dialog(self : WebView, options : FileDialogOptions) -> Result[FileDialogResult, WebViewError]pub(all) enum WebViewEvent {
Ready
CreationFailed(WebViewError)
ProcessFailed(WebViewError)
PageMessage(String)
NavigationStarting(String)
SourceChanged(String)
NavigationCompleted(String)
NavigationFailed(String, WebViewError)
TitleChanged(String)
HistoryChanged(Bool, Bool)
ScriptResult(String, String)
ScriptFailed(String, WebViewError)
ProtocolRequest(ProtocolRequest)
ProtocolCancelled(String)
} derive(Eq, Debug)pub(all) struct WebViewOptions {
context : WebContext
bounds : Rect
resource_limits : WebViewResourceLimits
initial_url : String
initial_html : String
initialization_script : String
user_agent : String
visible : Bool
on_event : (WebViewEvent) -> Unit
on_navigation : (String) -> NavigationDecision
on_new_window : (String) -> NewWindowDecision
on_media_permission : (MediaPermissionRequest) -> MediaPermissionDecision
}fn WebViewOptions::new(bounds~ : Rect, context? : WebContext, resource_limits? : WebViewResourceLimits, initial_url? : String, initial_html? : String, initialization_script? : String, user_agent? : String, visible? : Bool, on_event? : (WebViewEvent) -> Unit, on_navigation? : (String) -> NavigationDecision, on_new_window? : (String) -> NewWindowDecision, on_media_permission? : (MediaPermissionRequest) -> MediaPermissionDecision) -> WebViewOptionsfn WebViewResourceLimits::new(max_pending_commands? : Int, max_pending_command_bytes? : Int, max_protocol_request_body_bytes? : Int) -> WebViewResourceLimitsfn available() -> BoolDirect native WebView embedding for MoonBit.
Dependencies