Flutter InappWebView canGoBack - no implementation found for method - flutter

I am developing navigation to the previous pages for my flutter browser app, and to do this I am using goBack and goForward methods of InAppWebViewController.
To check whether I can go back (to change color of navigation buttons) I also call canGoBack method. As it returns Future, I am using FutureBuilder to display these icons.
I propagate canGoBack() or canGoForward() to the future field of FutureBuilder. And then a lot of strange thigs happen: sometimes when I switch between different tabs (which work similar to tabs in https://github.com/pichillilorenzo/flutter_browser_app) I receive:
MissingluginException: No implementation for method canGoForward on channel com.pichillilorenzo/flutter_inappwebview_n, where n is some number
Bug usually occur when I pop back to the widget with buttons and InAppWebView from tabs page.
I've searched all related github issues and haven't found anything related, tested on android(emulator + real device), iOS (simulator + real device) - and I cannot even see the pattern of how to reproduce this bug.
So, I have several questions:
What may be the reasons for this to happen? At first glance, it happens at random moments
What 'channel' exactly means here? I would be glad to read more about that
May it be caused because I use FutureBuilder?

Related

Flutter detect PointerEvents over Widget

I have a sample code which detects a hovering stylus over a widget.
The code is from this Stackoverflow Quesion.
In short. It binds using GestureBinding.instance?.pointerRouter.addGlobalRoute and checks in the handler if the event is of type stylus.
This gets triggered when the stylus is hovering over the screen (no contact).
It works great on Widgets like Text(), Container() etc.
Question:
I want to use this functionality on a different Widget, the Flutter InAppWebView but the event will not get triggered until the pen has contact with the surface. Even on the Container it does not work, if the child is the InAppWebView.
I think this problem will occur on other Widgets too.
I tried the Listener, AbsorbPointer and IgnorePointer.
Update 1:
I can see the following in the debug output when I start hovering the stylus over the screen.
I/ViewRootImpl(23491): updatePointerIcon pointerType = 20001, calling pid = 23491
D/InputManager(23491): setPointerIconType iconId = 20001, callingPid = 23491
Update 2:
The InAppWebView has an option useHybridComposition which is false by default. Setting it to true solves the issue. But the WebView is becoming very slow.
HERE is a repository that shows the problem.
Thanks!
EDIT
As desribed below, this question has two solutions.
Set useHybridComposition to true. For slowness, maybe raise an issue to that repo.
Hook at android/ios level instead of Flutter level, and forward events back to Flutter.
The debugging method maybe like this: Firstly, print out the pointer events in methods like your _handleEvent. Then you will know whether the pointer event just occur, or they even do not occur.
Secondly, try what widgets are OK and what are not. Text is OK, WebView is not. Then is Container OK? Is InkWell OK? Is IconButton OK? Is IconButton OK? etc. By doing this you gain insight of what is special about Text that makes it work.
Thirdly, as a hacky workaround, could you please try Text.rich(WidgetSpan(child: your_web_view))? Since you say Text is OK while other widgets are not OK.
Lastly, maybe need to dig into Text's source to see what magic happens - probably some special configuration? - to let it work.

Web view is too slow

Web view takes more than 4 sec to load the webpage. The same page takes less than 2 sec in Native app. Is there a way to speedup the load time. I tried both Official webview_flutter and flutter_webview_plugin.
If you app relies on WebView, just choose other tools: Swift for iOS & Kotlin for Android.
Here is why:
WebView actually does not load pages slow. Instead, creating the WebView widget is slow;
In order to solve 1, you might want use a cached WebView. Unfortunately, that is not easy. Layout changes (e.g. animation) might trigger a WebView "recreating" (the cached WebView becomes invalid/staled). And the "recreating" is very slow;
Flutter's widgets depend on "state" outside of the widgets, and widgets' creating are supposed to be fast/simple. Unfortunately, WebView (which is not a native widget) is not the case. WebView has its complex internal "state", a recreation simple discard everything and you returns to the WebView's initial state (initial URL). And it is very slow (Creating time + LoadTime: Network overhead);
It is very hard to create a "external state" outside a WebView, therefore after a WebView's recreating it cannot resume from the external state;
Since WebView's recreating is very slow, it totally kills animation and gives user a very bad experience. A solution might be put a WebView as your main page and never try to animate to a new WebView (just like a Wiki App Demo in YouTube).
Conclusion:
So, now, WebView in flutter is not ready and please don't consider use it seriously.
Discussion:
Flutter's widgets design is quite "unusual" since they are basically immutable. States outside widgets (external state) are used. When state changes, instead of modify the widget, Flutter choose to create a new widget based on the new state. Therefore, widgets are deigned to be light weighted so they can be created/destroyed very quickly. Unfortunately, WebView cannot fall into this category. WebView is as complex as the whole Flutter framework, so it cannot be a native widget but a plug-in. And WebView has its own internal state which is not compatible with the framework, which results in keep on being destroyed/recreated by the framework.
I am not sure why Flutter's widgets are designed in this way, maybe it is easier/faster for creating the framework? I saw some complex examples (~100 lines) using Redux/BLOC/Steam just in order to "change" a widget, which might just need a one-line of code in other frameworks.
Performance is also an issue. Rebuild a complex widgets tree is slow. Then you need writing a lot of code (Redux/BLOC/Stream/ScoppedModel...) in order to implement a partial widgets tree build.
Even for a very simple app, performance of Flutter is still not as good as native (https://thoughtbot.com/blog/examining-performance-differences-between-native-flutter-and-react-native-mobile-development). In fact, I'd like considering Flutter as "native" since it is compiled into machine code instead of Java's ByteCode.
Finally:
I am a new Flutter learner and start playing with Flutter for a couple of weeks. The widgets framework and the WebView plug-in just made me headache. A lot of time spent on the UI interface instead of the core logic of my app.
I am not saying Flutter is not good. Actually, I think it is the best cross-platform framework for iOS/Android. It just might be something (e.g. complex external widget like WebView) was not being taken into consideration while the framework was being designed. Hope the Flutter team can find a solution for this, maybe a special case for handling a complex external plug-in?
I will keep on learning/playing with Flutter.
And now Hybrid-Composition is default in webview_flutter 3.0.0:
https://pub.dev/packages/webview_flutter/changelog
Just tried it on my side and since it's not perfect, it's much more faster
cheers!
Updated to webview_flutter 1.0.x and adopted Hybrid-Composition. It performances much better on Android now.
Announcement: announcing-flutter-1-22-44f146009e5f
How to: webview_flutter
Docs: Hybrid-Composition

Positioning a sap.m.list

I'd like to create a twitter like stream out of a sap.m.list, hence when I get more data with a pulltorefresh control, I'd like to update the list with the additional rows, but should not move the list at all, and be hidden until the user scrolls the list down.
Any standard ways of doing this, or alternatively, custom CSS/JS recommended ways of doing this?
Thanks,
Matt
There's no need to drop down to jQuery here as OpenUI5 already contains the awesome iScroll library.
I've just setup a test app for you to have a look at here: https://github.com/js1972/ui5_pull_to_refresh.
Clone this; check the readme; then just run grunt serve to open the app in your default browser. You can use Chrome dev tools to emulate an iphone or android, etc.
I think this does what you're after - it works just like the GMail mobile app. You pull down to refresh items and at the end of the refresh your still looking at the same items but can now scroll up to see the new ones.
Will be interesting to see the performance if you have a thousand items... iScroll gives you allot of settings to play that may help (which aren't discussed in the UI5 SDK).
One thing to be careful of with browser scrolling is paint times. If the browser is not 100% done painting then iScroll can't calculate all the element dimensions it needs and you get strange results - typically just no scrolling. Sometimes you've just got to give a little time back to the browser by wrapping things in setTimeout(scroll_stuff, 0).
Hope this helps...
While not quite the answer I was after, looked into doing it another way, and provided you can work with automatically generated Id's that you'll need to calculate based on the row number, the following is one brute force way of doing it (I've borrowed it from another SO question and kept the animation for fun - Referenced SO Link):
var pOffset = $("#__item0-App--Main--MyList-76").position().top;
$("#App--Main--myPage-cont").animate({scrollTop: ( pOffset)}, 800);

gwt - history - how to "keep" UI state

I tried the example which is showing how to get data from history to re-generate UI; The thing I see mostly in all "history usage" examples are related to UI re-generation only so it is none-static way...
But what about "each UI state may have its unique url something like JSF does with flows"? For example I have app url like a
http://localhost:8080/myapp/MyApp.html
the app default UI contains main menu which is helping to navigate through my test catalog; I tried to make possible keep the UI dynamics in history by building url in this way
http://localhost:8080/myapp/MyApp.html#menu_testcategory_page1
but when I click internet browser "refresh" button the url keeps the same as http://localhost:8080/myapp/MyApp.html#menu_testcategory_page1 but the UI comes back to its default state :(
So my question is
is there an optimal way in pure gwt to stay in the same UI state even after browser's refresh button is clicked (I mean the unload/load window events occur)?
thanks
P.S. gwt 2.3
You should implement Activities and Places pattern: http://www.gwtproject.org/doc/latest/DevGuideMvpActivitiesAndPlaces.html
I am using it for 3 years, and it works very well.
Note, however, that when you reload a page, you lose all of your state, data, etc. If you need to preserve some of it, you can use a combination of a Place (#page1) and a token that tells the corresponding Activity the state of the View representing this Place, i.e. (#page1:item=5).
You probably just forgot to call
History.fireCurrentHistoryState();
from your entry point.

MonoTouch.Dialog Elements can be null when search bar used too quick

I have a DialogViewController with many elements and a search bar. When a user taps between the search bar and the cancel button fast, the Elements node of the Section in the following MonoTouch.Dialog.Elements.cs code is sometimes null so it throws an error and the app is torn down by the OS. Is there a work around?
From Elements.cs, latest Git version. Only happens on a real device.
To turn this into an answer - I think this is a bug.
I have filed it at:
https://github.com/migueldeicaza/MonoTouch.Dialog/issues/94
And produced a sample which reproduces the bug at:
https://github.com/Macropus/Bug-Reports/blob/master/BugReport94/BugReport94/AppDelegate.cs
I think it may be a threading synchronisation issue where the thread is trying to access the Root.Elements but they have been removed by the Cancel button.