无法分别构建Flutter Web和Flutter Mobile应用程序

6
我正在构建一个Flutter项目,但在将Web和移动端代码集成到单个项目时遇到了问题。我想在我的移动端代码中使用Moor和Moor_FFI,但即使我的Web(main.dart)和移动端代码(main.dev.dart)的入口点已被配置为不同以进行调试,它仍然尝试编译移动端代码用于Web。这会导致问题,因为目前Flutter Web不支持FFI和其他Dart插件,结果会产生巨大的错误消息。
Error compiling dartdevc module:ffi|lib/ffi.ddc.js

packages/ffi/src/utf8.dart:6:8: Error: Not found: 'dart:ffi'
import 'dart:ffi';
       ^
packages/ffi/src/utf16.dart:6:8: Error: Not found: 'dart:ffi'
import 'dart:ffi';
       ^
packages/ffi/src/allocation.dart:5:8: Error: Not found: 'dart:ffi'
import 'dart:ffi';
       ^
packages/ffi/src/utf8.dart:23:20: Error: Type 'Struct' not found.
class Utf8 extends Struct {
                   ^^^^^^
packages/ffi/src/utf8.dart:26:21: Error: Type 'Pointer' not found.
  static int strlen(Pointer<Utf8> string) {
                    ^^^^^^^
packages/ffi/src/utf8.dart:26:21: Error: Expected 0 type arguments.
  static int strlen(Pointer<Utf8> string) {
                    ^
packages/ffi/src/utf8.dart:41:26: Error: Type 'Pointer' not found.
  static String fromUtf8(Pointer<Utf8> string) {
                         ^^^^^^^
packages/ffi/src/utf8.dart:41:26: Error: Expected 0 type arguments.
  static String fromUtf8(Pointer<Utf8> string) {
                         ^
packages/ffi/src/utf8.dart:54:10: Error: Type 'Pointer' not found.
  static Pointer<Utf8> toUtf8(String string) {
         ^^^^^^^
packages/ffi/src/utf8.dart:54:10: Error: Expected 0 type arguments.
  static Pointer<Utf8> toUtf8(String string) {
         ^
packages/ffi/src/utf16.dart:16:21: Error: Type 'Struct' not found.
class Utf16 extends Struct {
                    ^^^^^^
packages/ffi/src/utf16.dart:24:10: Error: Type 'Pointer' not found.
  static Pointer<Utf16> toUtf16(String s) {
         ^^^^^^^
packages/ffi/src/utf16.dart:24:10: Error: Expected 0 type arguments.
  static Pointer<Utf16> toUtf16(String s) {
         ^
packages/ffi/src/allocation.dart:9:7: Error: Type 'DynamicLibrary' not found.
final DynamicLibrary stdlib = Platform.isWindows
      ^^^^^^^^^^^^^^
packages/ffi/src/allocation.dart:13:29: Error: Type 'Pointer' not found.
typedef PosixMallocNative = Pointer Function(IntPtr);
                            ^^^^^^^
packages/ffi/src/allocation.dart:13:46: Error: Type 'IntPtr' not found.
typedef PosixMallocNative = Pointer Function(IntPtr);
                                             ^^^^^^
packages/ffi/src/allocation.dart:14:23: Error: Type 'Pointer' not found.
typedef PosixMalloc = Pointer Function(int);
                      ^^^^^^^
packages/ffi/src/allocation.dart:18:27: Error: Type 'Void' not found.
typedef PosixFreeNative = Void Function(Pointer);
                          ^^^^
packages/ffi/src/allocation.dart:18:41: Error: Type 'Pointer' not found.
typedef PosixFreeNative = Void Function(Pointer);
                                        ^^^^^^^
packages/ffi/src/allocation.dart:19:35: Error: Type 'Pointer' not found.
typedef PosixFree = void Function(Pointer);
                                  ^^^^^^^
packages/ffi/src/allocation.dart:23:31: Error: Type 'Pointer' not found.
typedef WinGetProcessHeapFn = Pointer Function();
                              ^^^^^^^
packages/ffi/src/allocation.dart:26:7: Error: Type 'Pointer' not found.
final Pointer processHeap = winGetProcessHeap();
      ^^^^^^^

And so on.....

有没有办法配置编译器,仅针对Web或Mobile构建相应的文件?
参考:具有重现错误的Github存储库:https://github.com/JoshMarkF/MoorFFIIntegrationDemo
3个回答

2

编辑
flutter build webflutter run -d chrome都可以正常工作。
由于Web UI代码(webui.dart)和移动UI代码(mobileui.dart)位于不同的Dart文件中,因此这两个文件可以有不同的import

您可以复制粘贴运行下面的3个文件:main.dartwebui.dartmobileui.dart
您可以使用条件导入来分离Web和移动端的不同实现,从而使Web和移动端可以具有完全不同的逻辑。

代码片段调用前缀multiPlatform

import 'mobileui.dart' if (dart.library.html) 'webui.dart' as multiPlatform;
...
home:  multiPlatform.TestPlugin(),

使用 Android Studio 运行时,可以通过 Android EmulatorChrome 查看工作演示。

enter image description here

main.dart

import 'package:flutter/material.dart';
import 'mobileui.dart' if (dart.library.html) 'webui.dart' as multiPlatform;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget { 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(        
        primarySwatch: Colors.blue,
      ),
      home:  multiPlatform.TestPlugin(),
    );
  }
}

mobileui.dart

import 'package:flutter/material.dart';

class TestPlugin extends StatefulWidget {
  @override
  _TestPluginState createState() => _TestPluginState();
}

class _TestPluginState extends State<TestPlugin> {
  @override
  Widget build(BuildContext context) {
    return Text("Mobile");
  }
}

webui.dart

import 'package:flutter/material.dart';
import 'dart:html' as html;
import 'dart:js' as js;
import 'dart:ui' as ui;


class TestPlugin extends StatefulWidget {
  TestPlugin();

  _TestPluginState createState() => _TestPluginState();
}

class _TestPluginState extends State<TestPlugin> {
  String createdViewId = 'map_element';

  @override
  void initState() {
    // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory(
        createdViewId,
            (int viewId) => html.IFrameElement()
          ..width = MediaQuery.of(context).size.width.toString() //'800'
          ..height = MediaQuery.of(context).size.height.toString() //'400'
          ..srcdoc = """<!DOCTYPE html><html>
          <head><title>Page Title</title></head><body><h1>This is a Heading</h1><p>This is a paragraph.</p></body></html>"""
        /*..src = "http://f12apidev32.umc.com/Tableau/jsapi_practice.aspx"*/
          ..style.border = 'none');

    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        padding: EdgeInsets.symmetric(horizontal: 10),
        decoration: BoxDecoration(
            color: Colors.white,
            border: Border.all(color: Colors.grey[300], width: 1),
            borderRadius: BorderRadius.all(Radius.circular(5))),
        width: 200,
        height: 200,
        child: Directionality(
            textDirection: TextDirection.ltr,
            child: HtmlElementView(
              viewType: createdViewId,
            )));
  }
}

在我的代码中,错误是由移动端代码中的moor_ffi包引起的,这个包只有在移动端需要,而网页端不需要,同时需要dart:ffi。 是否有办法根据移动端或网页端来控制这些导入呢? - Joshua Mark Furtado
因为webui.dart和mobileui.dart是两个不同的dart文件,所以您不会遇到编译错误。您可以有完全不同的实现以及不同的导入。您需要做的只是将它们分开成不同的dart文件。 - chunhunghan
你可以看到我的示例webui.dart和mobileui.dart有完全不同的导入。 - chunhunghan
问题在于flutter build webflutter run -d chrome不使用与此处描述的相同编译器(https://flutter.dev/docs/get-started/web)。 简而言之,flutter build web使用dart2js,它将查看入口文件并仅编译Web代码。 然而,flutter run -d chrome使用dartdevc,它会查看lib文件夹中的所有文件。因此,它正在尝试编译移动文件和moor_ffi,因此出现了错误。 - Gpack
我已经测试了我的演示。flutter build web可以正常工作,当我将它放入IIS中时也可以正常工作。您可以复制粘贴并测试我的案例。使用条件导入也很好用。 - chunhunghan
使用flutter run -d chrome也可以正常工作。WebUI代码和MobileUI代码位于不同的Dart文件中。 - chunhunghan

0

在pubspec.yaml的dependencies中添加web_ffi: ^0.7.2,并导入此文件。

它将分别打开Web和移动设备。


0

您还需要修复任何依赖项、插件相关问题的 .pub-cache。 运行以下命令来清理您的 Flutter 并修复您的 pub-cache。

1. flutter clean

2. flutter pub cache repair 

这两个命令将解决大部分插件、依赖相关的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接