likes
comments
collection
share

Flutter 手机端项目转web运行部分问题记录

作者站长头像
站长
· 阅读数 31

最近尝试将平板程序编译成web应用发布,发布后程序可以运行,但是存在一些问题。现将问题和解决过程记录如下

  1. web应用加载耗时问题

  1. 加载时会去www.gstaic.com下载/chromium/canvaskit.js文件和canvaskit.wasm文件,
  2. 加载时会去www.gstaic.com下载notosanssc字体文件和roboto字体

Flutter 手机端项目转web运行部分问题记录

Flutter 手机端项目转web运行部分问题记录

Flutter 手机端项目转web运行部分问题记录

Flutter 手机端项目转web运行部分问题记录

打包指令

我的打包指令为:

flutter build web -t lib/main.dart --no-tree-shake-icons  --release

解决下载字体的问题

  1. 将需要下载的资源文件预下载放入项目中

  • 从对应的字体网址下载好roboto.ttf和notosanssc.otf
  • 将字体文件放在项目中的资源文件中

Flutter 手机端项目转web运行部分问题记录

  • 在项目的ymal文件中加入Font声明

Flutter 手机端项目转web运行部分问题记录

  • 打包项目,打包后build文件如下

Flutter 手机端项目转web运行部分问题记录

运行测试发现roboto.ttf文件已经可以从资源中下载,但是notosanssc.otf任然会从gstaic.com下载

Flutter 手机端项目转web运行部分问题记录

Flutter 手机端项目转web运行部分问题记录

  1. 解决notosanssc.otf仍然需要下载的问题

  • 修该ymal中Roboto字体的资源文件为notosanssc.otf

Flutter 手机端项目转web运行部分问题记录

  • 打包测试

Flutter 手机端项目转web运行部分问题记录

  • 不会再从gstaic中下载文件。这个方式不清楚原因,有知道原因的欢迎评论指正
  1. 解决canvaskit.js文件和canvaskit.wasm问题

  • buil目录中发现存在canvaskit.js和canvaskit文件

Flutter 手机端项目转web运行部分问题记录

  • 修改--dart-define=FLUTTER_WEB_CANVASKIT_URL为:canvaskit/,即

    •   --dart-define=FLUTTER_WEB_CANVASKIT_URL=canvaskit/
  • 此时编译指令为:

    • flutter build web -t lib/main.dart --no-tree-shake-icons  --release --dart-define=FLUTTER_WEB_CANVASKIT_URL=canvaskit/
      
  • 测试

Flutter 手机端项目转web运行部分问题记录

Flutter 手机端项目转web运行部分问题记录

  • chrome和safari加载时间不一致的问题

    •   canvaskit.wasm这个文件在chrome中需要耗时16s,在safari仅仅需要60ms

    • chrome

    • Flutter 手机端项目转web运行部分问题记录

    • safari

      • Flutter 手机端项目转web运行部分问题记录
    • 这个问题也不清楚原因,暂时未解决

  1. web浏览器刷新,url会重置的问题

我的项目是一个插件项目,需要主程序通过url传入一个资源地址,然后插件项目读取地址栏的地址,去下载并加载对应文件。主要代码如下:

void main() async {
  String? assetsApi = Uri.base.queryParameters['assetsApi'];
  printDebug("wbeApp start assetsApi:$assetsApi");
  runApp(MyApp(interface: MyControl(assetsApi: assetsApi ?? "")));
}
Widget build(BuildContext context) {
  return GetMaterialApp(
    home: AppUI(
      interface: interface,
    ) ,
  );
}

Flutter 手机端项目转web运行部分问题记录

此时程序可以读取地址栏的url,并正确加载

Flutter 手机端项目转web运行部分问题记录

  • 但是加载完成后,无法记录我们输入的url地址栏url再次变为:http://localhost:51335/#/

  • 解决方法

    • 使用setUrlStrategy方法
    • import 'package:flutter_web_plugins/flutter_web_plugins.dart';
      void main() async {
        String? assetsApi = Uri.base.queryParameters['assetsApi'];
        printDebug("wbeApp start assetsApi:$assetsApi");
        setUrlStrategy(PathUrlStrategy());
        runApp(MyApp(interface: MyControl(assetsApi: assetsApi ?? "")));
      }
      
    • 对app增加router
    •   Widget build(BuildContext context) {
          String basePath = Uri.base.path;
          debugPrint("basePath:$basePath");
          String router = "/?assetsApi=${interface.url}";
          debugPrint("router:$router");
          return GetMaterialApp(
            initialRoute: router,
            routes: {
              router: (_) {
                return AppUI(
                  interface: interface,
                );
              }
            },
            onGenerateRoute: (settings) {
              debugPrint('onGenerateRoute name: ${settings.name}');
            },
            onUnknownRoute: (settings){
              debugPrint('onUnknownRoute name: ${settings.name}');
            },
            // home: AppUI(
            //   interface: interface,
            // ) ,
          );
        }
      }
      
    • 此时从url加载完成程序后,地址栏不会重置,会记住上次的目录
    • initialRoute的值不知道如何填写的时候,可以从onUnknownRoute或者onGenerateRoute中寻找
  1. dart.io和dart:js

web项目中使用dart.io库中的API时会异常报错

非web项目无法使用dart:js的API时也会异常

那如何在一个功能中通过平台判断来使用不同的API呢

  1. 如何在同一个项目中同时使用dart.io和dart.js两个库的

操作如下:

  • 定义接口类abstract class,使用import if 来做头文件导入判断

app.dart

import 'desktop_mobile.dart'
  if (dart.library.html) 'web.dart';

abstract class App{
  Future<Map> init();
  factory App() => getApp();
}
  • 实现非web接口类

mobileApp.dart

  •  import 'dart:convert';
     import 'package:flutter/services.dart';
     import 'app.dart';
    
     class MobileApp implements App {
       @override
       Future<Map> init() async {
         String data = await rootBundle.loadString("assets/project_json.json");
         Map jsonData = jsonDecode(data);
         return jsonData;
       }
     }
    
     App getApp() => MobileApp();
    
  • 实现web接口类

    • 从js传过来的json格式数据可能导致dart无法识别,所以改为传jsonString

webApp.dart

import 'dart:convert';
import 'package:flutter/services.dart';
import 'app.dart';
import 'dart:js' as js;

class WebApp implements App {
  @override
  Future<Map> init() async {
    String? jsonString = js.context["appConfig"];
    jsonString ??= await rootBundle.loadString("assets/project_json.json");
    return jsonDecode(jsonString);
  }
}

App getApp() => WebApp();
  • 使用

main.dart

import 'app/app.dart';
Map jsonData = await App().init();
  1. runtimeType在web和手机端不同

web平台下数据的runtimeType和非原生不一样,判断数据类型时最好用is关键字来判断

如:

dynamic values = json[key];
  if (values != null && values is Map) {
}

而不使用

      dynamic values = json[key];
      if (values != null && values.runtimeType.toString().contains("Map")) {
      }

以下是部分整理

  1. macos平台

// int
dynamic int1 = 1; // int
int int2 = 1; // int
// double
dynamic double1 = 1.0;  // double
double double2 = 1.0; // double
// number
dynamic num1 = 2; // int
dynamic num2 = 2.0; // double
num num3 = 2; // int
num num4 = 2.0; // double
// string
dynamic string1 = "1.0"; // String
String string2 = "1.0"; // String
// map
dynamic map1 = {"1":2};// _Map<String, int>
dynamic map2 = {"1":2,"2":"2"};// _Map<String, Object>
dynamic map3 = {"1":2,"2":"2",1:'2'};// _Map<Object, Object>
Map map4 = {"1":2}; // _Map<dynamic, dynamic>
Map<dynamic,dynamic> map5 = {"1":2}; // _Map<dynamic, dynamic>
Map<String,dynamic> map6 = {"1":2}; // _Map<String, dynamic>
Map<dynamic,String> map7 = {"1":"2"};// _Map<dynamic, String>
// list
dynamic list1 = [1,2];// List<int>
dynamic list2 = ["1",2];// List<Object>
dynamic list3 = [1,2,{}];// List<Object>
List list4 = [{"1":2},{"1":2,"2":"2"}];// List<dynamic>
  1. web平台

// int
dynamic int1 = 1; // int
int int2 = 1; // int
// double
dynamic double1 = 1.0;  // int
double double2 = 1.0; // int
// number
dynamic num1 = 2; // int
dynamic num2 = 2.0; // int
num num3 = 2; // int
num num4 = 2.0; // int
// string
dynamic string1 = "1.0"; // String
String string2 = "1.0"; // String
// map
dynamic map1 = {"1":2};// IdentityMap<String, int>
dynamic map2 = {"1":2,"2":"2"};// IdentityMap<String, Object>
dynamic map3 = {"1":2,"2":"2",1:'2'};// LinkedMap<Object, Object>
Map map4 = {"1":2}; // LinkedMap<dynamic, dynamic>
Map<dynamic,dynamic> map5 = {"1":2}; // LinkedMap<dynamic, dynamic>
Map<String,dynamic> map6 = {"1":2}; // IdentityMap<String, dynamic>
Map<dynamic,String> map7 = {"1":"2"};// LinkedMap<dynamic, String>
// list
dynamic list1 = [1,2];// List<int>
dynamic list2 = ["1",2];// List<Object>
dynamic list3 = [1,2,{}];// List<Object>
List list4 = [{"1":2},{"1":2,"2":"2"}];// List<dynamic>
  1. Flutter web嵌入web项目

Flutter build的产物作为一个静态资源放在web项目中,web项目想调到flutter页面中,使用window.open函数

window.open(URL,name,specs,replace)
转载自:https://juejin.cn/post/7247028435340017724
评论
请登录