Flutter开发问题集

1. 两个插件之间冲突(target has frameworks with conflicting names)

  • 问题背景:本地插件和项目引用的插件中引用的插件之间有冲突,如:本地插件amap_location_flutter_plugin和远程插件amap_map_fluttify

  • 解决思路:
    1、将amap_map_fluttify放到amap_location_flutter_plugin中的dependency_overrides下面,如果需要,可以在本地插件里面将amap_map_fluttify内容export到项目中使用;最终发现在iOS中pod根本不会下载map的库,这个overrides只对当前module有效,所以该思路不通;

    2、将两个插件手动合并成一个插件来避免冲突,我是将amap_location_flutter_plugin中的内容放到了fluttify中,因为location中的内容较少也比较简单。在合并的过程中碰到了两个问题:1. 注册插件的问题;2. 包引用的问题;这个两个问题主要在Android项目上。在iOS很好解决因为我本身是iOS开发。iOS里面引用包的方式变成本地引用的方式就好,注册就直接在map中的register方法中调用location中plugin类的register就好了; 在Android里面就有意思了,因为注册插件的时候有两种方式,第一种是用register,第二种就是onAttachedToEngine,而安卓就是用的第二种,这好像是新版本的方式,也是在map的插件类中的onAttachedToEngine中binding.getFlutterEngine().getPlugins().add(new AmapLocationFlutterPlugin()); 关于包引用在Android根本不用改,很丝滑;
    在解决插件注册的时候了解到,flutter和原生交互的通道包括MethodChannel和EventChannel,前者是双向的交互,后者是单向的,既只支持原生端到flutter端,使用场景比如定位的实时获取,原生端将位置信息不停的将数据发送给flutter;

2. 将flutter老版本项目升级到2.0以上

  • 大概是以下几步:
    1. 主要是适配非空安全,这个在项目运行配置里面additional run args: --no-sound-null-safety;
    2. 升级一些版本低的插件,pub get的时候会有提示,还有一种办法就是在项目目录下用命令flutter pub add 库名,这种方式会自动下载一个合适的版本;
    3. 其他问题,比如我就碰到了问题1的插件冲突问题;

3. webView 和原生交互

  1. js调用flutter
  • 使用插件webview_flutter,
  • iOS端在info.plist文件中配置<key>io.flutter.embedded_views_preview</key>
    <true/>
  • 注入channels,使用js能够调用
JavascriptChannel(
              name: "NativeShare",
              onMessageReceived: (message) {
                print("收到web端消息: $message");
                // shareToWeChat(WeChatShareMiniProgramModel(webPageUrl: "webPageUrl", userName: ""));
              }),

然后再js中需要地方调用

NativeShare.postMessage(JSON.stringify({}));
  1. flutter调用js
    使用WebViewController对象执行;

4. QQ分享的图片地址转uri

Uri.parse("图片地址")

5. flutter中webview跳转安卓微信支付失败

开发环境:flutter 2.8.0 webview_flutter 3.0.0
一直会提示参数错误,主要是因为解析不出weixin://协议头的url,必须在加载微信支付url的时候在header中传入对应的微信支付平台授权的域名;

// 在拦截链接地时候重新加载
if (request.url.startsWith("https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb") && Platform.isAndroid) {
                // 安卓平台必须传入对应微信平台的授权域名
      _webViewController?.loadUrl(request.url, headers: {"Referer" : Uri.parse(controller.url).scheme + "://" + Uri.parse(controller.url).host});
      return NavigationDecision.prevent;
}

6. 分享到微信小程序

username要传原始ID,在小程序管理后台可以找到

7. 只生成release模式的framework和aar

flutter build ios-framework --no-debug --no-profile --output=./.framework/ios/

 flutter build aar --no-profile --no-debug --build-number x.x.x

8. 发送全局事件(通知)

依赖插件event_bus;
定义:

EventBus eventBus = EventBus();
enum TaskHallEventType {
  // 列表 下拉刷新 通知 刷新 勋章数量 滚动消息
  on_refresh,
  // 推送进入任务详情页
  on_enter_task_detail_page,

}
///任务大厅相关事件通知
class TaskHallEventMessage {

  Map<Object?, Object?>? parameters;
  TaskHallEventType eventType;

  TaskHallEventMessage(this.eventType, {this.parameters});
}

使用:

#发送事件
eventBus.fire(TaskHallEventMessage(TaskHallEventType.on_enter_task_detail_page, parameters: notificationInfo));


#监听事件
// 定义的监听对象需要再销毁的时候进行释放
 _taskHallListOnRefreshSubscription = eventBus.on<TaskHallEventMessage>().listen((event) {

      if (event.eventType == TaskHallEventType.on_refresh) {
        ///获取学生勋章数
        loadMedalCount();
        ///获取滚动列表数据
        loadScrollMsgList();
      } else if (event.eventType == TaskHallEventType.on_enter_task_detail_page) {
        if (event.parameters != null) {
          naviToTaskDetailPage(event.parameters!);
        }
      }

    });
void onClose() {
_taskHallListOnRefreshSubscription.cancle();
}


9. Get之Obx不刷新问题

#绑定
Obx(() {
    return Text(
               controller.isEditing.value == true ? "全选" : "删除",
               style: TextStyle(
               color: const Color(0xff3982FB),
               ontSize: 15.ft,
               fontWeight: FontWeight.w400
              ),
       );
 })

#改变
this.isEditing.value = false;

改变时是改变obs的value并不是赋值一个新的obs对象(this.isEditing = false.obs);看别人很多写的都是赋值新的obs对象,这样根本就刷新不了;

10. 报全局异常,只能提示错误的代码行,没有错误内容;

flutter版本:2.8.0
使用背景:请求接口返回的数据定义是个dynamic,然后使用map生成模型数组,在迭代期间没有问题,但是迭代完后却报错了,也不提示什么错误;
解决办法:将dynamic的变量转换成数组( as List) 再进行map就没问题了;

11. 两个Text中中文和数字对齐

解决: 将显示数字的Text种的style 中的height进行设置一般在1.5左右就能对齐;

12. 计算字符的高度

Size boundingTextSize(String text, TextStyle style,
      {int maxLines = 2 ^ 31, double maxWidth = double.infinity}) {
    if (text.isEmpty) {
      return Size.zero;
    }
    final TextPainter textPainter = TextPainter(
        textDirection: TextDirection.ltr,
        text: TextSpan(text: text, style: style), maxLines: maxLines)
      ..layout(maxWidth: maxWidth);
    return textPainter.size;
  }

13. 日期选择空间显示中文

 showDatePicker(context: ctx,builder: (BuildContext context, Widget? child) {
      return Localizations(
          locale: const Locale('zh'),
          child: child,
          delegates: <LocalizationsDelegate>[
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
          ]
      );
      }, initialDate: date, firstDate: date, lastDate: DateTime(date.year,date.month,date.day + 7)).then((value) {

        state.date = value.toString().substring(0,10);
        loadData(state.date);

    });

14. 打包Windows平台安装包命令

项目先添加msix插件依赖

执行命令:dart run msix:create

Win7 需要使用inno setup 处理打包,它可以生成打包脚本,Flutter build好后,就可以用这个执行脚本打包成exe安装包;


image.png

15. Windows插件制作时,插件中依赖其他的dll,只需要在set的时候 变量名称符合规则,dll就会被拷贝到生成目录。

具体写法如下:


image.png

16. Windows平台运行时偶现报错:C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073...

我目前的cmake版本是3.14,只要我把那个build文件删掉,再次编译就会报这个错误。找不到错误原因;
解决办法:用Visual studio打开build下面的Windows文件夹下的sin文件,重新生成一次解决方案,再回到flutter项目启动即可;
注:需要删除缓存的时候只把build下面的Windows文件夹删掉就行,再次构建就不会存在问题;

17. flutter抓包设置,在设置代理的时候Dio也需要一起初始化, 只需要在应用内设置代理的ip和端口并保持跟代理服务器在同一网段即可,无需其他配置;

 reset({String? ip, String? port}) {
    var baseUrl = AESStorageUtils.getString(SpConfigConstants.enConfig,
            defaultValue: EnvironmentType.Environment_Production.value) +
        Apis.kPathSuffix;
    _dio = Dio(BaseOptions(
        baseUrl: baseUrl, connectTimeout: RequestConfigure.connectTimeout));
    _dio.interceptors.add(LogInterceptor(responseBody: true));
    _dio.interceptors.add(TokenInterceptor());
    _dio.interceptors.add(URLInterceptor());
    if (ip != null && port != null) {
      AESStorageUtils.saveString(SpConfigConstants.kProxy_ip, ip);
      AESStorageUtils.saveString(SpConfigConstants.kProxy_port, port);
    }
    var local_ip = AESStorageUtils.getString(SpConfigConstants.kProxy_ip);
    var local_port = AESStorageUtils.getString(SpConfigConstants.kProxy_port);
    if (local_ip.isNotEmpty && local_port.isNotEmpty) {
      (_dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
        var client = HttpClient();
        client.findProxy = (uri) {
          return "PROXY $local_ip:$local_port";
        };
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) => true;
        return client;
      };
    }
  }

不断积累

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容