DroidOS
DroidOS

Reputation: 8900

Using Webviews in Flutter

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'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.

Upvotes: 6

Views: 2146

Answers (1)

Omatt
Omatt

Reputation: 10519

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.

Upvotes: 1

Related Questions