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

[webview_flutter_web] Migrate to package:web. #6792

Merged
merged 20 commits into from
Jul 10, 2024

Conversation

ThomasAunvik
Copy link
Contributor

@ThomasAunvik ThomasAunvik commented May 24, 2024

Would appreciate help with completing the mock tests if in case it does not work.
(I am somehow stuck with 'loading...' when attempting to test with mockito with --platform chrome)

Integration tests from what i was able to test passes.

Migrated to using BrowserClient for web due to issues creating mock tests with XMLHttpRequest which is returned from package:web's HttpRequest.request following error:

Bad state: Interface type 'XMLHttpRequest' which is nether an enum, nor a class, nor a mixin. This case is unknown, please report a bug.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Co-authored-by: David Iglesias [email protected]
Co-authored-by: Navaron Bracke [email protected]

@ThomasAunvik ThomasAunvik requested a review from ditman as a code owner May 24, 2024 19:07
@ThomasAunvik ThomasAunvik changed the title [webview_flutter_web] Migration to package:web and [webview_flutter_web] Migration to package:web May 24, 2024
@ThomasAunvik
Copy link
Contributor Author

ThomasAunvik commented May 24, 2024

The tests that seem to be failing now are just the ones in the legacy/ folder, that we require to create a mock HTMLIFrameElement.

And these two calls that i do not understand what it is trying to do.
Based on the lsp, argThat just returns null and mockElement.src cannot be set to a null, can only be set to String.

verify(mockElement.src = argThat(contains('%23')) ?? '');

verify(mockElement.src = argThat(contains('%23')) ?? '');

Legacy tests N-2 are failing due to the package:web having a higher dart sdk requirement than the test has installed.
currently web version is set to version ^0.5.1, it suggests it to be set to ^0.3.0. Reading the changelog of the package, i don't see any breaking changes on it. So i assume it should be fine to lower the versioning?

I can go down for web to ^0.3.0 and http to ^1.2.0, but HTMLIFrameElement is missing a src getter which the tests needs.
But if we going to need to create a mock for it, then I assume it should be fine to downgrade, if we can have the mock to have a getter on it.

nvm, package:web included an extension to use a getter to HTMLIFrameElement.src.

@ThomasAunvik ThomasAunvik force-pushed the fixwasmtests branch 2 times, most recently from 79c0198 to fa99260 Compare May 24, 2024 22:41
@ditman
Copy link
Member

ditman commented May 25, 2024

Thanks for the PR @ThomasAunvik! I'll take a look!

(Please take into account that next monday is a holiday in the US, so I won't be able to get to this until next tuesday at the earliest)

@uldall
Copy link

uldall commented Jun 3, 2024

I have been experimenting with this PR for a few days, and run into the issue that the created <iframe> doesn't have the credentialless attribute set, and so won't load if the iframe'ed document doesn't have the proper headers when being GET'ed. See:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/credentialless and https://developer.mozilla.org/en-US/docs/Web/Security/IFrame_credentialless

I think it would make sense to make it possible to specify whether this attribute should be set from Flutter code?

@ThomasAunvik
Copy link
Contributor Author

ThomasAunvik commented Jun 3, 2024

https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/credentialless and https://developer.mozilla.org/en-US/docs/Web/Security/IFrame_credentialless

Looking at the compatability, firefox and safari is not yet supported, but an option to enable it would be beneficial once it is fully supported.

Otherwise the current solution for all browsers is that the hosted webapp has the Cross-Origin-Embedder-Policy: credentialless header set.

@uldall
Copy link

uldall commented Jun 3, 2024

Otherwise the current solution for all browsers is that the hosted webapp has the Cross-Origin-Embedder-Policy: credentialless header set.

In most cases people don't own the sites that they iframe, and it can be very hard to convince a third party to add support for these headers.

Looking at the compatability, firefox and safari is not yet supported, but an option to enable it would be beneficial once it is fully supported.

I don't see why we would wait. The WASM builds are already only supported in Chromium based browsers. But I also understand if you don't want to add it in this PR :)

@ThomasAunvik
Copy link
Contributor Author

ThomasAunvik commented Jun 3, 2024

In most cases people don't own the sites that they iframe, and it can be very hard to convince a third party to add support for these headers.

Nevermind i got confused on how the cors weirdness works, as i did pain with it too. It would work on setting credentialless on the iframe.

It can be easily done by adding this right after loadRequest.

_webWebViewParams.iFrame.setAttribute('credentialless', 'true');

As the current HTMLIFrameElement doesn't have it implemented directly yet.

Would require me to update the LoadRequestParams in webview_flutter_platform_interface to include a boolean for credentialless.

@ThomasAunvik
Copy link
Contributor Author

ThomasAunvik commented Jun 3, 2024

Here is a proposal on how setting the credentialless would be.
This is added under WebWebViewController

/// Sets the IFrame Credentialless
/// https://developer.mozilla.org/en-US/docs/Web/Security/IFrame_credentialless
void setIFrameCredentialless(bool flag) {
  _webWebViewParams.iFrame
      .setAttribute('credentialless', flag ? 'true' : 'false');
}

And to set it would be as such:

if(WebViewPlatform.instance is WebWebViewPlatform) {
    WebWebViewController(
        const PlatformWebViewControllerCreationParams(),
    )
    ..setIFrameCredentialless(true)
    ..loadRequest(
        LoadRequestParams(
            uri: Uri.parse('https://flutter.dev'),
        ),
    ))
}

setIFrameCredentialless is would most likely be the one that requires to be set before loadRequest, or at the same time.

I have set up a branch for it: https://github.com/ThomasAunvik/flutter-packages/tree/wasmcredentialless

Would like feedback.

Another issue would be that _updateIFrameFromXhr would still have a cors issue.

@uldall
Copy link

uldall commented Jun 4, 2024

It seems that on other platforms these kind of platform specific parameters are set on the WebViewControllerCreationParams implementation.

An example from the Webkit impl. Here some boolean parameters like allowsInlineMediaPlayback and limitsNavigationsToAppBoundDomains are set in the WebKitWebViewControllerCreationParams. Seems similar to our credentialless use case.

I am by no means well versed in the Flutter codebase, but this was just my best effort on some feedback. I will be going on vacation for a week, but will test the new branch when I am back :)

@kevmoo
Copy link
Contributor

kevmoo commented Jun 10, 2024

What's the status here, friends?

@uldall
Copy link

uldall commented Jun 12, 2024

I managed to test the credentialless branch just now, and it works as expected and the contents of the iframe is loaded:
image

@kevmoo
Copy link
Contributor

kevmoo commented Jun 12, 2024

@ditman would you take a look?

@uldall
Copy link

uldall commented Jun 12, 2024

I have been testing the PR quite a bit, and created this issue because Godot games being loaded in the iframe resulted in an error: flutter/flutter#150119

However since then I have also started getting the error on other sites (for example https://flutter.dev/). It does however work great on a payment site that I use. (reepay.com). I am not sure what properties of the iframe'ed site makes it throw the error.

Maybe the error is unrelated to this PR, and probably a bug in the skwasm renderer?

@ditman
Copy link
Member

ditman commented Jun 26, 2024

This is next on my radar, after this lands:

@ditman
Copy link
Member

ditman commented Jul 9, 2024

@ThomasAunvik I've finally had some time to review this! Instead of adding a bunch of comments and back and forth with the code, I just force pushed (please, remember to git pull --rebase on your checkout) the changes I thought your branch needed.

(TL;DR: I removed the package:http dependency and used package:web fetch instead, and cleaned up the mocks in tests a little bit with the new tricks that we can do with the latest JS-Interop 😉)

Do you mind to make a quick re-review yourself, ensure that the changes I added make sense, and verify that the plugin still does what you need? Tests seem to be passing, and the example app seems to work as expected, but the more use cases, the merrier!

method: method,
body: sendData?.toJS,
credentials: withCredentials ? 'include' : 'same-origin',
headers: headers.jsify()! as web.HeadersInit,
Copy link
Contributor

@navaronbracke navaronbracke Jul 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have support for the JS Map type yet (in JS interop that is), so perhaps we should add a TODO for that? Unless we have a constructor for web.HeadersInit that takes a Map<String, String> ?

In my opinion we can eventually get rid of the jsify() in the long run?

Not sure how @ditman feels about doing that, though?

Copy link
Member

@ditman ditman Jul 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(@navaronbracke I wrote the .jsify() bits :P)

Currently HeadersInit is just an alias of JSObject.

The init in JS itself is a vague object-like thing that doesn't have a very specific way of being constructed: Headers init parameter:

init
An object containing any HTTP headers that you want to pre-populate your Headers object with. This can be a simple object literal with String values, an array of name-value pairs, where each pair is a 2-element string array; or an existing Headers object. In the last case, the new Headers object copies its data from the existing Headers object.

I'm using the simplest/most legible way I've found so far of creating an object literal of a JS-interop type (a Map<String, Object?>.jsify()! as JsInteropType). I agree that a more semantic constructor in package:web could be better, but this way I can use all the power of Dart Maps until the very last moment. /cc @srujzs for The Ultimate Expert Opinion™!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Maybe something with _createObjectLiteral? source)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add a better constructor here if that's easier to read, but it's not going to do anything more complicated than just jsify :) e.g.

JSObject.fromMap(Map m) => m.jsify() as JSObject;

Copy link
Member

@ditman ditman Jul 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@srujzs yeah, I'd like to have a jsify in non-nullable-object so I don't have to Map.jsify()! and maybe a T jsifyAs<T>() that does the casting for me, so I could replace:

headers.jsify()! as web.HeadersInit

by

headers.jsifyAs<web.HeadersInit>();

(Not that it saves too much typing, though)

@ditman
Copy link
Member

ditman commented Jul 9, 2024

Just verified in CI that this package enables the webview_flutter package to compile to Wasm! 🎉

Exluding the following plugins from the combined build:
  plugin_platform_interface
  camera
  google_maps_flutter

If this works for @ThomasAunvik, I think it's ready to land!

@ThomasAunvik
Copy link
Contributor Author

ThomasAunvik commented Jul 9, 2024

Works as expected.

Experiencing an issue when re-opening the iframe (and be using the same pdf blob data / url), iframe doesn't render properly, showing nothing just the background of the parent widget, until resizing the window. (on wasm only).
I'll have to test it a bit more.

@ThomasAunvik
Copy link
Contributor Author

Created a reproducible example: ThomasAunvik/flutter_webview_wasm_error@f75fddb

Seems like this time I managed to make the iframe not appear at all when using Navigator.of(context).push()

Left is wasm on chrome, right is non-wasm using firefox.

error.mp4

Unless it is an issue with this package alone, i don't see it to be needing to not merge it with this issue, if that is also just a lower level flutter issue.

@ditman
Copy link
Member

ditman commented Jul 10, 2024

@ThomasAunvik I think you've encountered something like this:

Platform Views in Wasm have some positioning issues yet (it can also be seen with the default example app, I think)

Copy link
Member

@ditman ditman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Been here, seen this!

@ditman ditman changed the title [webview_flutter_web] Migration to package:web [webview_flutter_web] Migrates to package:web. Jul 10, 2024
@ditman ditman changed the title [webview_flutter_web] Migrates to package:web. [webview_flutter_web] Migrate to package:web. Jul 10, 2024
@ditman ditman added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 10, 2024
@ditman
Copy link
Member

ditman commented Jul 10, 2024

Let's try to autoland the PR!

Copy link
Contributor

auto-submit bot commented Jul 10, 2024

auto label is removed for flutter/packages/6792, due to This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a flutter-hacker before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 10, 2024
@kevmoo
Copy link
Contributor

kevmoo commented Jul 10, 2024

Rerunning failures and adding back auto-submit!

@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 10, 2024
Copy link
Contributor

auto-submit bot commented Jul 10, 2024

auto label is removed for flutter/packages/6792, due to This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a flutter-hacker before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 10, 2024
@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 10, 2024
@auto-submit auto-submit bot merged commit c47614c into flutter:main Jul 10, 2024
74 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 10, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 10, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 10, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Jul 10, 2024
flutter/packages@14341d1...ea35fc6

2024-07-10 [email protected] [camera_avfoundation] Adds Swift Package Manager compatibility (flutter/packages#7080)
2024-07-10 [email protected] [webview_flutter_wkwebview] Adds Swift Package Manager compatibility (flutter/packages#7091)
2024-07-10 [email protected] [webview_flutter_web] Migrate to package:web. (flutter/packages#6792)
2024-07-10 [email protected] [camera] Clean up `maxDuration` code (flutter/packages#7039)
2024-07-10 [email protected] Update espresso dependencies (flutter/packages#7048)
2024-07-09 [email protected] [camera] Fix iOS torch mode regression (flutter/packages#7085)
2024-07-09 [email protected] [google_maps_flutter] Convert Obj-C->Dart calls to Pigeon (flutter/packages#7086)
2024-07-09 [email protected] Roll Flutter from fafd67d to 5103d75 (27 revisions) (flutter/packages#7084)
2024-07-09 [email protected] [camera_avfoundation] fix sample times not being numeric after pause/resume. (flutter/packages#6897)
2024-07-09 [email protected] [camera] Convert Windows to Pigeon (flutter/packages#6925)
2024-07-09 [email protected] [camera] Deprecate `maxDuration` in platform interface (flutter/packages#7078)
2024-07-09 [email protected] [google_maps_flutter] Semi-convert remaining iOS host API calls to Pigeon (flutter/packages#7079)
2024-07-09 [email protected] [path_provider] Remove `win32` (flutter/packages#7073)
2024-07-08 [email protected] [google_maps_flutter] Move iOS inspector to Pigeon (flutter/packages#6937)
2024-07-08 49699333+dependabot[bot]@users.noreply.github.com [camera]: Bump com.android.tools.build:gradle from 7.3.0 to 8.5.0 in /packages/camera/camera_android_camerax/android (flutter/packages#7072)
2024-07-08 49699333+dependabot[bot]@users.noreply.github.com [local_auth]: Bump com.android.tools.build:gradle from 7.3.1 to 8.5.0 in /packages/local_auth/local_auth_android/android (flutter/packages#7069)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App p: webview_flutter platform-web
Projects
None yet
6 participants