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

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

  1. web应用加载耗时问题

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

打包指令

我的打包指令为:

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

解决下载字体的问题

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

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

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

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

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

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

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

  • 打包测试

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

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

  • 修改–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/
      
  • 测试

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

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

    • chrome

    • safari

    • 这个问题也不清楚原因,暂时未解决

参考:我把FlutterWeb渲染模式改成Canvaskit后… – 掘金

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


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

  • 但是加载完成后,无法记录我们输入的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 来做头文件导入判断
import 'desktop_mobile.dart'
  if (dart.library.html) 'web.dart';

abstract class App{
  Future<Map> init();
  factory App() => getApp();
}


  • 实现非web接口类

    • 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
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();
  • 使用
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)

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYX7vlIC' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片