An open API service indexing awesome lists of open source software.

https://github.com/bosonphp/runtime

PHP WebView runtime
https://github.com/bosonphp/runtime

bridge browser html interface native php php84 render webview

Last synced: 2 days ago
JSON representation

PHP WebView runtime

Awesome Lists containing this project

README

        



---


PHP 8.4+
Latest Stable Version
Latest Unstable Version
License MIT
MetaStorm








Telegram

Why Boson? Because it's not an [Electron](https://www.electronjs.org)!
And much easier than that =)

> Also, this repository contains included high level PHP bindings
> [for Saucer v6.0](https://github.com/saucer/saucer).

- [Simple Example](#simple-example)
- [Requirements](#requirements)
- [Windows](#windows)
- [Linux & BSD](#linux-and-bsd)
- [MacOS](#macos)
- [Installation](#installation)
- [Usage](#usage)
- **Application**
- [Configuration](#application-configuration)
- [Launching](#application-launching)
- [Autorun](#application-autorun)
- [Quit](#application-quit)
- **Window**
- [Window Title](#window-title)
- [Window Size](#window-size)
- [Window Resizing](#window-resizing)
- [Window Max Size](#window-max-size)
- [Window Min Size](#window-min-size)
- [Window Decorations](#window-decorations)
- **WebView**
- [HTML Content](#webview-html-content)
- [Navigation to URL](#webview-url-navigation)
- [Navigation URL info](#webview-url-info)
- [Custom Protocols](#webview-custom-protocols)
- **JavaScript**
- [Scripts](#webview-scripts)
- [Code Evaluation](#webview-code-evaluation)
- [Creating Functions](#webview-function-bindings)
- [Code Requests](#webview-requests)
- **Events**
- [Events and Intentions](#events-and-intentions)
- **Misc**
- [Debug Mode](#debug-mode)
- [Custom Library](#custom-library)

## Simple Example

```php
use Boson\Application;

$app = new Application();

$app->webview->html = <<<'HTML'
Hello
HTML;

$app->webview->bind('foo', function (string $message): void {
var_dump($message);
});

$app->run();
```

## Requirements

- PHP ^8.4
- ext-ffi

| Platform | X86 | AMD64 | ARM64 | Technologies |
|----------|-----|-------|-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Windows | ✓ | ✓ | ✖ | [Windows API](https://docs.microsoft.com/en-us/windows/win32/apiindex/windows-api-list), [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) |
| Linux | ✓ | ✓ | ✓ | [GTK](https://gtk.org/), [WebKitGTK](https://webkitgtk.org/), [Qt5/Qt6](https://github.com/qt/qtwebkit) |
| macOS | ✓ | ✓ | ✓ | Cocoa, [WebKit](https://webkit.org/) |

> At the moment, all binaries are supplied [together with the library](./bin).
> In future versions, a separate platform-dependent installation of
> assemblies from [the GitHub Actions CI](https://github.com/BosonPHP/frontend/actions/workflows/build.yml)
> is planned.

### Windows

Requires Windows 10 or higher.

End-users must have the [WebView2 runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)
installed on their system for any version of Windows before Windows 11.

### MacOS

It appears that no additional dependencies are required.

### Linux and BSD

Supports both [WebKitGTK](https://webkitgtk.org/) and [Qt5](https://github.com/qt/qtwebkit)
as well as [Qt6](https://github.com/qt/qtwebkit) 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](https://github.com/BosonPHP/runtime/actions/workflows/build.yml).
Automatic detection and installation of dependencies is not supported yet.

## Installation

Boson package is available as Composer repository and can
be installed using the following command in a root of your project:

```bash
$ composer require boson-php/runtime
```

## Usage

> 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.

## Application Configuration

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:

```php
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: '

Hello!

',
contextMenu: false,
),
),
);
```

The configuration is passed to the application itself
and can be optional.

```php
use Boson\Application;
use Boson\ApplicationCreateInfo;

// Create an application
$app = new Application();

// Create an application with configuration
$appWithConfig = new Application(new ApplicationCreateInfo(
debug: false,
));
```

## Application Launching

To start the application, you must call the `run()` method.

```php
$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.

```php
$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](#application-autorun) option is enabled by default.

## Application Autorun

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`).

```php
use Boson\Application;
use Boson\ApplicationCreateInfo;

$app = new Application(new ApplicationCreateInfo(
autorun: false,
));
```

## Application Quit

To stop the application, you should call the `quit()` method.

```php
$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.

```php
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.

```php
use Boson\Application;
use Boson\ApplicationCreateInfo;

$appWithConfig = new Application(new ApplicationCreateInfo(
// Disables app quit when all windows are has been closed
quitOnClose: false,
));
```

### Window Title

To get or update the title, you should change the `$title` property

```php
$app = new Boson\Application();

$app->webview->title = 'New Title';

echo 'Current Title: ' . $app->webview->title;
```

Or set title from configuration

```php
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
title: 'New Title',
),
),
);
```

### Window Size

To obtain window size, use the `$size` property.

```php
$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.

```php
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
width: 640,
height: 480,
),
),
);
```

### Window Resizing

To change the size, use the `$size` property.

```php
$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.

```php
$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.

```php
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
resizable: false,
),
),
);
```

### Window Max Size

To specify the maximum window size, use the `$max` property. The behavior of
the property is identical to the `$size` property [described above](#window-size).

```php
$app = new Boson\Application();

echo $app->window->max; // Will display the maximum allowed window size

$app->window->max->update(1024, 768);
```

### Window Min Size

To specify the maximum window size, use the `$min` property. The behavior of
the property is identical to the `$size` property [described above](#window-size).

```php
$app = new Boson\Application();

echo $app->window->min; // Will display the minimum allowed window size

$app->window->min->update(1024, 768);
```

### Window Decorations

You can change the standard window\`s title bar, minimize, maximize and close
buttons via `Boson\Window\WindowDecoration` enum.

```php
$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.

```php
$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.

```php
$app = new Boson\Application(
info: new \Boson\ApplicationCreateInfo(
window: new Boson\Window\WindowCreateInfo(
decorated: false,
webview: new \Boson\WebView\WebViewCreateInfo(
html: <<<'HTML'


By dragging this element you can move the window

non-draggable button







By dragging this element you can resize the window

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` and `br` allows you to specify
simultaneous resizing of the window vertically and horizontally.
- The `data-webview-ignore` attribute disables drag or resize behaviour for
the element and children.

### WebView HTML Content

To set the content, you should use the `$html` property

```php
$app = new Boson\Application();

$app->webview->html = 'Do Not Click Me!';
```

Or set html content from configuration

```php
$app = new Boson\Application(
window: new Boson\Window\WindowCreateInfo(
webview: new Boson\WebView\WebViewCreateInfo(
html: 'Do Not Click Me!',
),
),
);
```

Please note that reading this property is NOT possible. If you need to
read the contents, use the [data retrieval method](#code-requests).

```php
use Boson\Application;
use Boson\WebView\Event\WebViewDomReady;

$app = new Application();

$app->webview->html = 'Do Not Click Me!';

$app->events->addEventListener(WebViewDomReady::class, function () use ($app) {
$html = $app->webview->request('document.body.innerHTML');

var_dump($html);
});
```

### WebView URL Navigation

To load content from the URL, you should use the `$url` property

```php
$app = new Boson\Application();

$app->webview->url = 'https://github.com/BosonPHP';
```

Or set URL from configuration

```php
$app = new Boson\Application(
window: new Boson\Window\WindowCreateInfo(
webview: new Boson\WebView\URLWebViewCreateInfo(
url: 'https://github.com/BosonPHP',
),
),
);
```

### WebView URL Info

In addition to navigation to the specified URL address, it is also possible
to obtain information about the URL.

```php
$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.

```php
$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")
});
```

### WebView Custom Protocols

You can register custom scheme/protocols and intercept standard one.

To enable processing of specific protocols, you should specify
them in the list of schemes.

```php
$app = new Boson\Application(new Boson\ApplicationCreateInfo(
// List of handling "https" protocol
schemes: [ 'https' ],
));

$app->webview->url = 'https://hello.world/';
```

After enabling the interception of all the necessary protocols (in this
case, `https`), you can start catching the corresponding events of sending
requests to this protocol (to this scheme).

```php
use \Boson\WebView\Event\WebViewRequest;

$app = new Boson\Application(new Boson\ApplicationCreateInfo(
// List of middleware for "https" protocol
schemes: [ 'https' ],
));

$app->events->addEventListener(WebViewRequest::class, function (WebViewRequest $e) {
echo \sprintf("%s %s\r\n", $e->request->method, $e->request->url);
foreach ($e->request->headers as $header => $value) {
echo \sprintf("%s: %s\r\n", $header, $value);
}
echo \sprintf("\r\n\r\n%s", $e->request->body);

//
// Result may looks like:
//
// GET https://hello.world/
// accept: text/html,application/xhtml+xml,application/xml;q=0.9,etc...
// upgrade-insecure-requests: 1
// user-agent: Mozilla/5.0 etc...
// sec-ch-ua: "Microsoft Edge WebView2";v="135", etc...
// sec-ch-ua-mobile: ?0
// sec-ch-ua-platform: "Windows"
//
});

$app->webview->url = 'https://hello.world/';
```

In that case, if you need to block a request to a specified URL,
you can cancel it.

```php
$app->events->addEventListener(WebViewRequest::class, function (WebViewRequest $e) {
$e->cancel();
});
```

In addition to canceling a request, you can also simulate a
response from a resource.

```php
$app->events->addEventListener(WebViewRequest::class, function (WebViewRequest $e) {
$e->response = new \Boson\Http\Response(
body: 'Hello World!',
);
});
```

Or a more complex response example:

```php
$app->events->addEventListener(WebViewRequest::class, function (WebViewRequest $e) {
$e->response = new \Boson\Http\Response(
body: \json_encode(['error' => 'Something went wrong']),
headers: ['content-type' => 'application/json'],
status: \Boson\Http\StatusCode::NotFound,
);
});
```

### WebView Code Evaluation

You can execute arbitrary code directly on current WebView

```php
$app = new Boson\Application();

// Load empty page
$app->webview->html = '';
// Evaluate JS code on this page
$app->webview->eval('document.write("Hello World!")');
```

### WebView Scripts

You can register a JavaScript code that will be applied to any page.

```php
$app = new Boson\Application();

$app->webview->scripts->add(<<<'JS'
alert('hello');
JS);
```

Or set scripts from configuration

```php
$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.

```php
$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: hello"
$app->webview->scripts->add(<<<'JS'
console.log('This code will be executed AFTER the page loads: ' + document?.body?.innerHTML);
JS);

$app->webview->html = 'hello';
```

### WebView Function Bindings

You can create a function that can be called directly from WebView

```php
$app = new Boson\Application();

$app->webview->bind('foo', function () {
var_dump('Executed!');
});
```

Or set functions list from configuration

```php
$app = new Boson\Application(
window: new Boson\Window\WindowCreateInfo(
webview: new Boson\WebView\WebViewCreateInfo(
functions: ['foo' => function () {
var_dump('Executed!');
}],
),
),
);
```

### WebView Requests

You can directly get data from WebView context.

```php
$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.

```php
$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
//
```

### Events and Intentions

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.

```php
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';
```

### Debug Mode

To enable debug mode, you should define the `debug: ?bool`
argument of the `Application` instance.

```php
$app = new Boson\Application(
// true - enable debug mode
// false - disable debug mode
// null - autodetect debug mode
debug: true,
);
```

### Custom Library

To define binary, you should define the `library: ?non-empty-string`
argument of the `Application` instance.

```php
$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`](https://t.me/boson_php)!