You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter移动端编译失败:含dart:html的Web专属插件适配问题求助

问题

目前没有可在Flutter中实现AdSense的包,我制作了一个仅支持Web端的本地插件。该插件十分简单,通过IFrameElement实现,因IFrameElement依赖dart:html,我已明确插件仅支持Web。但编译移动端版本时,仍因插件引入dart:html而失败,请问该如何解决?

插件代码:

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;
  }
}

使用代码:

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();
  }
}

解决方案

1. 用条件导入分离Web与移动端代码

dart:html是Web专属库,移动端编译时会因找不到该库报错。通过条件导入,让移动端加载不依赖dart:html的空实现:

  • 确保抽象类AdsensePlatform定义核心方法(已有可跳过):
// adsense_platform_interface.dart
abstract class AdsensePlatform {
  factory AdsensePlatform() => _instance;
  static AdsensePlatform _instance;

  Widget adsenseAdsView(double width, double height);
  Future<String?> getPlatformVersion();

  static set instance(AdsensePlatform instance) {
    _instance = instance;
  }
}
  • 创建移动端空实现文件adsense_mobile.dart:
// adsense_mobile.dart
import 'adsense_platform_interface.dart';
import 'package:flutter/material.dart';

class AdsenseMobile extends AdsensePlatform {
  @override
  Widget adsenseAdsView(double width, double height) {
    // 移动端返回空容器或自定义占位组件
    return SizedBox.shrink();
  }

  @override
  Future<String?> getPlatformVersion() async {
    return 'mobile';
  }
}
  • 创建插件入口文件adsense.dart,用条件导入自动匹配平台:
// adsense.dart
import 'adsense_platform_interface.dart';
import 'adsense_mobile.dart'
    if (dart.library.html) 'adsense_web.dart';

// 获取对应平台的插件实现
AdsensePlatform getAdsensePlatform() {
  return AdsensePlatform();
}
  • 修改Web端实现文件adsense_web.dart,添加工厂方法供条件导入调用:
// adsense_web.dart
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';

class AdsenseWeb extends AdsensePlatform {
  AdsenseWeb();

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

  @override
  Widget adsenseAdsView(double width, double height) {
    ui.platformViewRegistry.registerViewFactory(
        'adViewBlock',
            (int viewID) => IFrameElement()
          ..width = '${width.toInt()}'
          ..height = '${height.toInt()}' // 修复原代码中height误写为width的问题
          ..src = 'adview.html'
          ..style.border = 'none');

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

  @override
  Future<String?> getPlatformVersion() async {
    final version = html.window.navigator.userAgent;
    return version;
  }
}

// 供条件导入的工厂方法
AdsensePlatform getAdsensePlatform() => AdsenseWeb();

2. 优化使用代码,避免直接引用Web专属类

原使用代码直接导入adsense_web.dart,会导致移动端编译时仍尝试加载该文件。改为通过通用入口获取实例:

// 修改后的使用代码
import 'package:adsense/adsense.dart';
import 'package:flutter/foundation.dart' show kIsWeb;

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

3. 在pubspec.yaml中明确平台支持

在插件的pubspec.yaml中添加平台配置,明确仅支持Web(辅助提示,核心还是代码分离):

flutter:
  plugin:
    platforms:
      web:
        pluginClass: AdsenseWeb
        fileName: adsense_web.dart

这样修改后,移动端编译时会加载adsense_mobile.dart的空实现,不会引入dart:html,即可解决编译失败问题。


内容的提问来源于stack exchange,提问作者Globe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 16:05:24