init static method

WebViewController init({
  1. required bool isTour,
})

✅ Initialize WebView with full auto-size and click-channel support

Implementation

static WebViewController init({required bool isTour}) {
  final c = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..setBackgroundColor(const Color(0x00000000))
    ..enableZoom(false);

  c.setNavigationDelegate(
    NavigationDelegate(
      onProgress: (_) {},
      onPageStarted: (_) {},
      onPageFinished: (String url) async {
        try {
          print("✅ onPageFinished: $url");
          await Future.delayed(const Duration(milliseconds: 400));

          // 1️⃣ Remove scrollbars everywhere
          await c.runJavaScript('''
    document.documentElement.style.setProperty('margin','0','important');
    document.documentElement.style.setProperty('padding','0','important');
    document.documentElement.style.setProperty('overflow','hidden','important');
    document.body.style.setProperty('margin','0','important');
    document.body.style.setProperty('padding','0','important');
    document.body.style.setProperty('overflow','hidden','important');
    Array.from(document.querySelectorAll('*')).forEach(el=>{
      el.style.setProperty('overflow','hidden','important');
    });
  ''');

          // 2️⃣ Flutter JS Channel Setup (Android + iOS)
          await c.runJavaScript('''
    if (typeof window.FlutterChannel === 'undefined') {
      window.FlutterChannel = {
        postMessage: function(message) {
          try {
            if (window.MyFlutterApp) {
              window.MyFlutterApp.postMessage(message);
            }
            if (window.webkit?.messageHandlers?.FlutterChannel) {
              window.webkit.messageHandlers.FlutterChannel.postMessage(message);
            }
            console.log("FlutterChannel message:", message);
          } catch(e) {
            console.error("[Channel error]", e);
          }
        }
      };
    }
  ''');

          // 3️⃣ Universal Safe Button Handler (Android FIX)
          await c.runJavaScript(Platform.isAndroid
              ? '''
(function() {
function send(action, url) {
  const payload = JSON.stringify({ action: action, url: url || null });

  // iOS
  try {
    if (window.webkit?.messageHandlers?.FlutterChannel) {
      window.webkit.messageHandlers.FlutterChannel.postMessage(payload);
    }
  } catch(e){}

  // Android (REQUIRES MyFlutterApp)
  try {
    if (window.MyFlutterApp) {
      window.MyFlutterApp.postMessage(payload);
    }
  } catch(e){}

  // Fallback
  try {
    if (window.FlutterChannel) {
      window.FlutterChannel.postMessage(payload);
    }
  } catch(e){}
}

function attach() {
  const buttons = document.querySelectorAll("button[data-action]");
  buttons.forEach(btn => {
    if (btn.__added) return;
    btn.__added = true;

    const handler = function(e) {
      e.preventDefault();
      e.stopImmediatePropagation();

      const action = btn.getAttribute("data-action");
      const anchor = btn.closest("a");
      send(action, anchor?.href || null);
    };

    btn.addEventListener("click", handler, true);
    btn.addEventListener("touchend", handler, true);
  });
}

attach();
new MutationObserver(attach).observe(document.body, { childList: true, subtree: true });
})();
'''
              : '''
(function() {
console.log("[JS] Attaching persistent tour button listeners");

function sendToFlutter(action, url) {
  const payload = JSON.stringify({
    action: action,
    url: url || null
  });

  try {
    if (window.FlutterChannel) window.FlutterChannel.postMessage(payload);
    if (window.MyFlutterApp) window.MyFlutterApp.postMessage(payload);
    if (window.webkit?.messageHandlers?.FlutterChannel) {
      window.webkit.messageHandlers.FlutterChannel.postMessage(payload);
    }
  } catch(e) {
    console.error("[JS] Send error:", e);
  }
}

function attachListeners() {
  const buttons = document.querySelectorAll("button[data-action]");
  console.log("[JS] Found " + buttons.length + " buttons");

  buttons.forEach(btn => {
    if (btn._listenerAttached) return;
    btn._listenerAttached = true;

    const action = btn.getAttribute("data-action");

    const handler = function(event) {
      event.preventDefault();
      event.stopImmediatePropagation();

      const anchor = btn.closest("a");
      sendToFlutter(action, anchor?.href || null);
    };

    btn.addEventListener("click", handler, true);
    btn.addEventListener("touchend", handler, true);

    btn.style.cursor = "pointer";
  });
}

// Initial attach
attachListeners();

// Re-attach when DOM changes (SPA, animations)
new MutationObserver(attachListeners)
  .observe(document.body, { childList: true, subtree: true });

// Android safety fallback
setInterval(attachListeners, 600);
})();
''');

          // 4️⃣ (Optional) Debug verification
          final result = await c.runJavaScriptReturningResult('''
    (function() {
      return JSON.stringify({
        buttons: document.querySelectorAll("button[data-action]").length,
        hasChannel: typeof window.FlutterChannel !== "undefined"
      });
    })();
  ''');

          print("🔧 JS Setup Result: $result");
        } catch (e, st) {
          print("❌ Error in onPageFinished: $e\n$st");
        }
      },
      onHttpError: (error) => print("HTTP Error: $error"),
      onWebResourceError: (error) => print("Web Resource Error: $error"),
      onNavigationRequest: (NavigationRequest request) {
        return NavigationDecision.navigate;
      },
    ),
  );
  c.addJavaScriptChannel(
    'MyFlutterApp', // REQUIRED FOR ANDROID
    onMessageReceived: (JavaScriptMessage message) {
      handleJsMessage(message.message);
    },
  );
  c.addJavaScriptChannel(
    'FlutterChannel',
    onMessageReceived: (JavaScriptMessage message) {
      final data = jsonDecode(message.message);
      switch (data['action']) {
        case 'onNextStep':
          print("NEXTTTT");
          TourUtil.next();
          break;
        case 'onPrevStep':
          TourUtil.previous();
          break;
        case 'openLink':
          final url = data['url'] as String;
          Util.launchInBrowser(url);
          break;
        case 'onCloseStep':
          TourUtil.finish();
          break;
      }
    },
  );
  if (!isTour) controller = c;
  return c;
}