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
相关产品推荐
相关产品推荐

