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] make height of WebView the height of webpage #34138

Open
jordanmosakowski opened this issue Jun 9, 2019 · 34 comments
Open
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter customer: crowd Affects or could affect many people, though not necessarily a specific customer. p: webview The WebView plugin P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team

Comments

@jordanmosakowski
Copy link

I would like to have multiple WebViews (from the webview_flutter plugin) in my flutter app on the same page. I want to have each page be loaded so that the height of the container is the same as the height of the web page.

Here's what I have so far:

ListView(
   children: <Widget>[
      Container(
         height: 500,
         child: WebView(
            initialUrl: urlA,
         ),
      ),
      Container(
         height: 500,
         child: WebView(
            initialUrl: urlB,
         ),
      ),
      Container(
         height: 500,
         child: WebView(
            initialUrl: urlC,
         ),
      ),
   ]       
)

Obviously, this loads 3 webviews each with a height of 500. However, I don't want to have to define a height for each page, and instead have it set the height of the Container based on the height of the actual page. (ie. urlA has a page with a height of 300, urlB is 250, and urlC is 600, so each container (or some other widget) has a height of 300, 250, and 600 respectively. Each container fits to be exactly that size. If at any point they go off the page, you can scroll with ListView.)

@stuartmorgan stuartmorgan added p: webview The WebView plugin plugin labels Jun 16, 2019
@SPodjasek
Copy link
Contributor

SPodjasek commented Jun 18, 2019

I wanted a similar behavior and came up with a new widget which wraps WebView and using some injected JavaScript reads page height after loading, then sends this information back using javascriptChannels and resizes itself to match the content height.
It works.... mostly, at least it works without any problems on my Nexus 5x. But it seems that resizing of PlatformView can cause problems on random hardware - problems including application exceptions and even soft-boot of Android (#34647). So as for now, I don't use this solution in production.

You can find source of my solution here.

@ivtod
Copy link

ivtod commented Jun 20, 2019

Hi @SPodjasek, great solution. Do you get the exact size for the webview with
<script type="text/javascript">window.extents.postMessage(document.body.offsetHeight);</script>?
I always get extra space at the end of the webview.
Have you been able to debug the webview?

@SPodjasek
Copy link
Contributor

@ivtod This is the simplest possible solution that works for me. My WebView contents were 100% static and maybe because of that, I haven't noticed any extra white space. If your is in any kind dynamic, even when you use some lazy loading web fonts you would have to think of some other solution to fetch final body height, using event listeners on DOM - maybe snippet below will give you better results.

document.body.onload = function() {
  window.extents.postMessage(document.body.offsetHeight)
}

And keep in mind that using this solution you can get really nasty results in production, scaling WebView anything above 3000px on Pixel 3 emulator results in depletion of resources and system soft-boot. This limit varies by platform.

@lorentz-wu
Copy link

lorentz-wu commented Aug 7, 2019

I add webview to scrollable. webview crashed when content height too large. how to resolve this?

contentHeight=8455.0
W/PlatformViewsController(22212): Creating a virtual display of size: [720, 16910] may result in problems(#2897 is larger than the device screen size: [720, 1184].
D/EGL_emulation(22212): eglMakeCurrent: 0x7553d843dae0: ver 2 0 (tinfo 0x7553d85b7a80)
Lost connection to device

@SPodjasek
Copy link
Contributor

SPodjasek commented Aug 20, 2019

@lorentz-wu You can't resolve this for now with WebView. Use some other solution, or if you really need to place WebView in scrollable experiment with fixed WebView size and javascript channel to synchronize WebView internal scroll offset with srollable's ScrollController logic.

@phamnhuvu-dev
Copy link

Hi @SPodjasek, great solution. Do you get the exact size for the webview with
<script type="text/javascript">window.extents.postMessage(document.body.offsetHeight);</script>?
I always get extra space at the end of the webview.
Have you been able to debug the webview?

me too, working fine on iOS

@shadysamir
Copy link

shadysamir commented Dec 12, 2019

I use document.body.scrollHeight with the exact same solution. I think it's our only option for now and it works well. window.onLoad works best because it waits for all the resources to finish loading. Those can affect the final size. There could be 2 functions, one for initial DOM ready (document.onLoad) and one for full page ready (window.onLoad) to adapt faster to size change.

Meanwhile, @SPodjasek is the height resources limitation officially documented anywhere? Or do we go by trial and error?

@SPodjasek
Copy link
Contributor

@shadysamir I haven't found any documentation about this limitation and it is probably hardware dependent limitation. And as for some recent flutter/engine changes you get a warning if you scale PlatformView above hardware screen size (flutter/engine#9110).

@TahaTesser TahaTesser added customer: crowd Affects or could affect many people, though not necessarily a specific customer. p: first party c: proposal A detailed proposal for a change to Flutter labels Mar 19, 2020
@hardypatel30
Copy link

I wanted a similar behavior and came up with a new widget which wraps WebView and using some injected JavaScript reads page height after loading, then sends this information back using javascriptChannels and resizes itself to match the content height.
It works.... mostly, at least it works without any problems on my Nexus 5x. But it seems that resizing of PlatformView can cause problems on random hardware - problems including application exceptions and even soft-boot of Android (#34647). So as for now, I don't use this solution in production.

You can find source of my solution here.

Hey, tried many solution but this seemed work for me.

@BeshoyAdelHemaya
Copy link

The problem is still exist. we need an urgent solution for this issue. i tried more ways like parse html and load it in list of webviews but it affect the performance.

@bilal2-1
Copy link

how to manage width of web page in flutter

@shah-xad
Copy link

I just created an extension of webview_flutter which allows getting the height of Web content which will allow you to use it even in a listview, do check this webview_flutter_plus.

@sm9i
Copy link

sm9i commented Jul 27, 2020

I also encounter this problem. I use 'flutter_Inappwebview ` loads Amap and crashes while moving

@CuoJue21
Copy link

CuoJue21 commented Aug 28, 2020

same problem
get webview height but is too large for some phone like Android so than it will be kill

@aker99
Copy link

aker99 commented Sep 3, 2020

I have created a package in extension to the webview_flutter which can update web-view height dynamically, it's currently limited to embed of social media platforms, but anyone can use my approach to develop their variant. Do check it: social_embed_webview

@pocketbranch
Copy link

This implementation partly solves this issue for me

https://gist.github.com/PonnamKarthik/877a90917a576ecff613d5169680d02c

See CarloTerracciano solution for URLs as in your case.

https://gist.github.com/PonnamKarthik/877a90917a576ecff613d5169680d02c#gistcomment-3437222

@dejvizelo
Copy link

dejvizelo commented Nov 22, 2020

@lorentz-wu You can't resolve this for now with WebView. Use some other solution, or if you really need to place WebView in scrollable experiment with fixed WebView size and javascript channel to synchronize WebView internal scroll offset with srollable's ScrollController logic.

@SPodjasek I know this is an old comment, but I need to implement what you described here in my app, as I am trying to embed a WebView in DraggableScrollableSheet. Could you maybe help me implement this or point me to the right direction? How can I sync the WebView internal scroll to Scrollable's ScrollController?

@obiwanzenobi
Copy link

obiwanzenobi commented Feb 9, 2021

You could always inject resize observer into body to adjust webview size in real time:

<script>
  const resizeObserver = new ResizeObserver(entries =>
  Resize.postMessage("height" + (entries[0].target.clientHeight).toString()) )
  resizeObserver.observe(document.body)
</script>

And add a js channel

         javascriptChannels: Set.from([
            JavascriptChannel(name: "Resize", onMessageReceived: (JavascriptMessage message) {
              updateHeight();
            })
          ]),

Update height:

  void updateHeight() async {
    double height = double.parse(await controller
        .evaluateJavascript(
        "document.documentElement.scrollHeight;"));
    
    if(this.height != height) {
      setState(() {
        this.height = height;
      });
    }
  }

I'm using additional update height because resize observer gave me a wrong height metrics

@shadysamir
Copy link

I already implement a height observer in my web page and I read it through JS channel. That's not the issue. The issue is that there seems to be a limit to the webview height, beyond it the app crashes (memory?)

@dickverweij
Copy link

dickverweij commented Mar 1, 2021

Sorry to barge in here. But i use a simular approach for obtaining the pixel height.

double height = double.parse(await controller
.evaluateJavascript(
"document.documentElement.scrollHeight;"));

My problem is that the reported pixelheight on IOS (Iphone 12) looks like it is twice the flutter pixel height???

For example I get 1900 pixels back from the IOS callback. but is has to be 950 "flutter" pixels.. Is there some kind of multiplier on the ios device active?

@stuartmorgan stuartmorgan added the P3 Issues that are less important to the Flutter project label Apr 5, 2021
@p02diada
Copy link

p02diada commented Aug 13, 2021

Sorry to barge in here. But i use a simular approach for obtaining the pixel height.

double height = double.parse(await controller
.evaluateJavascript(
"document.documentElement.scrollHeight;"));

My problem is that the reported pixelheight on IOS (Iphone 12) looks like it is twice the flutter pixel height???

For example I get 1900 pixels back from the IOS callback. but is has to be 950 "flutter" pixels.. Is there some kind of multiplier on the ios device active?

@dickverweij Did you find a solution? I Have the same problem, in Android the workaround works well but in IOS (SE 1º gen) the height is almost double.

@singh-karan-7
Copy link

Sorry to barge in here. But i use a simular approach for obtaining the pixel height.

double height = double.parse(await controller .evaluateJavascript( "document.documentElement.scrollHeight;"));

My problem is that the reported pixelheight on IOS (Iphone 12) looks like it is twice the flutter pixel height???

For example I get 1900 pixels back from the IOS callback. but is has to be 950 "flutter" pixels.. Is there some kind of multiplier on the ios device active?

Hey there, did you or anyone here found the solution to this? I tried to divide the height by MediaQuery.of(context).devicePixelRatio, but, the height is still more than what it should be.

@dickverweij
Copy link

dickverweij commented May 25, 2022

Sorry to barge in here. But i use a simular approach for obtaining the pixel height.
double height = double.parse(await controller .evaluateJavascript( "document.documentElement.scrollHeight;"));
My problem is that the reported pixelheight on IOS (Iphone 12) looks like it is twice the flutter pixel height???
For example I get 1900 pixels back from the IOS callback. but is has to be 950 "flutter" pixels.. Is there some kind of multiplier on the ios device active?

Hey there, did you or anyone here found the solution to this? I tried to divide the height by MediaQuery.of(context).devicePixelRatio, but, the height is still more than what it should be.

Nope.. Sadly IOS is currently not pixel perfect in our app. Next to the crash for big android webviews loaded in to flutter platform views, we can say that normal viewing web content in a flutter app is somewhat flawed.

For anyone who has issues with the big size crash in android, we "solved" it to make the view in flutter a fixed height and used gestures to control the scrolling in the platform view.

@phyohtetarkar
Copy link

Hello, I don't know if this is late. I resolved getting the wrong height by adding some delay before evaluating scrollHeight.

WebView(
  javascriptMode: JavascriptMode.unrestricted,
  onWebViewCreated: (controller) {
    _controller = controller;
    _controller?.loadHtmlString(_htmlString.trim());
  },
  onPageFinished: (url) async {
    // Add some delay before evaluate
    await Future.delayed(const Duration(milliseconds: 1000));

    String heightStr = await _controller?.runJavascriptReturningResult(
            "document.documentElement.scrollHeight") ??
        "0";
    setState(() {
      _webviewHeight = double.parse(heightStr);
    });
    log(heightStr);
  },
)

@balaji101010
Copy link

balaji101010 commented Oct 31, 2022

@phyohtetarkar still I get double height of webview in iOS

@singh-karan-7
Copy link

I solved this. This should work for everyone. I am using flutter_inappwebview, but, it should work for webview_flutter too. You have to use your controller for this:

if (Platform.isIOS) {
                  _webViewController!
                      .evaluateJavascript(source: "document.readyState")
                      .then((value) {
                    _webViewController!
                        .evaluateJavascript(
                            source:
                                "document.body.style.width = '${screenWidth - responsivePadding}px'")
                        .then((value) {
                      _webViewController!
                          .evaluateJavascript(
                              source: "document.body.scrollHeight")
                          .then((value) {
                        setState(() {
                          newFrameHeight = value + 10;
                        });
                        // print(newFrameHeight);
                        // print('scrollHeight');
                      });
                    });
                  });
                } else {
                  final cHeight = await controller.getContentHeight();
                  setState(() {
                    newFrameHeight = (cHeight?.toDouble() ?? 0) + 10;
                  });
                }

@Andreigr0
Copy link

Sorry to barge in here. But i use a simular approach for obtaining the pixel height.

double height = double.parse(await controller .evaluateJavascript( "document.documentElement.scrollHeight;"));

My problem is that the reported pixelheight on IOS (Iphone 12) looks like it is twice the flutter pixel height???

For example I get 1900 pixels back from the IOS callback. but is has to be 950 "flutter" pixels.. Is there some kind of multiplier on the ios device active?

Just add this line to <html></html>:
<meta name="viewport" content="width=device-width, initial-scale=1.0">

Thanks to pichillilorenzo/flutter_inappwebview#35 (comment)

@dickverweij
Copy link

I already did that:

<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, viewport-fit=cover">

The only thing what works for me is to wait a second, and then do the javascript call again, then it reports the actual (correct) size.

@singh-karan-7
Copy link

I already did that:

<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, viewport-fit=cover">

The only thing what works for me is to wait a second, and then do the javascript call again, then it reports the actual (correct) size.

Did you try the above solution by me, involving setting the width in the Flutter app by evaluating Javascript?

@dickverweij
Copy link

dickverweij commented Jan 18, 2023

I already did that:
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, viewport-fit=cover">
The only thing what works for me is to wait a second, and then do the javascript call again, then it reports the actual (correct) size.

Did you try the above solution by me, involving setting the width in the Flutter app by evaluating Javascript?

No. Does setting the width somehow influences the height (?? )

Also I see that your script evaluates document.readyState into flutter variable "value" but does nothing with it?

@singh-karan-7
Copy link

I already did that:
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, viewport-fit=cover">
The only thing what works for me is to wait a second, and then do the javascript call again, then it reports the actual (correct) size.

Did you try the above solution by me, involving setting the width in the Flutter app by evaluating Javascript?

No. Does setting the width somehow influences the height (?? )

Also I see that your script evaluates document.readyState into flutter variable "value" but does nothing with it?

Why not just try it? You can ignore the value in readyState.

@flutter-triage-bot flutter-triage-bot bot added the package flutter/packages repository. See also p: labels. label Jul 5, 2023
@Hixie Hixie removed the plugin label Jul 6, 2023
@flutter-triage-bot flutter-triage-bot bot added team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team labels Jul 8, 2023
@stuartmorgan stuartmorgan added the c: new feature Nothing broken; request for a new capability label Sep 8, 2023
@emiliodallatorre
Copy link

Just a quick question to add in this thread.
Are the webview pixels (the one defined in CSS) scaled in device pixels or are they 1:1?

I mean, if a div has a size of 600px, will it fit perfectly in a container sized 600px?

@adrianvintu
Copy link

Still not fixed, after 5 years...

@malbolged
Copy link

malbolged commented Feb 16, 2024

Still not fixed, after 5 years...

P3 so ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter customer: crowd Affects or could affect many people, though not necessarily a specific customer. p: webview The WebView plugin P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team
Projects
None yet
Development

No branches or pull requests