pichillilorenzo / flutter_inappwebview

A Flutter plugin that allows you to add an inline webview, to use a headless webview, and to open an in-app browser window.
https://inappwebview.dev
Apache License 2.0
3.26k stars 1.6k forks source link

Infinite Loading with very long repeated log #782

Closed ycv005 closed 3 years ago

ycv005 commented 3 years ago

Environment

Technology Version
Flutter version 2.0.3 & 2.0.4
Plugin version flutter_inappwebview: ^5.3.1
Android version 10, 8, 7
iOS version NA
Xcode version NA

Device information: Redmi, Realme, and Samsung

Description

I am opening some website, let assume that I have open it 10 times, out of 7 times it open normally rest like 3 times it when into infinite loading and throwing very long log message. Also, the internet speed is very good like 1/2 Mbps when it goes into infinite loading. So, there is some problem for definite.

I have open several different website and i have same issue.

Video link- - https://photos.app.goo.gl/PD5n2v7ZweHnjypB7

Current behavior:

Steps to reproduce

  1. This
  2. Than that
  3. Then

Images

Stacktrace/Logcat

I am getting repeat logs so posting few of them-

I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 6 lines
8
D/AudioManager(20916): getStreamVolume isRestricted mode = 0
I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 14 lines
2
D/AudioManager(20916): getStreamVolume isRestricted mode = 0
I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 7 lines
3
D/AudioManager(20916): getStreamVolume isRestricted mode = 0
I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 2 lines
9
D/AudioManager(20916): getStreamVolume isRestricted mode = 0
I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 8 lines
3
D/AudioManager(20916): getStreamVolume isRestricted mode = 0
I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 4 lines
2
D/AudioManager(20916): getStreamVolume isRestricted mode = 0
I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 4 lines
2
D/AudioManager(20916): getStreamVolume isRestricted mode = 0
I/chatty  (20916): uid=10618(com.example.tbo) AdWorker(Defaul identical 1 line
6
D/AudioManager(20916): getStreamVolume isRestricted mode = 0

I also mailing you my app link on the mail for the reference

github-actions[bot] commented 3 years ago

👋 @ycv005

NOTE: This comment is auto-generated.

Are you sure you have already searched for the same problem?

Some people open new issues but they didn't search for something similar or for the same issue. Please, search for it using the GitHub issue search box or on the official inappwebview.dev website, or, also, using Google, StackOverflow, etc. before posting a new one. You may already find an answer to your problem!

If this is really a new issue, then thank you for raising it. I will investigate it and get back to you as soon as possible. Please, make sure you have given me as much context as possible! Also, if you didn't already, post a code example that can replicate this issue.

In the meantime, you can already search for some possible solutions online! Because this plugin uses native WebView, you can search online for the same issue adding android WebView [MY ERROR HERE] or ios WKWebView [MY ERROR HERE] keywords.

Following these steps can save you, me, and other people a lot of time, thanks!

pichillilorenzo commented 3 years ago

Could you share some URL that gives you these log messages? Also, if you can, please share just your WebView code implementation with options and methods/events you are using, otherwise I can do nothing to test if there is something wrong on my plugin or in your specific code.

pichillilorenzo commented 3 years ago

However, 1/2 Mbps is very very low internet connection. For example with my smartphone I can reach ~100 Mbps, instead with my internet home connection I can reach up to ~170/180 Mbps. Are you sure is just 1/2 Mbps?

ycv005 commented 3 years ago

Hey, Is it fine to share on gmail? Also, I have shared my app link.

Also, I was saying 1 or 2 MBps...here zoomed screenshot from video

https://photos.app.goo.gl/bjmmqKbr1qpstoyr8

Also, I am facing this issue after plugin update, i exactly don't remember after what version this start occurring.

pichillilorenzo commented 3 years ago

Wherever you want. If you post here, you could help more people. You don’t need to share your App code, just how you use my webview plugin to replicate the issue (if it is an issue). However the message logs you see is not related to my plugin but on AdMob https://stackoverflow.com/questions/62284590/what-is-d-audiomanager12346-getstreamvolume-isrestricted-mode-0-in-flutter

bdlukaa commented 3 years ago

Does this issue happen when in release mode?

ycv005 commented 3 years ago

@pichillilorenzo I think it is not related to Admob, even I have commented out the all Admob's related code, still facing same issue.

@bdlukaa , yes, it is happening release as well. here are the tried url and code as well - https://gist.github.com/ycv005/5eaff4661a6d24b00327897d58b44c01

pichillilorenzo commented 3 years ago

Thanks, I will take a look at it as soon as possible! In the meantime, you can help me trying the different versions of the plugin and tell me the plugin version when exactly you see this issue happening.

ycv005 commented 3 years ago

You can consider top 5(nearly) latest plugin version. I think it may be introduce after swipe to reload.

pichillilorenzo commented 3 years ago

Then could you test it? Thanks. These days I’m not able to work on it.

ycv005 commented 3 years ago

Ya, I would test it and your guidance will make it much faster.

ycv005 commented 3 years ago

Here is any other logs. @pichillilorenzo

I/flutter (25008): here in single_app with url- https://www.flipkart.com/the-gift-card-store & useragent- Mozilla/5.0 (Linux; Android 10; RMX1851 Build/QKQ1.190918.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.105 Mobile Safari/537.36

D/WindowManager(25008): Add to mViews: android.widget.FrameLayout{a76758f V.E...... ......I. 0,0-0,0}, this = android.view.WindowManagerGlobal@303d4b8,pkg= com.example.tbo
I/Choreographer(25008): Skipped 1 frames!  The application may be doing too much work on its main thread.
D/DynamitePackage(25008): Instantiating com.google.android.gms.ads.ChimeraAdManagerCreatorImpl
I/Ads     (25008): Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("1A1A252201F28BC29EF51A5B1ECB36E7")) to get test ads on this device.
I/AudioManager(25008): In isSpeakerphoneOn(), calling application: com.example.tbo
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=16, streamType=2
D/ColorExSystemServiceHelper(25008): checkColorExSystemService className = com.google.android.gms.ads.cache.CacheBrokerService
I/Choreographer(25008): Skipped 4 frames!  The application may be doing too much work on its main thread.
D/ColorExSystemServiceHelper(25008): checkColorExSystemService className = com.google.android.gms.ads.AdRequestBrokerService
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->putObject(Ljava/lang/Object;JLjava/lang/Object;)V (greylist, linking, allowed)
I/m.example.tb(25008): NativeAlloc concurrent copying GC freed 5997(814KB) AllocSpace objects, 5(116KB) LOS objects, 26% free, 11MB/15MB, paused 94us total 118.028ms
I/Choreographer(25008): Skipped 1 frames!  The application may be doing too much work on its main thread.
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->getInt(Ljava/lang/Object;J)I (greylist, linking, allowed)
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
I/DynamiteModule(25008): Considering local module com.google.android.gms.ads.dynamite:0 and remote module com.google.android.gms.ads.dynamite:210402101
I/DynamiteModule(25008): Selected remote version of com.google.android.gms.ads.dynamite, version >= 210402101
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
I/Choreographer(25008): Skipped 1 frames!  The application may be doing too much work on its main thread.
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->putInt(Ljava/lang/Object;JI)V (greylist, linking, allowed)
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->putLong(Ljava/lang/Object;JJ)V (greylist, linking, allowed)
3
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
D/DynamitePackage(25008): Instantiating com.google.android.gms.ads.ChimeraAdManagerCreatorImpl
I/Ads     (25008): Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("1A1A252201F28BC29EF51A5B1ECB36E7")) to get test ads on this device.
I/AudioManager(25008): In isSpeakerphoneOn(), calling application: com.example.tbo
2
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
D/DynamitePackage(25008): Instantiating com.google.android.gms.ads.ChimeraAdManagerCreatorImpl
I/Ads     (25008): Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("1A1A252201F28BC29EF51A5B1ECB36E7")) to get test ads on this device.
I/AudioManager(25008): In isSpeakerphoneOn(), calling application: com.example.tbo
2
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=16, streamType=2
I/Choreographer(25008): Skipped 2 frames!  The application may be doing too much work on its main thread.
2
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
W/Ads     (25008): Not retrying to fetch app settings
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->putObject(Ljava/lang/Object;JLjava/lang/Object;)V (greylist, linking, allowed)
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
I/Choreographer(25008): Skipped 2 frames!  The application may be doing too much work on its main thread.
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
I/DynamiteModule(25008): Considering local module com.google.android.gms.ads.dynamite:0 and remote module com.google.android.gms.ads.dynamite:210402101
I/DynamiteModule(25008): Selected remote version of com.google.android.gms.ads.dynamite, version >= 210402101
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->getInt(Ljava/lang/Object;J)I (greylist, linking, allowed)
I/Choreographer(25008): Skipped 1 frames!  The application may be doing too much work on its main thread.
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->putInt(Ljava/lang/Object;JI)V (greylist, linking, allowed)
W/m.example.tb(25008): Accessing hidden method Lsun/misc/Unsafe;->putLong(Ljava/lang/Object;JJ)V (greylist, linking, allowed)
9
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
I/m.example.tb(25008): NativeAlloc concurrent copying GC freed 35936(2789KB) AllocSpace objects, 28(1168KB) LOS objects, 25% free, 11MB/15MB, paused 576us total 115.901ms
2
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3
I/Choreographer(25008): Skipped 1 frames!  The application may be doing too much work on its main thread.
2
D/AudioManager(25008): getStreamVolume packageName=com.example.tbo, index=5, streamType=3

this is just a repeated logs which is very large. Also, Now I am start loading Ads when only and only OnLoadStop is called that is website is loaded fully.

bdlukaa commented 3 years ago

I also get these logs, but they're not a problem I think. I have these logs since the first version of the plugin native_admob_flutter. It doesn't happen in release mode

ycv005 commented 3 years ago

@bdlukaa how could you check logs or output in release version ?

bdlukaa commented 3 years ago

how could you check logs or output in release version ?

flutter run --release

pichillilorenzo commented 3 years ago

Yes, probably commenting out or not the Flutter/Dart code about the AdMob plugin does nothing because however it is added as a plugin from the Java native side so I think it will make some sort of AdMob initialization.

However, I think I found your problem. You are using the onLoadStart and onLoadStop events to track and detect when you need to dispose the Circle progress indicator (your LoadingCircle widget).

This works if the user is not moving through other web pages of a Single Page Application (SPA), such as web apps made with Angular, React js, etc, or if it is just replacing the current HTML content using AJAX or something like this.

The onLoadStart and onLoadStop events are called when there is an effective loading of the webpage and not just route change or HTML change. For example, using the URL https://www.flipkart.com, when the WebView is loaded the first time, they are called, but when the user is moving to another page, these events won't be called because of how the website is developed. Single Page Applications, using their router service/component will change the URL but they don't make a new webpage request (as you would have years ago when the concept of SPA didn't exist and rendering was done server-side). They, probably, will change the history of the WebView using the JavaScript History API.

To detect URL changes made this way, you should use the onUpdateVisitedHistory event.

So, this is something related to the website itself (on how the developers developed that website) and not of this plugin. Some websites will work this way, some others will work in another way. This is website-dependent, so you should check better on how to manage each website you are showing in your App.

Here is my test code:

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();

  if (Platform.isAndroid) {
    await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
  }

  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {

  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController? webViewController;
  InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
    android: AndroidInAppWebViewOptions(
      disableDefaultErrorPage: true,
      useHybridComposition: true,
      supportMultipleWindows: true,
      cacheMode: AndroidCacheMode.LOAD_DEFAULT,
    ),
    crossPlatform: InAppWebViewOptions(
      cacheEnabled: true,
      mediaPlaybackRequiresUserGesture: false,
      horizontalScrollBarEnabled: false,
      userAgent: "Mozilla/5.0 (Linux; Android 10; RMX1851 Build/QKQ1.190918.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.105 Mobile Safari/537.36",
      useShouldOverrideUrlLoading: true,
      verticalScrollBarEnabled: false,
      javaScriptCanOpenWindowsAutomatically: true,
    ),
  );

  String url = "";
  double progress = 0;
  final urlController = TextEditingController();

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(title: Text("Website test")),
          body: SafeArea(
              child: Column(children: <Widget>[
                TextField(
                  decoration: InputDecoration(
                      prefixIcon: Icon(Icons.search)
                  ),
                  controller: urlController,
                  keyboardType: TextInputType.url,
                  onSubmitted: (value) {
                    var url = Uri.parse(value);
                    if (url.scheme.isEmpty) {
                      url = Uri.parse("https://www.google.com/search?q=" + value);
                    }
                    webViewController?.loadUrl(
                        urlRequest: URLRequest(url: url));
                  },
                ),
                Expanded(
                  child: Stack(
                    children: [
                      InAppWebView(
                        key: webViewKey,
                        initialUrlRequest:
                        URLRequest(url: Uri.parse("https://www.flipkart.com/")),
                        initialOptions: options,
                        onWebViewCreated: (controller) {
                          webViewController = controller;
                        },
                        onLoadStart: (controller, url) {
                          print("onLoadStart $url");
                          setState(() {
                            this.url = url.toString();
                            urlController.text = this.url;
                          });
                        },
                        androidOnPermissionRequest: (controller, origin, resources) async {
                          return PermissionRequestResponse(
                              resources: resources,
                              action: PermissionRequestResponseAction.GRANT);
                        },
                        shouldOverrideUrlLoading: (controller, navigationAction) async {
                          final Uri? uri = navigationAction.request.url;
                          final String url = uri.toString();
                          if (url.startsWith("https://play.google.com/") ||
                              url.startsWith("http://play.google.com/")) {
                            if (await canLaunch(url)) {
                              await launch(url);
                            } else {
                              print("unable to launch");
                            }
                            return NavigationActionPolicy.CANCEL;
                          } else if (!url.startsWith("http")) {
                            if (!url.startsWith("intent")) {
                              // Constants.launchUrl(url);
                            }
                            return NavigationActionPolicy.CANCEL;
                          }
                          return NavigationActionPolicy.ALLOW;
                        },
                        onLoadStop: (controller, url) async {
                          print("onLoadStop $url");
                          setState(() {
                            this.url = url.toString();
                            urlController.text = this.url;
                          });
                        },
                        onLoadError: (controller, url, code, message) {
                          print("onLoadError: $code, $message ");
                        },
                        onLoadHttpError: (controller, uri, statusCode, message) async {
                          print("onLoadHttpError: $statusCode, $message");
                        },
                        onProgressChanged: (controller, progress) {
                          print("onProgressChanged $progress");
                          setState(() {
                            this.progress = progress / 100;
                            urlController.text = this.url;
                          });
                        },
                        onUpdateVisitedHistory: (controller, url, androidIsReload) {
                          print("onUpdateVisitedHistory $url");
                          setState(() {
                            this.url = url.toString();
                            urlController.text = this.url;
                          });
                        },
                        onConsoleMessage: (controller, consoleMessage) {
                          print(consoleMessage);
                        },
                      ),
                      progress < 1.0
                          ? LinearProgressIndicator(value: progress)
                          : Container(),
                    ],
                  ),
                ),
                ButtonBar(
                  alignment: MainAxisAlignment.center,
                  children: <Widget>[
                    ElevatedButton(
                      child: Icon(Icons.arrow_back),
                      onPressed: () {
                        webViewController?.goBack();
                      },
                    ),
                    ElevatedButton(
                      child: Icon(Icons.arrow_forward),
                      onPressed: () {
                        webViewController?.goForward();
                      },
                    ),
                    ElevatedButton(
                      child: Icon(Icons.refresh),
                      onPressed: () {
                        webViewController?.reload();
                      },
                    ),
                  ],
                ),
              ]))),
    );
  }
}

Here is the screen recording of my test:

https://user-images.githubusercontent.com/5956938/113699071-66b0df00-96d5-11eb-9a89-1300f1b6934e.mov

ycv005 commented 3 years ago

Hey @pichillilorenzo thanks for the effort. Also, I understand that what you say. But I was using onLoadStart and onLoadStop from long time & didn't face till now knowing that this website didn't called both function (onLoadStart and onLoadStop) everytime. The video which I have uploaded is basically takes long load on very first load. Like I open webview 10 times (all first time), out of which 8-9 times is fine and 2-1 time stuck in loading. I am not facing any issue after the website is loaded for first time. Problem like either occur on first time or didn't occur any time.

Also, I could I track, how much internet does a website takes on a single load.

pichillilorenzo commented 3 years ago

Could you track your scenario in some way? Print to the console events to track if they got called or not. If you listen to the onProgressChanged, onLoadStart, and onLoadStop events, do they get called also when the website takes a lot of time to load? It doesn't make any sense to me that most of the time it gets loaded "fast" and sometimes gets a lot of time to load. If they get called, maybe it's the website itself that, at a specific moment, cannot handle these requests (maybe too much work on their server-side) so you are experiencing this delay.

Have you tried also to load other websites? https://google.com/, https://github.com/, https://flutter.dev/?? If it works with other websites, I think it is related to the specific website.

Also, if you test https://www.flipkart.com/ using my code example above, does it work every time or are you experiencing the same issue? Because if it works with my simple code example, then you could have something else in your codebase that is delaying, for some reason, the load of the website (maybe other HTTP requests to your online services, downloading something, etc.).

ycv005 commented 3 years ago

Ok, I am checking all the stuff @pichillilorenzo . Also, can we debug the memory and network request while using webview on Flutter DevTools. I am checking and here is the empty logs in the Network request page

image

And here are the some logs in the memory request page.

image

pichillilorenzo commented 3 years ago

Ok! But if you listen to the onProgressChanged, onLoadStart, and onLoadStop events, do they get called also when the website takes a lot of time to load?

Also, did you test https://www.flipkart.com/ using my code example above? with my code example does it work every time or are you experiencing the same issue? Because if it works with my simple code example, as I said, maybe there is something else in your codebase that causes this issue or, simply, it's the website itself that, at a specific moment, cannot handle these requests quickly.

Please make these tests otherwise I cannot help you more than this. Thanks

ycv005 commented 3 years ago

I have checked using your code as well, problem I faced the same. Also, I have test on Realme 3 pro and Redmi K20 pro, situation was same. Out of 15 times, 1-2 times this occur. (It occurence frequency changes time to time but not much).

Yes, when the website takes lot of time, onProgressChanged is being listened and surprisingly it always stop at 10 in case when website loading stuck. (Note- In general this doesn't happen. This happen 1-2 times out of 15 times).

So, only onProgressChanged is called whereas onLoadStart and onLoadStop is not called. Also, I might forgot to add, that this is happening on more than 1 domain.

Here is the video - https://photos.app.goo.gl/LzABSyFc7EjboNwz5. One thing again to note from this video that is, if it get stuck and then I press refresh button, it then went to onLoadStop state that's why it show me that 'time taken to load 0 ms & 0 sec'.

I/flutter (14866): here is the mainUrl- https://in.bookmyshow.com/
D/EgretLoader(14866): EgretLoader(Context context)
D/EgretLoader(14866): The context is not activity
I/flutter (14866): here onWebViewCreated is called
I/flutter (14866): here onProgressChanged 10
W/ContentCatcher(14866): Failed to notify a WebView
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 2 lines
5
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 3 lines
5
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 3 lines
3
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 5 lines
2
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 2 lines
12
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 1 line
24
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 1 line
23
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 2 lines
16
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 1 line
16
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 1 line
6
D/AudioManager(14866): getStreamVolume isRestricted mode = 0
I/chatty  (14866): uid=10623(com.example.tbo) AdWorker(Active identical 2 lines
10
D/AudioManager(14866): getStreamVolume isRestricted mode = 0

I just test this like, I open then close, then open and close. repeatly doing this (sometime opening same webview and sometime switching among them) and then after some time, I face the problem.

This problem is even faced by some user, who are using it. this mean that either I open or close suddenly many time or normaly open and close, it doesn't matter.

Here are the another video - https://photos.app.goo.gl/wzaqJAg9d8hbeVuD7 (video was very long, I have cut it. Actually, in start of the video all were loading pretty smooth and in last bookmyshow didn't load well & stuck at onProgress value -10 & both video are different see the time above in recording). Also, one thing to note from this and from above video as well that is in starting normal or high internet is consumed easily when progress reach to 10 then the internet speed goes down it may be webview stop sending request or what. I have check via mobile data as well as wifi.

I would recommed you highly to test my apk, most of the time webview is working smoothly, but didn't know why someone switch frequently or try same webview (like open then close, then open and close. repeatly), then problem occur. when I exit and open back, it works normally. Really need your help. Thanks in advance.

apk link- https://drive.google.com/file/d/1GV2qf6OKRTOfAc-VLVlR4pm4v8c87BvD/view?usp=sharing

pichillilorenzo commented 3 years ago

I installed your APK and it seems that the URL https://www.shopclues.com/electronics-offers-zone.html is not working completely (Electronic -> Shopclues). But if I put that URL inside my code example above, it gets loaded correctly. I don't know but there is something in your code that is causing the issue. From your Gists, I don't know if you are managing the reTryCount variable correctly inside the onLoadStop event.

Try to use the minimum code inside your WebView implementation or completely comment out the events until you get what is causing this issue.

pichillilorenzo commented 3 years ago

I made a simple example similar to your App and I was not able to reproduce your issue. I used a real Android 9 phone and tested it in release mode.

This is my test code example:

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();

  if (Platform.isAndroid) {
    await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
  }

  runApp(MaterialApp(home: new MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  AndroidCacheMode cacheModeSelected = AndroidCacheMode.LOAD_DEFAULT;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("Website test")),
        body: SafeArea(
            child: Column(children: <Widget>[
          Center(
            child: ElevatedButton(
              child: Text("Shopclues"),
              onPressed: () {
                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => Webpage(
                            androidCacheMode: cacheModeSelected,
                            title: "Shopclues",
                            url: Uri.parse(
                                "https://www.shopclues.com/electronics-offers-zone.html"))));
              },
            ),
          ),
          Center(
              child: ElevatedButton(
            child: Text("Flipkart"),
            onPressed: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Webpage(
                          androidCacheMode: cacheModeSelected,
                          title: "Flipkart",
                          url: Uri.parse("https://www.flipkart.com/"))));
            },
          )),
          Center(
              child: ElevatedButton(
            child: Text("BookMyShow"),
            onPressed: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Webpage(
                          androidCacheMode: cacheModeSelected,
                          title: "BookMyShow",
                          url: Uri.parse("https://in.bookmyshow.com/"))));
            },
          )),
          Center(
              child: ElevatedButton(
            child: Text("Amazon"),
            onPressed: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => Webpage(
                          androidCacheMode: cacheModeSelected,
                          title: "Amazon",
                          url: Uri.parse("https://www.amazon.com/"))));
            },
          )),
          Center(
              child: DropdownButton<AndroidCacheMode>(
            value: cacheModeSelected,
            icon: const Icon(Icons.arrow_downward),
            iconSize: 24,
            elevation: 16,
            onChanged: (value) {
              setState(() {
                cacheModeSelected = value!;
              });
            },
            items: <AndroidCacheMode>[
              AndroidCacheMode.LOAD_DEFAULT,
              AndroidCacheMode.LOAD_CACHE_ONLY,
              AndroidCacheMode.LOAD_CACHE_ELSE_NETWORK,
              AndroidCacheMode.LOAD_NO_CACHE
            ].map<DropdownMenuItem<AndroidCacheMode>>((AndroidCacheMode value) {
              return DropdownMenuItem<AndroidCacheMode>(
                value: value,
                child: Text(value.toString()),
              );
            }).toList(),
          ))
        ])));
  }
}

class Webpage extends StatefulWidget {
  String title;
  AndroidCacheMode androidCacheMode;
  Uri url;

  Webpage(
      {Key? key,
      required this.title,
      required this.url,
      required this.androidCacheMode})
      : super(key: key);

  @override
  _WebpageState createState() => new _WebpageState();
}

class _WebpageState extends State<Webpage> {
  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController? webViewController;
  late InAppWebViewGroupOptions options;
  late String url;
  double progress = 0.0;

  @override
  void initState() {
    this.url = widget.url.toString();

    this.options = InAppWebViewGroupOptions(
      android: AndroidInAppWebViewOptions(
        disableDefaultErrorPage: false,
        useHybridComposition: true,
        supportMultipleWindows: true,
        cacheMode: widget.androidCacheMode,
      ),
      crossPlatform: InAppWebViewOptions(
        cacheEnabled: true,
        mediaPlaybackRequiresUserGesture: false,
        horizontalScrollBarEnabled: false,
        userAgent:
            "Mozilla/5.0 (Linux; Android 10; RMX1851 Build/QKQ1.190918.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.105 Mobile Safari/537.36",
        useShouldOverrideUrlLoading: true,
        verticalScrollBarEnabled: false,
        javaScriptCanOpenWindowsAutomatically: true,
      ),
    );

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
            leading: IconButton(
              icon: Icon(Icons.arrow_back),
              onPressed: () {
                Navigator.pop(context, false);
              },
            ),
          ),
          body: SafeArea(
              child: Column(children: <Widget>[
            Container(
              padding: EdgeInsets.all(10),
              child: Text(
                this.url,
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
              ),
            ),
            Expanded(
              child: Stack(
                children: [
                  InAppWebView(
                    key: webViewKey,
                    initialUrlRequest: URLRequest(url: widget.url),
                    initialOptions: options,
                    onWebViewCreated: (controller) {
                      webViewController = controller;
                    },
                    onLoadStart: (controller, url) {
                      print("onLoadStart $url");
                      setState(() {
                        this.url = url.toString();
                      });
                    },
                    androidOnPermissionRequest:
                        (controller, origin, resources) async {
                      return PermissionRequestResponse(
                          resources: resources,
                          action: PermissionRequestResponseAction.GRANT);
                    },
                    shouldOverrideUrlLoading:
                        (controller, navigationAction) async {
                      final Uri? uri = navigationAction.request.url;
                      final String url = uri.toString();
                      if (url.startsWith("https://play.google.com/") ||
                          url.startsWith("http://play.google.com/")) {
                        if (await canLaunch(url)) {
                          await launch(url);
                        } else {
                          print("unable to launch");
                        }
                        return NavigationActionPolicy.CANCEL;
                      } else if (!url.startsWith("http")) {
                        if (!url.startsWith("intent")) {
                          // Constants.launchUrl(url);
                        }
                        return NavigationActionPolicy.CANCEL;
                      }
                      return NavigationActionPolicy.ALLOW;
                    },
                    onLoadStop: (controller, url) async {
                      print("onLoadStop $url");
                      setState(() {
                        this.url = url.toString();
                      });
                    },
                    onLoadError: (controller, url, code, message) {
                      print("onLoadError: $code, $message ");
                    },
                    onLoadHttpError:
                        (controller, uri, statusCode, message) async {
                      print("onLoadHttpError: $statusCode, $message");
                    },
                    onProgressChanged: (controller, progress) {
                      print("onProgressChanged $progress");
                      setState(() {
                        this.progress = progress / 100;
                      });
                    },
                    onUpdateVisitedHistory: (controller, url, androidIsReload) {
                      print("onUpdateVisitedHistory $url");
                      setState(() {
                        this.url = url.toString();
                      });
                    },
                    onConsoleMessage: (controller, consoleMessage) {
                      print(consoleMessage);
                    },
                    onCreateWindow: (controller, createWindowRequest) async {
                      showDialog(
                        context: context,
                        builder: (context) {
                          return AlertDialog(
                            content: Container(
                              width: MediaQuery.of(context).size.width,
                              height: 400,
                              child: InAppWebView(
                                windowId: createWindowRequest.windowId,
                                initialOptions: options,
                                onLoadStart: (controller, url) {
                                  print("onLoadStart popup $url");
                                },
                                onLoadStop: (controller, url) {
                                  print("onLoadStop popup $url");
                                },
                              ),
                            ),
                          );
                        },
                      );

                      return true;
                    },
                  ),
                  progress < 1.0
                      ? LinearProgressIndicator(value: progress)
                      : Container(),
                ],
              ),
            ),
            ButtonBar(
              alignment: MainAxisAlignment.center,
              children: <Widget>[
                ElevatedButton(
                  child: Icon(Icons.arrow_back),
                  onPressed: () {
                    webViewController?.goBack();
                  },
                ),
                ElevatedButton(
                  child: Icon(Icons.arrow_forward),
                  onPressed: () {
                    webViewController?.goForward();
                  },
                ),
                ElevatedButton(
                  child: Icon(Icons.refresh),
                  onPressed: () {
                    webViewController?.reload();
                  },
                ),
              ],
            ),
          ]))),
    );
  }
}

Here is the screen recording:

https://user-images.githubusercontent.com/5956938/114174659-35384d80-9939-11eb-8980-fc104b9159f4.mp4

As you can see, I don't have any issues. The app loads correctly every time the website selected.

So, I think there is something in your code that is causing some issues. Please, enable the debugging mode on Android (see https://inappwebview.dev/docs/debugging-webviews/) and check for any JavaScript error. You may have some JavaScript error that may block the website's loading.

ycv005 commented 3 years ago

Hey @pichillilorenzo thanks for the effort. I have used your class WebPage(its all code) replacing my class. But sadly, I still facing issue. This time I have recorded video using your code. (link- https://photos.app.goo.gl/gpbTKDNhQELas8xeA)

Thanks for the debugging info. I have checked and found the console is empty totally some time & some time few response or msg were written when website got stuck loading. How can I check for the JavaScript error, other than checking console? I didn't excecute any JS code in my code and even it is not used in your code that I am using.

Does, behind my code, any other JS are executed ?

If my old code would have an issue, then why did the same issue occur in your code as well ? I would share any info related to this, please let me know.

pichillilorenzo commented 3 years ago

Nope, what I mean is that you need to try only my code and not use my code inside your app. Just use only my code example App as on my video recording! If my App example works, then there is something else in your code that I don’t know that is causing it. Please, test only my code. Just create a new example project with that code.

ycv005 commented 3 years ago

ok, I will do the same exactly. Also, may you tell me how to avoid any kind of JS error that cause website loading.

pichillilorenzo commented 3 years ago

I don’t know. It could be specific to the website itself or any code you are injecting in it eventually.

ycv005 commented 3 years ago

Hey @pichillilorenzo , I have regrously tested your code into the newly created project, that only consist of your code and I have found the same issue happening. (Note- Additional to your code, I have just added few more website that's it) Here is the long video- https://photos.app.goo.gl/ukWCAZNP6MQRCbeF6

pichillilorenzo commented 3 years ago

Ok, so I think that it could be related to an issue where the WebView, sometimes, is not able to load the request as soon as the WebView is added to the native Android View tree. Taking the example from this answer https://stackoverflow.com/a/60863225/4637638 on StackOverflow, if you postpone the loading of the URL inside the onWebViewCreated event, does it work?

Try to delete the initialUrlRequest property and load the widget.url inside the onWebViewCreated event:

InAppWebView(
  key: webViewKey,
  initialOptions: options,
  onWebViewCreated: (controller) async {
    webViewController = controller;
    await controller.loadUrl(urlRequest: URLRequest(url: widget.url));
  },

then try again to see if it could work.

If it doesn't work either, try postponing the load URL a little bit this way:

InAppWebView(
  key: webViewKey,
  initialOptions: options,
  onWebViewCreated: (controller) async {
    webViewController = controller;
    await Future.delayed(Duration(milliseconds: 500));
    await controller.loadUrl(urlRequest: URLRequest(url: widget.url));
  },

Does it work using one of these two ways?

ycv005 commented 3 years ago

Hey @pichillilorenzo thanks for it. I will try and let you know.

Also, it seems to be work around, is there any correct solution?

pichillilorenzo commented 3 years ago

If it works, I can consider to add this workaround to the native side. Unfortunately, this is a behaviour of the Android native WebView and I cannot do much about it if it works this way. However, if it works, I will try to understand this behaviour better to find a better solution on the native side.

pichillilorenzo commented 3 years ago

Here is other links related to this problem:

ycv005 commented 3 years ago

1st Method

InAppWebView(
  key: webViewKey,
  initialOptions: options,
  onWebViewCreated: (controller) async {
    webViewController = controller;
    await controller.loadUrl(urlRequest: URLRequest(url: widget.url));
  },

with this method, a blank white screen seems to loaded very first, as when I exiting by hitting back button, it appears everytime in a webview.

and 2nd Method is not even working, nothing is loading.

Still testing the 1st method- that previous error is coming or not. Have a try on your self @pichillilorenzo

github-actions[bot] commented 1 week ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug and a minimal reproduction of the issue.