Skip to content

Commit 15164d9

Browse files
authored
feat(core): allow defining a custom invoke system (#2899)
1 parent dd1d2b6 commit 15164d9

11 files changed

Lines changed: 153 additions & 181 deletions

File tree

.changes/custom-invoke-system.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
Added an API to use a custom invoke system to receive and respond to commands (`Builder#invoke_system`).

core/tauri/scripts/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/tauri/scripts/core.js

Lines changed: 29 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5-
;(function () {
5+
;
6+
(function () {
67
function uid() {
78
const length = new Int8Array(1)
89
window.crypto.getRandomValues(length)
@@ -11,58 +12,6 @@
1112
return array.join('')
1213
}
1314

14-
function ownKeys(object, enumerableOnly) {
15-
var keys = Object.keys(object)
16-
if (Object.getOwnPropertySymbols) {
17-
var symbols = Object.getOwnPropertySymbols(object)
18-
if (enumerableOnly)
19-
symbols = symbols.filter(function (sym) {
20-
return Object.getOwnPropertyDescriptor(object, sym).enumerable
21-
})
22-
keys.push.apply(keys, symbols)
23-
}
24-
return keys
25-
}
26-
27-
function _objectSpread(target) {
28-
for (var i = 1; i < arguments.length; i++) {
29-
var source = arguments[i] != null ? arguments[i] : {}
30-
if (i % 2) {
31-
ownKeys(source, true).forEach(function (key) {
32-
_defineProperty(target, key, source[key])
33-
})
34-
} else if (Object.getOwnPropertyDescriptors) {
35-
Object.defineProperties(
36-
target,
37-
Object.getOwnPropertyDescriptors(source)
38-
)
39-
} else {
40-
ownKeys(source).forEach(function (key) {
41-
Object.defineProperty(
42-
target,
43-
key,
44-
Object.getOwnPropertyDescriptor(source, key)
45-
)
46-
})
47-
}
48-
}
49-
return target
50-
}
51-
52-
function _defineProperty(obj, key, value) {
53-
if (key in obj) {
54-
Object.defineProperty(obj, key, {
55-
value: value,
56-
enumerable: true,
57-
configurable: true,
58-
writable: true
59-
})
60-
} else {
61-
obj[key] = value
62-
}
63-
return obj
64-
}
65-
6615
if (!window.__TAURI__) {
6716
window.__TAURI__ = {}
6817
}
@@ -103,30 +52,24 @@
10352
return reject(new Error('Invalid argument type.'))
10453
}
10554

106-
if (window.rpc) {
107-
window.rpc.notify(
108-
cmd,
109-
_objectSpread(
110-
{
111-
callback: callback,
112-
error: error,
113-
__invokeKey: key || __TAURI_INVOKE_KEY__
114-
},
115-
args
116-
)
55+
if (window.__TAURI_POST_MESSAGE__) {
56+
window.__TAURI_POST_MESSAGE__(
57+
cmd, {
58+
...args,
59+
callback: callback,
60+
error: error,
61+
__invokeKey: key || __TAURI_INVOKE_KEY__
62+
}
11763
)
11864
} else {
11965
window.addEventListener('DOMContentLoaded', function () {
120-
window.rpc.notify(
121-
cmd,
122-
_objectSpread(
123-
{
124-
callback: callback,
125-
error: error,
126-
__invokeKey: key || __TAURI_INVOKE_KEY__
127-
},
128-
args
129-
)
66+
window.__TAURI_POST_MESSAGE__(
67+
cmd, {
68+
...args,
69+
callback: callback,
70+
error: error,
71+
__invokeKey: key || __TAURI_INVOKE_KEY__
72+
}
13073
)
13174
})
13275
}
@@ -147,8 +90,7 @@
14790
target.target === '_blank'
14891
) {
14992
window.__TAURI_INVOKE__(
150-
'tauri',
151-
{
93+
'tauri', {
15294
__tauriModule: 'Shell',
15395
message: {
15496
cmd: 'open',
@@ -188,8 +130,7 @@
188130
if (e.target.hasAttribute('data-tauri-drag-region') && e.buttons === 1) {
189131
// start dragging if the element has a `tauri-drag-region` data attribute and maximize on double-clicking it
190132
window.__TAURI_INVOKE__(
191-
'tauri',
192-
{
133+
'tauri', {
193134
__tauriModule: 'Window',
194135
message: {
195136
cmd: 'manage',
@@ -206,8 +147,7 @@
206147
})
207148

208149
window.__TAURI_INVOKE__(
209-
'tauri',
210-
{
150+
'tauri', {
211151
__tauriModule: 'Event',
212152
message: {
213153
cmd: 'listen',
@@ -233,8 +173,7 @@
233173
return Promise.resolve(window.Notification.permission === 'granted')
234174
}
235175
return window.__TAURI_INVOKE__(
236-
'tauri',
237-
{
176+
'tauri', {
238177
__tauriModule: 'Notification',
239178
message: {
240179
cmd: 'isNotificationPermissionGranted'
@@ -253,8 +192,7 @@
253192
function requestPermission() {
254193
return window
255194
.__TAURI_INVOKE__(
256-
'tauri',
257-
{
195+
'tauri', {
258196
__tauriModule: 'Notification',
259197
message: {
260198
cmd: 'requestNotificationPermission'
@@ -276,17 +214,13 @@
276214
isPermissionGranted().then(function (permission) {
277215
if (permission) {
278216
return window.__TAURI_INVOKE__(
279-
'tauri',
280-
{
217+
'tauri', {
281218
__tauriModule: 'Notification',
282219
message: {
283220
cmd: 'notification',
284-
options:
285-
typeof options === 'string'
286-
? {
287-
title: options
288-
}
289-
: options
221+
options: typeof options === 'string' ? {
222+
title: options
223+
} : options
290224
}
291225
},
292226
_KEY_VALUE_
@@ -329,8 +263,7 @@
329263

330264
window.alert = function (message) {
331265
window.__TAURI_INVOKE__(
332-
'tauri',
333-
{
266+
'tauri', {
334267
__tauriModule: 'Dialog',
335268
message: {
336269
cmd: 'messageDialog',
@@ -343,8 +276,7 @@
343276

344277
window.confirm = function (message) {
345278
return window.__TAURI_INVOKE__(
346-
'tauri',
347-
{
279+
'tauri', {
348280
__tauriModule: 'Dialog',
349281
message: {
350282
cmd: 'confirmDialog',
@@ -359,8 +291,7 @@
359291
if (navigator.userAgent.includes('Mac')) {
360292
window.print = function () {
361293
return window.__TAURI_INVOKE__(
362-
'tauri',
363-
{
294+
'tauri', {
364295
__tauriModule: 'Window',
365296
message: {
366297
cmd: 'manage',

core/tauri/src/app.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ pub(crate) mod tray;
77

88
use crate::{
99
command::{CommandArg, CommandItem},
10-
hooks::{InvokeHandler, OnPageLoad, PageLoadPayload, SetupHook},
10+
hooks::{
11+
window_invoke_responder, InvokeHandler, InvokeResponder, OnPageLoad, PageLoadPayload, SetupHook,
12+
},
1113
manager::{Asset, CustomProtocol, WindowManager},
1214
plugin::{Plugin, PluginStore},
1315
runtime::{
@@ -19,7 +21,7 @@ use crate::{
1921
sealed::{ManagerBase, RuntimeOrDispatch},
2022
utils::assets::Assets,
2123
utils::config::{Config, WindowUrl},
22-
Context, Invoke, InvokeError, Manager, StateManager, Window,
24+
Context, Invoke, InvokeError, InvokeResponse, Manager, StateManager, Window,
2325
};
2426

2527
use tauri_macros::default_runtime;
@@ -582,6 +584,12 @@ pub struct Builder<R: Runtime> {
582584
/// The JS message handler.
583585
invoke_handler: Box<InvokeHandler<R>>,
584586

587+
/// The JS message responder.
588+
invoke_responder: Arc<InvokeResponder<R>>,
589+
590+
/// The script that initializes the `window.__TAURI_POST_MESSAGE__` function.
591+
invoke_initialization_script: String,
592+
585593
/// The setup hook.
586594
setup: SetupHook<R>,
587595

@@ -624,6 +632,9 @@ impl<R: Runtime> Builder<R> {
624632
Self {
625633
setup: Box::new(|_| Ok(())),
626634
invoke_handler: Box::new(|_| ()),
635+
invoke_responder: Arc::new(window_invoke_responder),
636+
invoke_initialization_script:
637+
"Object.defineProperty(window, '__TAURI_POST_MESSAGE__', { value: (cmd, args) => window.rpc.notify(cmd, args) })".into(),
627638
on_page_load: Box::new(|_, _| ()),
628639
pending_windows: Default::default(),
629640
plugins: PluginStore::default(),
@@ -648,6 +659,21 @@ impl<R: Runtime> Builder<R> {
648659
self
649660
}
650661

662+
/// Defines a custom JS message system.
663+
///
664+
/// The `responder` is a function that will be called when a command has been executed and must send a response to the JS layer.
665+
///
666+
/// The `initialization_script` is a script that initializes `window.__TAURI_POST_MESSAGE__`.
667+
/// That function must take the `command: string` and `args: object` types and send a message to the backend.
668+
pub fn invoke_system<F>(mut self, initialization_script: String, responder: F) -> Self
669+
where
670+
F: Fn(Window<R>, InvokeResponse, String, String) + Send + Sync + 'static,
671+
{
672+
self.invoke_initialization_script = initialization_script;
673+
self.invoke_responder = Arc::new(responder);
674+
self
675+
}
676+
651677
/// Defines the setup hook.
652678
pub fn setup<F>(mut self, setup: F) -> Self
653679
where
@@ -905,6 +931,7 @@ impl<R: Runtime> Builder<R> {
905931
self.state,
906932
self.window_event_listeners,
907933
(self.menu, self.menu_event_listeners),
934+
(self.invoke_responder, self.invoke_initialization_script),
908935
);
909936

910937
// set up all the windows defined in the config

0 commit comments

Comments
 (0)