[HTML5] Implement JavaScript PWA update callbacks.
Allows detecting when a new version of the progressive web app service worker is waiting (i.e. an update is pending), along a function to force the update and reload all clients.
This commit is contained in:
parent
afdfe7c03b
commit
4c23a902c1
@ -54,7 +54,29 @@
|
|||||||
Returns an interface to a JavaScript object that can be used by scripts. The [code]interface[/code] must be a valid property of the JavaScript [code]window[/code]. The callback must accept a single [Array] argument, which will contain the JavaScript [code]arguments[/code]. See [JavaScriptObject] for usage.
|
Returns an interface to a JavaScript object that can be used by scripts. The [code]interface[/code] must be a valid property of the JavaScript [code]window[/code]. The callback must accept a single [Array] argument, which will contain the JavaScript [code]arguments[/code]. See [JavaScriptObject] for usage.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="pwa_needs_update" qualifiers="const">
|
||||||
|
<return type="bool" />
|
||||||
|
<description>
|
||||||
|
Returns [code]true[/code] if a new version of the progressive web app is waiting to be activated.
|
||||||
|
[b]Note:[/b] Only relevant when exported as a Progressive Web App.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="pwa_update">
|
||||||
|
<return type="int" enum="Error" />
|
||||||
|
<description>
|
||||||
|
Performs the live update of the progressive web app. Forcing the new version to be installed and the page to be reloaded.
|
||||||
|
[b]Note:[/b] Your application will be [b]reloaded in all browser tabs[/b].
|
||||||
|
[b]Note:[/b] Only relevant when exported as a Progressive Web App and [method pwa_needs_update] returns [code]true[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
|
<signals>
|
||||||
|
<signal name="pwa_update_available">
|
||||||
|
<description>
|
||||||
|
Emitted when an update for this progressive web app has been detected but is waiting to be activated because a previous version is active. See [method pwa_update] to force the update to take place immediately.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
</signals>
|
||||||
<constants>
|
<constants>
|
||||||
</constants>
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
@ -71,6 +71,9 @@ void JavaScript::_bind_methods() {
|
|||||||
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScript::_create_object_bind, mi);
|
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScript::_create_object_bind, mi);
|
||||||
}
|
}
|
||||||
ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScript::download_buffer, DEFVAL("application/octet-stream"));
|
ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScript::download_buffer, DEFVAL("application/octet-stream"));
|
||||||
|
ClassDB::bind_method(D_METHOD("pwa_needs_update"), &JavaScript::pwa_needs_update);
|
||||||
|
ClassDB::bind_method(D_METHOD("pwa_update"), &JavaScript::pwa_update);
|
||||||
|
ADD_SIGNAL(MethodInfo("pwa_update_available"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
|
#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
|
||||||
@ -102,6 +105,12 @@ Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if !defined(JAVASCRIPT_ENABLED)
|
#if !defined(JAVASCRIPT_ENABLED)
|
||||||
|
bool JavaScript::pwa_needs_update() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Error JavaScript::pwa_update() {
|
||||||
|
return ERR_UNAVAILABLE;
|
||||||
|
}
|
||||||
void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
|
void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -59,6 +59,8 @@ public:
|
|||||||
Ref<JavaScriptObject> create_callback(Object *p_ref, const StringName &p_method);
|
Ref<JavaScriptObject> create_callback(Object *p_ref, const StringName &p_method);
|
||||||
Variant _create_object_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
|
Variant _create_object_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
|
||||||
void download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime = "application/octet-stream");
|
void download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime = "application/octet-stream");
|
||||||
|
bool pwa_needs_update() const;
|
||||||
|
Error pwa_update();
|
||||||
|
|
||||||
static JavaScript *get_singleton();
|
static JavaScript *get_singleton();
|
||||||
JavaScript();
|
JavaScript();
|
||||||
|
@ -49,6 +49,8 @@ extern void godot_js_os_fs_sync(void (*p_callback)());
|
|||||||
extern int godot_js_os_execute(const char *p_json);
|
extern int godot_js_os_execute(const char *p_json);
|
||||||
extern void godot_js_os_shell_open(const char *p_uri);
|
extern void godot_js_os_shell_open(const char *p_uri);
|
||||||
extern int godot_js_os_hw_concurrency_get();
|
extern int godot_js_os_hw_concurrency_get();
|
||||||
|
extern int godot_js_pwa_cb(void (*p_callback)());
|
||||||
|
extern int godot_js_pwa_update();
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
extern void godot_js_input_mouse_button_cb(int (*p_callback)(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers));
|
extern void godot_js_input_mouse_button_cb(int (*p_callback)(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers));
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "api/javascript_singleton.h"
|
#include "api/javascript_singleton.h"
|
||||||
#include "emscripten.h"
|
#include "emscripten.h"
|
||||||
|
#include "os_javascript.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime);
|
extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime);
|
||||||
@ -346,3 +347,10 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
|
|||||||
void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
|
void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
|
||||||
godot_js_os_download_buffer(p_arr.ptr(), p_arr.size(), p_name.utf8().get_data(), p_mime.utf8().get_data());
|
godot_js_os_download_buffer(p_arr.ptr(), p_arr.size(), p_name.utf8().get_data(), p_mime.utf8().get_data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JavaScript::pwa_needs_update() const {
|
||||||
|
return OS_JavaScript::get_singleton()->pwa_needs_update();
|
||||||
|
}
|
||||||
|
Error JavaScript::pwa_update() {
|
||||||
|
return OS_JavaScript::get_singleton()->pwa_update();
|
||||||
|
}
|
||||||
|
@ -368,3 +368,58 @@ const GodotEventListeners = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
mergeInto(LibraryManager.library, GodotEventListeners);
|
mergeInto(LibraryManager.library, GodotEventListeners);
|
||||||
|
|
||||||
|
const GodotPWA = {
|
||||||
|
|
||||||
|
$GodotPWA__deps: ['$GodotRuntime', '$GodotEventListeners'],
|
||||||
|
$GodotPWA: {
|
||||||
|
hasUpdate: false,
|
||||||
|
|
||||||
|
updateState: function (cb, reg) {
|
||||||
|
if (!reg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!reg.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (reg.waiting) {
|
||||||
|
GodotPWA.hasUpdate = true;
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
GodotEventListeners.add(reg, 'updatefound', function () {
|
||||||
|
const installing = reg.installing;
|
||||||
|
GodotEventListeners.add(installing, 'statechange', function () {
|
||||||
|
if (installing.state === 'installed') {
|
||||||
|
GodotPWA.hasUpdate = true;
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
godot_js_pwa_cb__sig: 'vi',
|
||||||
|
godot_js_pwa_cb: function (p_update_cb) {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
const cb = GodotRuntime.get_func(p_update_cb);
|
||||||
|
navigator.serviceWorker.getRegistration().then(GodotPWA.updateState.bind(null, cb));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
godot_js_pwa_update__sig: 'i',
|
||||||
|
godot_js_pwa_update: function () {
|
||||||
|
if ('serviceWorker' in navigator && GodotPWA.hasUpdate) {
|
||||||
|
navigator.serviceWorker.getRegistration().then(function (reg) {
|
||||||
|
if (!reg || !reg.waiting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reg.waiting.postMessage('update');
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
autoAddDeps(GodotPWA, '$GodotPWA');
|
||||||
|
mergeInto(LibraryManager.library, GodotPWA);
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include <png.h>
|
#include <png.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "api/javascript_singleton.h"
|
||||||
#include "dom_keys.inc"
|
#include "dom_keys.inc"
|
||||||
#include "godot_js.h"
|
#include "godot_js.h"
|
||||||
|
|
||||||
@ -1035,6 +1036,19 @@ void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OS_JavaScript::update_pwa_state_callback() {
|
||||||
|
if (OS_JavaScript::get_singleton()) {
|
||||||
|
OS_JavaScript::get_singleton()->pwa_is_waiting = true;
|
||||||
|
}
|
||||||
|
if (JavaScript::get_singleton()) {
|
||||||
|
JavaScript::get_singleton()->emit_signal("pwa_update_available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error OS_JavaScript::pwa_update() {
|
||||||
|
return godot_js_pwa_update() ? FAILED : OK;
|
||||||
|
}
|
||||||
|
|
||||||
bool OS_JavaScript::is_userfs_persistent() const {
|
bool OS_JavaScript::is_userfs_persistent() const {
|
||||||
return idb_available;
|
return idb_available;
|
||||||
}
|
}
|
||||||
@ -1072,6 +1086,8 @@ OS_JavaScript::OS_JavaScript() {
|
|||||||
idb_available = godot_js_os_fs_is_persistent() != 0;
|
idb_available = godot_js_os_fs_is_persistent() != 0;
|
||||||
idb_needs_sync = false;
|
idb_needs_sync = false;
|
||||||
idb_is_syncing = false;
|
idb_is_syncing = false;
|
||||||
|
pwa_is_waiting = false;
|
||||||
|
godot_js_pwa_cb(&OS_JavaScript::update_pwa_state_callback);
|
||||||
|
|
||||||
if (AudioDriverJavaScript::is_available()) {
|
if (AudioDriverJavaScript::is_available()) {
|
||||||
#ifdef NO_THREADS
|
#ifdef NO_THREADS
|
||||||
|
@ -78,6 +78,7 @@ private:
|
|||||||
bool idb_available;
|
bool idb_available;
|
||||||
bool idb_needs_sync;
|
bool idb_needs_sync;
|
||||||
bool idb_is_syncing;
|
bool idb_is_syncing;
|
||||||
|
bool pwa_is_waiting;
|
||||||
|
|
||||||
static void fullscreen_change_callback(int p_fullscreen);
|
static void fullscreen_change_callback(int p_fullscreen);
|
||||||
static int mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers);
|
static int mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers);
|
||||||
@ -98,6 +99,7 @@ private:
|
|||||||
static void send_notification_callback(int p_notification);
|
static void send_notification_callback(int p_notification);
|
||||||
static void fs_sync_callback();
|
static void fs_sync_callback();
|
||||||
static void update_clipboard_callback(const char *p_text);
|
static void update_clipboard_callback(const char *p_text);
|
||||||
|
static void update_pwa_state_callback();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resume_audio();
|
void resume_audio();
|
||||||
@ -116,6 +118,8 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
bool check_size_force_redraw();
|
bool check_size_force_redraw();
|
||||||
|
bool pwa_needs_update() const { return pwa_is_waiting; }
|
||||||
|
Error pwa_update();
|
||||||
|
|
||||||
// Override return type to make writing static callbacks less tedious.
|
// Override return type to make writing static callbacks less tedious.
|
||||||
static OS_JavaScript *get_singleton();
|
static OS_JavaScript *get_singleton();
|
||||||
|
Loading…
Reference in New Issue
Block a user