6

I have a very complex Cordova app on Android that I have developed over a period of over a year. The app uses one custom, i.e written by me, Cordova plugin. A I consider a port of the app to iOS I am contemplating switching to Flutter in order to have just the one codebase to maintain - failing that the whole of the plugin will have to be rewritten for iOS.

With clean HTML5 + ES6 + CSS3 it works remarkably well and I see no reason to throw it all out and start all over again as a pure Flutter app. Enter WebViews. I am planning to use all of my current Cordova Webview code - essentially the whole of the Cordova project www folder - in a WebView in flutter. Key to this all is being able to efficiently communicate bidirectionally between the WebView and Flutter. To that end I have written up a small skeleton project. The main.dart file for that project is shown below

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'package:webview_flutter/webview_flutter.dart';

void main() => runApp(Webby());

class Webby extends StatelessWidget 
{
 @override Widget build(BuildContext context) 
 {
  return MaterialApp
  (
   title: 'Flutter Demo',
   theme: ThemeData(primarySwatch: Colors.blue,),
   home: Feuille(),
  );
 }
}

class Feuille extends StatefulWidget
{
 Feuille({Key key}):super(key: key);
 @override  _FeuilleState createState() => _FeuilleState();
}

class _FeuilleState extends State<Feuille>
{
 WebViewController wVC; 
 @override Widget build(BuildContext context) 
 {
  SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);  
  return Scaffold
  (
   body:SafeArea
   (
    child:Column
    (
     children:<Widget>
     [
      Expanded
      (
       child:Container
       (
        margin:const EdgeInsets.all(0.0),
        child:WebView
        (
         debuggingEnabled:true, 
         initialUrl:'',
         javascriptMode:JavascriptMode.unrestricted,
         onWebViewCreated:registerController,
         javascriptChannels:Set.from
         ([JavascriptChannel(name:'JSBridge',onMessageReceived:handleMessage)]),
        ),),)])));
 }

 Future<void> handleMessage(JavascriptMessage message) async
 {
  print(message.message);
  wVC.evaluateJavascript("addNums(10,21)");
 }

 void registerController (WebViewController controller) async
 {
  wVC = controller;
  String html = await rootBundle.loadString('assets/index.html');
  wVC.loadUrl(Uri.dataFromString(html,mimeType:'text/html',
  encoding:Encoding.getByName('utf-8')).toString());
 }
}

The local HTML that is loaded into this webview is shown below

<!DOCTYPE html>
<html>
 <head>
  <meta name='viewport'
   content='user-scalable=no, initial-scale=1, maximum-scale=1, 
   minimum-scale=1, width=device-width, height=device-height' />
   <meta charset='utf-8' />
 </head>  
 <body>
  <p>The result is <span id="spnResult">Not Available Yet</span></p> 
 </body>
 <script>
   window.addEventListener("load",flutterReady);

   function flutterReady()
   {
    alert("Sending message");
    setTimeout(function(){JSBridge.postMessage("This is London calling");},5000);
   } 

   function addNums(n1,n2)
   {
    document.getElementById("spnResult").innerText = n1 + n2;
   }
  </script>
</html>

Finally the pubspec.yaml file for the project is as follows

name: webby
description: Webby Project

version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
 flutter:
  sdk: flutter

 cupertino_icons: ^0.1.2
 path_provider: ^1.4.0
 permission_handler: ^3.3.0
 connectivity: ^0.4.5+6
 webview_flutter: ^0.3.19+9

dev_dependencies:
 flutter_test:
 sdk: flutter


flutter:
 uses-material-design: true
assets:
  - assets/

Now my questions

  • I am using this skeleton project to test if I can communicate bidirectionally: from Webview hosted JS to Flutter and from Flutter back to Webview hosted JS. This works - very well. However, there are things I have done here quite blindly - this is my second day with Flutter - which need clarification

  • I have used the window.load event in HTML5 to know when I start communicating with Flutter. This is my replacement for the Cordova.docReady event. Is it reasonable to assume that when this event occurs Flutter will be "ready", the WebViewController will be availbale etc?

  • In my effort to get the WebView to occupy the entire device screen I have ended up using Scaffold...SafeAera...Expanded... quite simply because I ran into this being used to show a full screen image and it worked for me. However, it is not clear to me that this is the best way/right way to do things

  • I note that pubspec.yaml specifies the use of Material Design and the "Widget" being created here is a MaterialApp. Given that the whole of my UI is created and managed through HTML5 + CSS3 + ES6 in the WebView is there not a simpler way to create the widget that might entail some performance/memory footprint benefits

  • I have come across comments to the effect that WebView is slow, does not render well on iOS etc. In my experience people who make such comments typically tend to rely on "frameworks" that impose an unnecessary burden on the system. With clean HTML + ES6 that relies only on the HTML5 DOM as its "framework" performance has never been an issue to me. Is there any known reason why the Flutter WebView (which is ultimately the OS supplied WebView) should underperform?

  • And finally: Once I have got this nailed down I need to start implementing GeoLocation, Wifi network watching, accelerometer monitoring, websocket driven I/O, local file storage, SQLite database storage etc. Are the APIs provided by Fluter up to these tasks - and are they adequately OS agnostic to truly generate apps for both Android and iOS?

I'd be most grateful to anyone who might be able to provide some tips and pointers here.


I am not sure I am ever going to get a response here. However, a footnote for anyone running into this thread and attempting to copy what I have done thus far.

Quite simply - this will not work. Using Uri.dataFromString(... will allow you to show a static HTML document with embedded styles and JS. It will not be able to access stylesheets and scripts stored in other files/folders inside your Flutter assets folder. In order to do that you need to run a local HTTP server. While you could try to spin your own it isn't worth doing. Consider using the excellent, and well documented, flutter_inappwebview plugin instead.

6
  • Why on earth would you try to redo Cordova inside Flutter if you cordova app works? I don't get it... Commented Mar 19, 2020 at 15:25
  • Given the number of different APIs I use ensuring that I stay on top of them all in two different OSs will be a never ending battle. I do this with Android already. The system keeps evolving, methods that worked get deprecated... . Fighting that battle on two fronts on a continual basis is a lot to do. I want to see if using Flutter API wrappers makes the task more manageable. Commented Mar 19, 2020 at 15:40
  • So basically, you want to ditch the Cordova plugin system in favor of Flutter API? Commented Mar 19, 2020 at 17:23
  • Correct - at least I want to try it out so I can decide whether it will read to a flatter development curve than having to write, and maintain, a Cordova plugin that uses geolocation, sensors, SQLite, websockets... in iOS and in Android. Android, for instance, has been making it harder and harder to keep an app running. Background services got ejected in favor of JobService and that in turn in favor of WorkManager. Not easy to keep up. Commented Mar 19, 2020 at 18:50
  • What do you mean by write plugins? Most of the popular plugins are maintained (geo, sensors, sql etc) so that's where I don't get your requests... Interesting idea though. Commented Mar 19, 2020 at 19:24

1 Answer 1

1

From what I understand, it seems that you'd just like to display your webpage using WebView on Flutter. If you need access to geolocation support on a WebView, webview_flutter has still this issue open. As a workaround, you may want to consider using flutter_inappwebview in the meantime. As for handling WebView callbacks on Flutter, here's an interesting guide that you can use as a start.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this answer @Omatt. I had figured out the issues involved a while ago. Nevertheless, the link to that guide you provide has proven to be useful reading. I was not in fact aware of Web Message Listeners/Channels.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.