
Why Boson? Because it's not an Electron! And much easier than that =)
Also, this repository contains included high level PHP bindings for Saucer v6.0.
- Simple Example
- Requirements
- Installation
- Usage
- Application
- Window
- WebView
- Events
- Misc
use Boson\Application;
$app = new Application();
$app->webview->html = <<<'HTML'
<button onclick="foo('HELLO');">Hello</button>
HTML;
$app->webview->bind('foo', function (string $message): void {
var_dump($message);
});
$app->run();
- PHP ^8.4
- ext-ffi
Platform | X86 | AMD64 | ARM64 | Technologies |
---|---|---|---|---|
Windows | âś“ | âś“ | âś– | Windows API, WebView2 |
Linux | âś“ | âś“ | âś“ | GTK, WebKitGTK, Qt5/Qt6 |
macOS | âś“ | âś“ | âś“ | Cocoa, WebKit |
At the moment, all binaries are supplied together with the library. In future versions, a separate platform-dependent installation of assemblies from the GitHub Actions CI is planned.
Requires Windows 10 or higher.
End-users must have the WebView2 runtime installed on their system for any version of Windows before Windows 11.
It appears that no additional dependencies are required.
Supports both WebKitGTK and Qt5 as well as Qt6 on Linux.
The default backend is WebKitGtk:
- Debian:
apt install libgtk-4-1 libwebkitgtk-6.0-4
- Fedora:
dnf install gtk4 webkitgtk6.0
- FreeBSD:
pkg install webkit2-gtk4
You can download other assemblies separately from GitHub Actions. Automatic detection and installation of dependencies is not supported yet.
Boson package is available as Composer repository and can be installed using the following command in a root of your project:
$ composer require boson-php/runtime
This documentation corresponds to the latest release (see https://github.com/BosonPHP/runtime/tags). Behavior and code in the
master
branch may differ from what is shown below.
An application configuration is built on the basis of the DTO hierarchy, which reflects the application hierarchy.
ApplicationCreateInfo
// ... application configs
window: WindowCreateInfo
// ... window configs
webview: WebViewCreateInfo
// ... webview configs
In the PHP code it might look like this:
use Boson\ApplicationCreateInfo;
use Boson\WebView\WebViewCreateInfo;
use Boson\Window\WindowCreateInfo;
$config = new ApplicationCreateInfo(
debug: false,
window: new WindowCreateInfo(
title: 'Hello World!',
width: 640,
height: 480,
webview: new WebViewCreateInfo(
html: '<h1>Hello!</h1>',
contextMenu: false,
),
),
);
The configuration is passed to the application itself and can be optional.
use Boson\Application;
use Boson\ApplicationCreateInfo;
// Create an application
$app = new Application();
// Create an application with configuration
$appWithConfig = new Application(new ApplicationCreateInfo(
debug: false,
));
To start the application, you must call the run()
method.
$app = new Boson\Application();
$app->run();
Launching an application blocks the execution thread, meaning that no further code will be executed until the application is stopped.
$app = new Boson\Application();
$app->run();
echo 'This code DOES NOT execute until the application is stopped!';
In most cases, explicit
run()
invocation is not required, as the autorun option is enabled by default.
By default, the application is automatically launched after creation (delayed,
not immediately), even if you do not call the run()
method yourself.
This is because the autostart option is enabled (defined as true
) by default.
If you do not need the application to start automatically,
then this option should be disabled (set to false
).
use Boson\Application;
use Boson\ApplicationCreateInfo;
$app = new Application(new ApplicationCreateInfo(
autorun: false,
));
To stop the application, you should call the quit()
method.
$app = new Boson\Application();
/// ... do smth
$app->quit();
Since exit (according to the logic of work) occurs after the application is launched, and launching blocks the thread, it makes sense for the application to terminate after any event is fired.
use Boson\Application;
use Boson\Window\Event\WindowMinimized;
$app = new Application();
// The application will exit after minimizing.
$app->events->addEventListener(WindowMinimized::class, function () use ($app) {
$app->quit();
});
It is also worth keeping in mind that the application may close
automatically after ALL windows are closed. To disable this behavior,
you should set the quitOnClose
application config.
use Boson\Application;
use Boson\ApplicationCreateInfo;
$appWithConfig = new Application(new ApplicationCreateInfo(
// Disables app quit when all windows are has been closed
quitOnClose: false,
));
To get or update the title, you should change the $title
property
$app = new Boson\Application();
$app->webview->title = 'New Title';
echo 'Current Title: ' . $app->webview->title;
Or set title from configuration
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
title: 'New Title',
),
),
);
To obtain window size, use the $size
property.
$app = new Boson\Application();
echo $app->window->size; // Size(640 Ă— 480)
echo $app->window->size->width; // int(640)
echo $app->window->size->height; // int(480)
You also may set default window size via configuration.
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
width: 640,
height: 480,
),
),
);
To change the size, use the $size
property.
$app = new Boson\Application();
// Update window size to 640Ă—480
$app->window->size->update(640, 480);
// Or set the dimensions explicitly using new Size object
$app->window->size = new \Boson\Window\Size(640, 480);
In addition, each window size can also be changed separately.
$app = new Boson\Application();
$app->window->size->width = 640;
$app->window->size->height = 480;
To disable the ability to resize a window, pass the appropriate
resizable
window configuration option.
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
resizable: false,
),
),
);
To specify the maximum window size, use the $max
property. The behavior of
the property is identical to the $size
property described above.
$app = new Boson\Application();
echo $app->window->max; // Will display the maximum allowed window size
$app->window->max->update(1024, 768);
To specify the maximum window size, use the $min
property. The behavior of
the property is identical to the $size
property described above.
$app = new Boson\Application();
echo $app->window->min; // Will display the minimum allowed window size
$app->window->min->update(1024, 768);
You can change the standard window`s title bar, minimize, maximize and close
buttons via Boson\Window\WindowDecoration
enum.
$app = new Boson\Application();
// Sets default window behaviour
$app->window->decoration = Boson\Window\WindowDecoration::Default;
// Enable dark mode
$app->window->decoration = Boson\Window\WindowDecoration::DarkMode;
// Disable window decorations
$app->window->decoration = Boson\Window\WindowDecoration::Frameless;
// Disable decorations and make window transparent
$app->window->decoration = Boson\Window\WindowDecoration::Transparent;
Or via configuration options.
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
decoration: Boson\Window\WindowDecoration::Frameless,
),
),
);
Enum Case | Controls | Dark Mode | Transparency |
---|---|---|---|
Default | âś“ | âś— | âś— |
DarkMode | âś“ | âś“ | âś— |
Frameless | âś— | âś— | âś— |
Transparent | âś— | âś— | âś“ |
Please note that by disabling the standard title bar and buttons you will not be able to control the window (moving and resizing), but you can implement this behavior yourself using HTML attributes.
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
decorated: false,
webview: new \Boson\WebView\WebViewCreateInfo(
html: <<<'HTML'
<div data-webview-drag>
By dragging this element you can move the window
<button data-webview-ignore>non-draggable button</button>
</div>
<hr />
<div data-webview-resize="br">
By dragging this element you can resize the window
</div>
HTML
)
),
),
);
- The
data-webview-drag
attribute defines the area by dragging which you can move the window. - The
data-webview-resize
attribute defines the area by dragging which you can resize the window.- An
t
attribute's value means the ability to resize vertically, top of the window. - An
b
attribute's value means the ability to resize vertically, bottom of the window. - An
r
attribute's value means the ability to resize horizontally, right of the window. - An
l
attribute's value means the ability to resize horizontally, left of the window. - Using combinations such as
tl
,tr
,bl
andbr
allows you to specify simultaneous resizing of the window vertically and horizontally.
- An
- The
data-webview-ignore
attribute disables drag or resize behaviour for the element and children.
To set the content, you should use the $html
property
$app = new Boson\Application();
$app->webview->html = '<button>Do Not Click Me!</button>';
Or set html content from configuration
$app = new Boson\Application(
window: new Boson\Window\WindowCreateInfo(
webview: new Boson\WebView\WebViewCreateInfo(
html: '<button>Do Not Click Me!</button>',
),
),
);
Please note that reading this property is NOT possible. If you need to read the contents, use the data retrieval method.
use Boson\Application;
use Boson\WebView\Event\WebViewDomReady;
$app = new Application();
$app->webview->html = '<button>Do Not Click Me!</button>';
$app->events->addEventListener(WebViewDomReady::class, function () use ($app) {
$html = $app->webview->request('document.body.innerHTML');
var_dump($html);
});
To load content from the URL, you should use the $url
property
$app = new Boson\Application();
$app->webview->url = 'https://github.com/BosonPHP';
Or set URL from configuration
$app = new Boson\Application(
window: new Boson\Window\WindowCreateInfo(
webview: new Boson\WebView\URLWebViewCreateInfo(
url: 'https://github.com/BosonPHP',
),
),
);
In addition to navigation to the specified URL address, it is also possible to obtain information about the URL.
$app = new Boson\Application();
$app->webview->url = 'https://github.com/BosonPHP';
echo 'URL: ' . $app->webview->url . "\n"; // string("about:blank")
$app->events->addEventListener(WebViewNavigated::class, function () use ($app) {
echo 'URL: ' . $app->webview->url . "\n"; // string("https://github.com/BosonPHP")
});
In addition, you can get separate information about the URL parts.
$app = new Boson\Application();
$app->webview->url = 'https://github.com/BosonPHP';
$app->events->addEventListener(WebViewNavigated::class, function () use ($app) {
echo 'Scheme: ' . $app->webview->url->scheme . "\n"; // string("https")
echo 'Host: ' . $app->webview->url->host . "\n"; // string("github.com")
echo 'Path: ' . $app->webview->url->path . "\n"; // string("/BosonPHP")
});
You can register custom scheme/protocols and intercept standard one.
To register global application middleware you may define list of middleware for the given protocol.
use Boson\Application;
use Boson\ApplicationCreateInfo;
use Boson\Http\Middleware\HandlerInterface;
use Boson\Http\Middleware\MiddlewareInterface;
use Boson\Http\RequestInterface;
use Boson\Http\Response;
$middleware = new class implements MiddlewareInterface {
public function handle(RequestInterface $request, HandlerInterface $handler): Response
{
return new Response('<h1>Hello from "' . $request->url . '"!</h1>');
}
};
$app = new Application(new ApplicationCreateInfo(
// List of middleware for "https" protocol
schemes: [ 'https' => [$middleware] ],
));
$app->webview->url = 'https://hello.world/';
To register middleware for a specific window (webview) for a specified protocol, you should use direct addition of middleware to the middleware list for webview.
use Boson\Application;
use Boson\ApplicationCreateInfo;
use Boson\Http\Middleware\HandlerInterface;
use Boson\Http\Middleware\MiddlewareInterface;
use Boson\Http\RequestInterface;
use Boson\Http\Response;
$app = new Application(new ApplicationCreateInfo(
// Adding "https" protocol interception support
schemes: [ 'https' ],
));
// Select pipeline for "https" protocol
$pipeline = $app->webview->schemes->find('https');
// Add middleware for "https" protocol for main window
$pipeline?->append(new class implements MiddlewareInterface {
public function handle(RequestInterface $request, HandlerInterface $handler): Response
{
return new Response('<h1>Hello from "' . $request->url . '"!</h1>');
}
});
$app->webview->url = 'https://hello.world/';
You can execute arbitrary code directly on current WebView
$app = new Boson\Application();
// Load empty page
$app->webview->html = '';
// Evaluate JS code on this page
$app->webview->eval('document.write("Hello World!")');
You can register a JavaScript code that will be applied to any page.
$app = new Boson\Application();
$app->webview->scripts->add(<<<'JS'
alert('hello');
JS);
Or set scripts from configuration
$app = new Boson\Application(
window: new Boson\Window\WindowCreateInfo(
webview: new Boson\WebView\WebViewCreateInfo(
scripts: [<<<'JS'
alert('hello');
JS],
),
),
);
It is worth noting that adding code is available in several options.
$app = new Boson\Application();
// "This code will be executed BEFORE the page loads: undefined"
$app->webview->scripts->preload(<<<'JS'
console.log('This code will be executed BEFORE the page loads: ' + document?.body?.innerHTML);
JS);
// "This code will be executed AFTER the page loads: <b>hello</b>"
$app->webview->scripts->add(<<<'JS'
console.log('This code will be executed AFTER the page loads: ' + document?.body?.innerHTML);
JS);
$app->webview->html = '<b>hello</b>';
You can create a function that can be called directly from WebView
$app = new Boson\Application();
$app->webview->bind('foo', function () {
var_dump('Executed!');
});
Or set functions list from configuration
$app = new Boson\Application(
window: new Boson\Window\WindowCreateInfo(
webview: new Boson\WebView\WebViewCreateInfo(
functions: ['foo' => function () {
var_dump('Executed!');
}],
),
),
);
You can directly get data from WebView context.
$app = new Boson\Application();
$app->events->addEventListener(WebViewDomReady::class, function () use ($app) {
var_dump($app->webview->request('document.location'));
// array:10 [
// "ancestorOrigins" => []
// "href" => "https://nesk.me/"
// "origin" => "https://nesk.me"
// "protocol" => "https:"
// "host" => "nesk.me"
// "hostname" => "nesk.me"
// "port" => ""
// "pathname" => "/"
// "search" => ""
// "hash" => ""
// ]
});
$app->webview->url = 'https://nesk.me';
Please note that the request CAN NOT be processed if the application is not running.
$app = new Boson\Application();
var_dump($app->webview->request('document.location'));
//
// Uncaught Boson\WebView\Requests\Exception\UnprocessableRequestException:
// Request "document.location" could not be processed
// because application is not running
//
Any event is a fact. Events can not be changed or rejected. Unlike events, an intent is an attempt by the application or any of its components to do something. Any intent can be rejected or modified.
To subscribe to events and intents, the $events
field is used.
use Boson\WebView\Event\WebViewNavigating;
use Boson\WebView\Event\WebViewNavigated;
$app = new Boson\Application();
$app->events->addEventListener(WebViewNavigating::class, function (WebViewNavigating $intention): void {
echo 'Try to move on URL: ' . $intention->url . "\n";
// Randomly block navigating to another URL
if (\random_int(0, 1)) {
$intention->cancel();
}
});
$app->events->addEventListener(WebViewNavigated::class, function (WebViewNavigated $event): void {
echo 'Navigated to URL: ' . $event->url . "\n";
});
$app->webview->url = 'https://nesk.me';
To enable debug mode, you should define the debug: ?bool
argument of the Application
instance.
$app = new Boson\Application(
// true - enable debug mode
// false - disable debug mode
// null - autodetect debug mode
debug: true,
);
To define binary, you should define the library: ?non-empty-string
argument of the Application
instance.
$app = new Boson\Application(
// string - defines pathname to the library
// null - autodetect library
library: __DIR__ . '/path/to/custom-webview.so',
);
Any questions left? You can ask them in the chat t.me/boson_php
!