Search code examples
flutterdart-htmlflutter-pluginflutter-platform-channelflutter-html

Flutter plugin - mobile fails to compile because of 'dart:html' but plugin only supports web


Since there is no package to implement AdSense in Flutter, I decided to create a local plugin. It's extremely simple, the widget is an IFrameElement. I made sure when creating the plugin to specify that it only supports web because IFrameElement requires import 'dart:html' but whenever I try to compile/build the mobile version it fails because it tries to use the plugin with dart:html. How can I fix this?

Plugin:

import 'dart:html' as html show window;
import 'dart:html';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

import 'adsense_platform_interface.dart';

/// A web implementation of the AdsensePlatform of the Adsense plugin.
class AdsenseWeb extends AdsensePlatform {
  /// Constructs a AdsenseWeb
  AdsenseWeb();

  static void registerWith(Registrar registrar) {
    AdsensePlatform.instance = AdsenseWeb();
  }

  Widget adsenseAdsView(double width, double height) {

    ui.platformViewRegistry.registerViewFactory(
        'adViewBlock',
            (int viewID) => IFrameElement()
          ..width = '${width.toInt()}'
          ..height = '${width.toInt()}'
          ..src = 'adview.html'
          ..style.border = 'none');

    return SizedBox(
      height: height,
      width: width,
      child: const HtmlElementView(
        viewType: 'adViewBlock',
      ),
    );
  }

  /// Returns a [String] containing the version of the platform.
  @override
  Future<String?> getPlatformVersion() async {
    final version = html.window.navigator.userAgent;
    return version;
  }
}

Use:

import 'package:adsense/adsense_web.dart' show AdsenseWeb;

  Widget mainBody() {
    final height = MediaQuery.of(context).size.height;
    final width = MediaQuery.of(context).size.width;
    if (kIsWeb) {
      if (height > width) {
        return Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            locationsGridView(),
            AdsenseWeb().adsenseAdsView(width/3, height/2)
          ],
        );
      } else {
        return Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            locationsGridView(),
            AdsenseWeb().adsenseAdsView(width/3, height/2)
          ],
        );
      }
    } else {
      return locationsGridView();
    }
  }

Solution

  • You must create three classes:

    1. A class for the Flutter Web. This is your current AdsenseWeb class, which contains import 'dart:html'. You can name the file adsense_web.dart.

    2. The class for the mobile build. It should also be called AdsenseWeb. The file can be called adsense_web_stub.dart. There should be no dart:html import in this file! The class could be a stub or have specific behavior for mobile platforms.

    3. A wrapper that selects the desired AdsenseWeb:

      import 'package:......adsense_web_stub.dart'
        if (dart.library.html) 'package:...... adsense_web.dart'
        if (dart.library.io) 'package:...... adsense_web_stub.dart'
        as web;
      import 'package:flutter/widgets.dart';
      
      class Adsense extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return web.AdsenseWeb();
        }
      }