-1

i have an app that renders a webpage inside a webview. this actually has a bunch of crypto addresses. I want them to be automatically made clickable. and when they are clicked - i want to show a popup (some information about the addresses).

can this be done ? im very unsure if this thing about changing the UI is possible...but in desktop web world, there are extensions that do this. if there are any examples of flutter webview codebases that do this, that would be helpful

the second point - communicating back and forth with the webpage is even more confusing. can this be done at all ? can i receive the data of the click back to main flutter app and then do something ?

Sandeep
  • 1,745
  • 3
  • 20
  • 30

1 Answers1

1

Here's a working example

Flutter App demo

This is achieved as I said by Injecting Js when the webpage loads, as for communication with Flutter, I used the flutter Webview plugin provided JavascriptChannel

  • The Javascript code looks for a specific element firstly on Page load and secondly while scrolling the webpage (to account for newly created dynamic elements)

Here's how the flow works

  • JS: assigns the element a new css style (Or in your case make it look like a button) or even create a button and insert it into the webpage

  • JS: assign on click to the element to call the Flutter JS Channel.

  • Flutter: Receive message Display a snackbar - you can deeplink or do whatever you want.

As the comments on the JS code say. the scrolling behavior calls every time which is not always ideal, you can use another function make it only trigger on a specific scroll distance

Full working example

import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

dynamic ctrl;

// if you have multiple elements, just use querySelector All and loop
const jsCodeToForAnElement = """
// Choose the element

watch();

// I would add dealy to calculate delta between scrolls
// Meaning this code wont watch on every scroll
window.onscroll = watch();

function watch(){
let elm = document.querySelector("main h1");

try{
// Style it
elm.style.cssText =  "background: red";

// Add on click
elm.onclick = (event)=> {
  var walletHTMLElement = event.target;

  // Use native API to communicate with Flutter
  jsMessager.postMessage('Wallet clicked: ' +  walletHTMLElement.innerHTML);
  };
}catch(e){
    jsMessager.postMessage('Error: ' +  e);
}

}

""";

void main() {
  runApp(
    MaterialApp(
      home: WebViewExample(),
    ),
  );
}

class WebViewExample extends StatefulWidget {
  @override
  WebViewExampleState createState() => WebViewExampleState();
}

class WebViewExampleState extends State<WebViewExample> {
  @override
  void initState() {
    super.initState();

    // Enable virtual display.
    if (Platform.isAndroid) WebView.platform = AndroidWebView();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: WebView(
        initialUrl: 'https://flutter.dev/',
        debuggingEnabled: true,
        onWebViewCreated: (WebViewController webViewController) {
          ctrl = webViewController;
        },
        javascriptMode: JavascriptMode.unrestricted,
        javascriptChannels: <JavascriptChannel>{
          JavascriptChannel(
              name: 'jsMessager',
              onMessageReceived: (jsMessager) async {
                if (jsMessager.message.contains("Wallet")) {
                  var snackBar = SnackBar(
                    content: Text(jsMessager.message),
                  );
                  ScaffoldMessenger.of(context).showSnackBar(snackBar);

                  // Do Other Thing like deeplinking to crypto app
                  // Deeplink to wallet LaunchApp(wallet) <-- clean  wallet string first
                }
              }),
        },
        onPageStarted: (String url) async {
          ctrl.runJavascript(jsCodeToForAnElement);
        },
        onPageFinished: (String url) async {},
      ),
    );
  }
}

Original Answer

This would be possible by Injecting Javascript into Webviews (This is one idea)

1 - I would wait for the page to load

2 - Modify the HTML content using Javascript

Should be pretty straight forward.

Refer to this Answer to see how it is done in Flutter.

https://stackoverflow.com/a/73240357/6151564

Sal7_one
  • 427
  • 2
  • 7
  • webview injecting javascript has lot of nuances - onpageload or pageunload, etc. there are many hooks and conditions there. im not sure if that works or how to get it to work - am looking for a working answer. much thanks – Sandeep Oct 25 '22 at 11:38
  • @Sandeep Here you go! I hope you found this helpful – Sal7_one Oct 26 '22 at 08:02
  • thanks for your example. But I'm looking for text patterns and not html selectors. that was the original challenge. For example - any text element that is a ethereum wallet address like "0xb794f5ea0ba39494ce839613fffba74279579268". that is what im wondering about. – Sandeep Oct 26 '22 at 16:49
  • You literally just add this `let resp = str.match(/(\b0x[a-f0-9]{40}\b)/g)` to whatever html element you're watching (which could be the whole document body) – Sal7_one Oct 26 '22 at 18:00