Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YouTube Music freezing the webviews #35

Open
Priyanshu-CODERX opened this issue Jan 2, 2025 · 20 comments
Open

YouTube Music freezing the webviews #35

Priyanshu-CODERX opened this issue Jan 2, 2025 · 20 comments

Comments

@Priyanshu-CODERX
Copy link

I’ve integrated the TLabWebView plugin with the Meta XR SDK, but I’m encountering an issue with YouTube Music. When I open the YouTube Music website, it freezes the entire webview system. After that, no other URLs can be loaded, even if I destroy the webview instance at runtime. However, the music continues playing in the background. If I try to instantiate a new webview, it fails to load, and this sometimes leads to the app crashing. Even when the app doesn’t crash, the music persists in the background, and closing the app doesn’t stop it. I ultimately have to restart the headset to resolve the issue.

Any solution to this would be highly appreciated.

Thanks

@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 2, 2025

Hi @Priyanshu-CODERX , thanks for the report. I just read and not everything you mentioned, but I tested music.youtube.com on my sample project in oculus quest 2 and meta quest, meta quest 2.

The following issues are I previously noticed and similar the issue that you mentioned. Maybe thier related and maybe issues are already fixed in the latest version.


  1. Can't load url after load first page.
  2. Media is still playing even after destroying the WebView instance.

Additionally, please paying attention that it is impossible to play multiple media with multiple WebView. If you playing media with WebView, other WebView instance's media will be paused.


What plugin version are you currently using ? TLabWebViewVR uses TLabWebView and latest version is v1.0.2. It is destractive update for v0.* to v1.* (especially event callback and javascript interface) and if you currently using v0.* (it can check via package.json), may it will be a hard work to migrate to v1.*. Please tell me about update plugin and how to support to latest api if you have any question.


Currently, I couldn't check the issue for app crash and media still playing even if close app. If it is possible, it is preferble to attach logcat's output. And if problem could reproduce on my sample project, it is most preferable to show step of how reproduce error and attach logcat's output of it.

@Priyanshu-CODERX
Copy link
Author

Priyanshu-CODERX commented Jan 2, 2025

Hi @TLabAltoh, thank you for your prompt response. I am currently using version 1.0.1 of the plugin. The pages are loading correctly, including YouTube and other sites. However, when I visit YouTube Music and play a song, the entire WebView freezes. Interestingly, no errors are being logged in logcat.

For YouTube, it is expected behavior that when multiple WebView instances are open, playing media in one instance pauses playback in the others. However, with YouTube Music, the website completely freezes not after media starts playing but when I try to search for something else through the search bar. Even attempting to destroy the frozen instance doesn’t stop the playback, and this causes every other WebView instance to freeze as well. Any new instance that I try to open after this issue, the page remains completely blank.

Previously, there was an issue where destroying a WebView instance while a YouTube video was playing caused the app to crash. My workaround for that was to redirect the WebView to a static page before destroying the instance. This solution worked well for other media players. However, with YouTube Music, the WebView does not even load the static page, making this workaround ineffective.

I couldn’t find anything unusual in the logcat to indicate why the freeze and crash occurred, but I will recheck it. Meanwhile, here’s how you can reproduce the issue:

  1. Open YouTube Music in a browser instance within the WebView and play a song.
  2. Attempt to search for something else using the search bar.
  3. Then try to add more Webview instances

When you do this, all the WebView instances freeze. If you try to use other WebView instances or create new ones, you’ll notice the entire system freezes. In some cases, it crashes. When a crash occurs, the media continues to play quite abruptly.

I am attaching a couple of recordings for your reference.
https://youtu.be/yP_5Aydb-sg
https://youtu.be/G_b8o4EpKOM

Also, I would like to know if there is a better way to destroy these instances? cos currently I am just using Destroy() any cleanups that I would have to do?

@TLabAltoh
Copy link
Owner

Thanks for the details ... I'll check them again !

TLabAltoh added a commit to TLabAltoh/TLabWebViewPlugin that referenced this issue Jan 2, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebView that referenced this issue Jan 2, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebView that referenced this issue Jan 2, 2025
TLabAltoh added a commit that referenced this issue Jan 2, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebViewSample that referenced this issue Jan 2, 2025
@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 2, 2025

This is just a progress report, but I was able to reproduce the error (currently, I only checked https://youtu.be/yP_5Aydb-sg yet) ... I think this issue is related to the Horizon OS problem. Horizon OS doesn't support standard android widget components in 3d app, so popup windows commonly used in android app could not be used in (oculus/meta) quest's 3d app. This causes WebView's some popup not to work on (oculus/meta) quest (like datatime-picker, and this case) and additionally it also causes problem that app couldn't close properly when it's problem called.

In this video, I was asked "Can you leave this site? Changes you have made may not be saved. (cancel / leave the page)". It didn't show up in the (oculus/meta) quest's WebView.

screen-20250103-042538.mp4


Maybe the above problem can't be solved from my side because it's an OS layer problem. So I suggest to use GeckoView plugin instead of WebView as browser engine. It is experimental and poor documentation, but I support GeckoView as browser engine in TLabWebView. It is mostly the same as WebView, but could handle the browser's popup window event as a customisable uGUI.

Please note that changing the browser engine from WebView to GeckoView may result in compromises. For example, WebView has a more powerful javascript interface than GeckoView, it could send and receive data from both javascript and Unity C#. But GeckoView only has the function of sending data from C# to javascript. And WebView's plugin interface has been in development longer than GeckoView's it. GeckoView feature is experimental, so possibility to include annoying problem in other part. Also, GeckoView plugin is not a system service like WebView. It is binary file and need to be included in application. So it cause increase application size (maybe +200MB).

Please see here for replace browser engine from WebView to GeckoView (Maybe the explanation is too rough to understand).

In the meantime, after a little time, I will check the other issue (https://youtu.be/G_b8o4EpKOM). But please don't hesitate to ask me about replacing the browser engine from WebView to GeckoView or any other opinion on this topic.


Also, I would like to know if there is a better way to destroy these instances? cos currently I am just using Destroy() any cleanups that I would have to do?

↑ using Destroy() is the intended and correct way !

@Priyanshu-CODERX
Copy link
Author

Hey, thanks for the update! I tried using GeckoView as you suggested, and it resolved the issue with destroying the YouTube Music instance—there are no longer any problems when I do so.

However, I encountered another issue. After playing music on YouTube Music and performing a search through the search bar, a popup appears as expected when leaving the site. But when I click on any of the buttons in the popup, the app crashes.

I’m attaching the crash log for your reference. Let me know if you need additional details or further testing!

2025-01-03 10:39:29.322 30461 30461 Error TLabWebView (Gecko) loadUrl: https://www.google.com/search?q=gmail
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime FATAL EXCEPTION: main
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime Process: com.PriyanshuBhattacharjee.Widgets, PID: 30461
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime java.lang.RuntimeException: org.json.JSONException: End of input at character 0 of 
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at com.tlab.webkit.BaseOffscreenBrowser.lambda$PostDialogResult$0$com-tlab-webkit-BaseOffscreenBrowser(BaseOffscreenBrowser.java:95)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at com.tlab.webkit.BaseOffscreenBrowser$$ExternalSyntheticLambda4.run(Unknown Source:6)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at android.os.Handler.handleCallback(Handler.java:938)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at android.os.Handler.dispatchMessage(Handler.java:99)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at android.os.Looper.loopOnce(Looper.java:214)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at android.os.Looper.loop(Looper.java:304)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at android.app.ActivityThread.main(ActivityThread.java:7918)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at java.lang.reflect.Method.invoke(Native Method)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1010)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime Caused by: org.json.JSONException: End of input at character 0 of 
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at org.json.JSONTokener.syntaxError(JSONTokener.java:460)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at org.json.JSONTokener.nextValue(JSONTokener.java:101)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at org.json.JSONObject.<init>(JSONObject.java:168)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at org.json.JSONObject.<init>(JSONObject.java:185)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	at com.tlab.webkit.BaseOffscreenBrowser.lambda$PostDialogResult$0$com-tlab-webkit-BaseOffscreenBrowser(BaseOffscreenBrowser.java:93)
2025-01-03 10:39:31.606 30461 30461 Error AndroidRuntime 	... 9 more

@Priyanshu-CODERX
Copy link
Author

Also, I cannot seem to view youtube video on fullscreen and this error is popping up

2025-01-03 12:13:37.907 15802 17264 Error GeckoConsole [JavaScript Error: "TypeError: Not in fullscreen mode" {file: "resource://gre/modules/GeckoViewContent.sys.mjs" line: 176}]

@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 3, 2025

Please update TLabWebView to the latest version (v1.0.3). I noticed a crash yesterday when clicking the popup window button, now it is fixed.


Also, full screen is not supported at the moment in Gecko feature. I should have mentioned this in the previous comment, but I forgot.

See here for details. This developer had the same problem and discussed it with the GeckoView team. Maybe the problem is related to GeckoView's architecture.


I know it is inconvenient that there is no complete solution. I'm just trying to figure out what to do about it ...

@Priyanshu-CODERX
Copy link
Author

Hi! Thanks for your help on this. 😊 I’ll update to version 1.0.3.

I also wanted to ask how to inject JavaScript into WebView. I tried using EvaluateJS, but nothing seemed to happen. My goal is to block popups from appearing on these websites so that I can use WebView without any crashes.

Below is the code that blocks the popups from happening.

window.onbeforeunload = null;

// Overwrite addEventListener to block any 'beforeunload' events
const originalAddEventListener = window.addEventListener;
window.addEventListener = function (type, listener, options) {
    if (type === 'beforeunload') {
        console.warn("Blocked a 'beforeunload' listener from being added.");
        return;
    }
    originalAddEventListener.call(this, type, listener, options);
};

const removeUnloadListeners = () => {
    const eventListeners = window.getEventListeners?.(window); // Chrome-only
    if (eventListeners?.beforeunload) {
        eventListeners.beforeunload.forEach(listener => {
            window.removeEventListener('beforeunload', listener.listener);
        });
    }
};

removeUnloadListeners?.();

// Add a final 'beforeunload' handler to ensure no returnValue is set
window.addEventListener("beforeunload", (event) => {
    console.log("Ensuring no prompt is shown during unload.");
    event.preventDefault();
});

@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 3, 2025

I see, that's the way to do it. I have not tested the code on my environment, so it is not sure, but maybe removing the commentout will make it work. EvaluateJS executes javascript via the LoaUrl function in the native plugin. So javascript is treated as a single line string. So it is necessary to remove the commentout.

PS: I'll check myself later.

TLabAltoh added a commit to TLabAltoh/TLabWebViewPlugin that referenced this issue Jan 4, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebView that referenced this issue Jan 4, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebView that referenced this issue Jan 4, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebViewSample that referenced this issue Jan 4, 2025
@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 4, 2025

I tested on my environment (only my Android phone, it is not Oculus Quest but based on the same OS so it is enough to test) and faced failure. And this problem seems to be caused by my native plugin problem, so I updated the plugin from v1.0.3 to v1.0.4. Now your javascript code works on my enviroment (but please remove comment as mentioned above). Please update plugin, maybe problem solved ...

@Priyanshu-CODERX
Copy link
Author

Hey! mate thanks for your support. I tried the package and I am currently getting this error

Library\PackageCache\com.tlabaltoh.webview@7d3a31ac20\Runtime\Sample\JSSnippets.cs(7,34): error CS0246: The type or namespace name 'BrowserContainer' could not be found (are you missing a using directive or an assembly reference?)

I tried deleting it but as it's a part of the package itself it keeps coming back.

@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 8, 2025

Thanks for the report ... Currently investigating. Could you try restarting the editor and reinstalling the package? I have not been able to reproduce the error and do not know the cause of the error ...

Your package's commit id is certainly latest version. So maybe there happened to be some git error or conflict of script file's metadata (not sure) ?

@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 8, 2025

Maybe this (form A) or this (form B) will help ?

form A -----------------------------------
nattybumppo
Did you try deleting your Library and letting Unity re-create it? Alternatively, you might be able to fix it by selecting Help —> Reset Packages to defaults in the menu.
form B -----------------------------------
andrew-lukasik
Open up project’s package manager and either try installing different version number or uninstall ${package name} package entirely

@Priyanshu-CODERX
Copy link
Author

Hi! I tried the suggested solutions, but unfortunately, they didn’t resolve the issue. I plan to explore a few more approaches to see if they work.

In the meantime, I deleted the script and built the app again, but the JavaScript code still doesn’t seem to execute. I also tested it with your sample, and the issue persists there as well.

Currently, I’m using the BrowserContainer to access the EvaluateJS() function. This function is invoked whenever the enter or search button is pressed, utilizing the OnEnter event from the SearchBar script. However, the same problem continues.

Interestingly, it worked temporarily when I tried this approach a few days ago with the update you provided. However, after building the app a second time, the issue reappeared.

It'd be great if you could take a look at that

Thanks

TLabAltoh added a commit to TLabAltoh/TLabWebViewPlugin that referenced this issue Jan 8, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebView that referenced this issue Jan 8, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebView that referenced this issue Jan 8, 2025
TLabAltoh added a commit that referenced this issue Jan 8, 2025
@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 8, 2025

I re-tested and noticed that beforeunload event is ignored only when loading media url with autoplay. Before, I only tested com.music.youtube/{media url} with autoplay so it seems passed but actually the problem is not solved ... (very very sorry!! 😞). Also, I found this form and it says that getEventListeners is a dev-console api, so it didn't defined in WebView's javascript engine. Maybe that's why javascript didn't work as intended on WebView (maybe it is difficult to remove the pre-added event from window).

Therefor, I have added OnPageStart callback to avoid specific events added to window in the latest update. It was also tested on oculus-quest and next time it should work (The OnPageStart callback is not synchronized with the WebView loading process, but this approach may work in most cases). Please update TLabWebView from v1.0.4 to v1.0.5. bellow is the demo movie and code example (the problem of JSSnippets.cs's compile error is still investigating).


C#

using UnityEngine;

namespace TLab.WebView.Sample
{
    public class JSSnippets : MonoBehaviour
    {
        [SerializeField] private BrowserContainer m_container;

        public void DisableBeforeUnload()
        {
            var js = Resources.Load<TextAsset>("TLab/WebView/Samples/Scripts/JS/disable-beforunload")?.ToString();
            m_container.browser.EvaluateJS(js);
        }
    }
}

javascript

// disable-beforeunload.txt
const originalAddEventListener = window.addEventListener;
window.addEventListener = function (type, listener, options) {
    if (type === 'beforeunload') {
        console.warn("Blocked a 'beforeunload' listener from being added.");
        return;
    }
    originalAddEventListener.call(this, type, listener, options);
};

@Priyanshu-CODERX
Copy link
Author

Hey mate, thanks a ton for all your help! The scripts are now executing properly, and I also managed to resolve the conflict error. It turned out that there were a few duplicate files in the project causing the issue. Deleting the entire package along with those duplicates fixed it.

However, there's still one issue remaining: the "GoForward" functionality isn't working for the webviews, even though the "GoBack" feature works perfectly.

TLabAltoh added a commit to TLabAltoh/TLabWebViewPlugin that referenced this issue Jan 9, 2025
TLabAltoh added a commit to TLabAltoh/TLabWebView that referenced this issue Jan 9, 2025
@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 9, 2025

However, there's still one issue remaining: the "GoForward" functionality isn't working for the webviews, even though the "GoBack" feature works perfectly.

Thanks for reporting, it is a related plugin bug. So I released fixed version just now but please note that this update didn't updated package version code (treated as tiny update). Please update TLabWebView.

@Priyanshu-CODERX
Copy link
Author

Ah, awesome, thanks! :) Would it possible to add an event callback that gets invoked when any input field is clicked? The goal is to make the keyboard appear only when an input field is selected.

@TLabAltoh
Copy link
Owner

TLabAltoh commented Jan 9, 2025

It is possible to switch keybord's active state via html input's focus event, but it is with some limmitation. Here is an example and this feature has implemented on this sample repositly.


C#

original is here

using UnityEngine;
using UnityEngine.EventSystems;
using TLab.VKeyborad;


namespace TLab.WebView.Sample
{
    public class FocusInOutInteractionSample : MonoBehaviour, IPointerDownHandler
    {
        [SerializeField] private SearchBar m_searchBar;
        [SerializeField] private BaseInputField m_inputField;
        [SerializeField] private BrowserContainer m_container;

        public void OnPageFinish(string url)
        {
            var js = JSUtil.ToVariable("go", gameObject.name) + JSUtil.ToVariable("method", nameof(OnMessage));
            js += Resources.Load<TextAsset>("TLab/WebView/Samples/Scripts/JS/focus-in-out-interaction")?.ToString();

            m_container.browser.EvaluateJS(js);
        }

        public void OnMessage(string message)
        {
            Debug.Log("OnMessage: " + message);

            switch (message)
            {
                case "Focusin":
                    m_inputField.OnFocus(true);
                    break;
                case "Focusout":
                    m_inputField.OnFocus(false);
                    break;
            }
        }

        public void OnPointerDown(PointerEventData eventData) => m_searchBar.OnFocus(false);
    }
}

javascript

original is here

function searchShadowRoot(node, roots) {
    if (node == null) {
        return;
    }

    if (node.shadowRoot != undefined && node.shadowRoot != null) {
        roots.push(node.shadowRoot);
        searchShadowRoot(node.shadowRoot, roots);
    }

    for (var i = 0; i < node.childNodes.length; i++) {
        searchShadowRoot(node.childNodes[i], roots);
    }
}


function getAllRoot() {
        var roots = [document];
        searchShadowRoot(document, roots);
        return roots;
}

var roots = getAllRoot();

function focusin (e) {
    const target = e.target;
    if (target.tagName == 'INPUT' || target.tagName == 'TEXTAREA') {
        window.tlab.unitySendMessage(go, method, 'Focusin');
    }
}


function focusout (e) {
    const target = e.target;
    if (target.tagName == 'INPUT' || target.tagName == 'TEXTAREA') {
        window.tlab.unitySendMessage(go, method, 'Focusout');
    }
}


for (var i = 0; i < roots.length; i++) {
    roots[i].removeEventListener('focusin', focusin);
    roots[i].removeEventListener('focusout', focusout);

    roots[i].addEventListener('focusin', focusin);
    roots[i].addEventListener('focusout', focusout);
}

This approach didn't work on some website because it's impossible to add event listener to iframe's html document if iframe content's server doesn't allow crossorigin access. So above example will work on most of website, but won't work on only some iframe content.

other solution

Oculus Quest can use the system keyboard on unity and also works on the TLabWebView's html input element (this feature is not limited even if iframe). Please see here for how to setup system keyborad on unity.


WebView doesn't have feature for handling html element's event other than javascript. So I am still considering more efficient way but this is only way I came up with ...

@Priyanshu-CODERX
Copy link
Author

Thanks mate for the suggestions, I have switched to system keyboard for now but I will be experimenting with the other approach as well.

Thanks for all the help :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants