Flutter桌面端-应用启动后占满屏幕

前置条件

  • MacBook Pro M2 macOS Tahoe (26.0) / Windows 11 24H2
  • Flutter 3.35.3

功能需求

以目前的情况来看,Flutter 的桌面端软件其实跟移动端软件很像,因为 Flutter 桌面端目前默认只有一个窗口,而不是像原生的桌面端软件一样,经常会有很多个窗口。 比较不一样的是,移动端是直接全屏显示,桌面端的软件是以窗口的形式存在的。

而桌面端窗口大小可以设置,还可以由用户自由放大缩小。

所以一般桌面端软件都需要对窗口做一些配置,比如设置启动时的默认窗口大小以达到最佳的界面显示,设置最小的窗口大小来避免界面变形严重或者遮盖了重要界面等等。

我们希望应用启动后就占据整个屏幕,但是不是最大化,顶部状态栏,底部不要进行覆盖,类似 Chrome 浏览器的行为。

解决方法

可以使用 window_manager 插件来实现,但是发现达不到想要的效果。

后面发现 learnFlutter 还有一个开源库是 screen_retriever ,这个插件允许 Flutter 桌面 应用检索关于屏幕大小,显示,光标位置等信息。

试了下确实可以获取到屏幕的高度,可行的实现方式是使用 screen_retriever 获取到屏幕的高度之后再使用window_manager 设置窗口大小。

但是,上述的代码由于需要 Flutter 引擎初始化之后才能执行,因此会短暂先出现小窗口,然后窗口才会变大。整个过程中有明显的延迟,用户体验不好。

因此,还是需要从底层API层面进行窗口大小的调整,应用启动后,窗口大小立即调整完成,用户体验较好。

macOS 解决方案

方案一:

通过调用 NSWindowzoom 函数,实现窗口的放大。代码如下:

方案二:

通过调整 NSWindowvisibleFrame ,实现窗口的放大。代码如下:

方案三(推荐):

调整 MainFlutterWindow 的代码,直接设置窗口大小:

Windows 解决方案

Windows 系统下的解决方案比较简单,直接修改 ShowWindow 函数的参数,设置为 SW_MAXIMIZE 即可。代码如下:

Linux 解决方案

Linux 系统下的使用的是 GTK,因此可以通过在初始化窗口之前调用 gtk_window_maximize 函数即可(此函数支持窗口显示之前调用)。代码如下:

参考链接


Android页面内嵌入FlutterView

随着 Flutter 的流行,越来越多的开发者希望在现有的 Android 应用中引入 Flutter 的功能。本文将介绍如何在Android 应用中嵌入 Flutter View,并提供示例代码来帮助开发者快速上手。

1. 环境准备

在开始之前,请确保您已安装以下工具:

  • Android Studio
  • Flutter SDK

首先,您需要在您的 Android 应用中添加 Flutter 依赖。在 build.gradle 文件中添加 Flutter 相关的依赖:

2. 创建Flutter Module

接下来,您需要创建一个 Flutter 模块。在命令行中运行以下命令:

这将创建一个名为 flutter_moduleFlutter 模块。

3. 在Android中集成Flutter

3.1 修改Android原生代码

在您的 Android 项目中,首先需要设置 Flutter 引擎。在 ActicityonCreate 方法中,添加如下代码来初始化 Flutter

3.2 在XML布局中添加FlutterView

接下来,您可以在 XML 布局中添加 FlutterView。这里是一个示例布局:

3.3 Flutter View的显示

在设置好布局后,您需要在 Java 代码中加载 FlutterView 并显示它:

3.4 生命周期绑定

Android Acvitity 的生命周期中调用 appIsResumed()appIsInactiveappIsPausedappIsDetached以通知 Flutter 界面进入相应状态,否则页面会出现绘制异常。

参考链接


mbedtls tls 客户端应用详解

介绍 mbedtls 的 tls client 的使用方法,常见的功能参数配置和含义。 当前使用的 mbedtls 版本是: mbedtls-3.4.0。

功能参数配置

需要配置的功能选项

  • 设置 tls 协议版本: 配置 tls 1.2, tls 1.3, 还是二者都支持。
  • 认证方式设置:单向认证、双向认证、还是 psk。
  • 握手时的校验等级设置:不校验证书合法性,仅加密;校验,但如果失败也继续执行后面的握手流程;校验不通过则终止握手流程。
  • 服务器ca证书设置
  • 客户端证书和密钥设置
  • 预定义共享密钥设置

编译配置

使用 mbedtls_config.h 配置文件,tls 1.2 默认打开,不需要修改,但 tls 1.3 未开启,需要特别设置。

解决 mps_common.h 中的编译问题,替换 MBEDTLS_MPS_STORED_SIZE_MAX 和 MBEDTLS_MPS_SIZE_MAX 宏定义。

API 设计和实现

接口处理的事情,主要是连接参数配置、打开和关闭连接,接收和发送数据。

数据结构定义:

连接参数配置说明:

  • auth_mode:认证方式设置。

    一是通过证书认证,另一个是通过预定义密钥 PSK。

  • verify_mode:握手的校验等级。

    推荐配置为 QTF_TLS_VERIFY_MODE_REQUIRED。如果只是想加密而不校验,可以配置 QTF_TLS_VERIFY_MODE_NONE 或 QTF_TLS_VERIFY_MODE_OPTIONAL。

  • tls_version:tls 协议版本。

    推荐配置成 tls 1.2 或 tls 1.3,tls 1.2 以下的版本不安全,tls 1.3 版本 mbedtls 没有完整支持。

  • debug_level:日志等级。

    推荐设置 QTF_TLS_DEBUG_LEVEL_NONE 关闭日志输出。排查问题时可以将日志打开 QTF_TLS_DEBUG_LEVEL_VERBOSE(注意会打印密钥和收发数据的明文内容)。

  • max_frag_len: 数据分片大小设置。

    在客户端侧设置,用于协商数据分片大小,设置这个参数应该是出于对使用内存大小和带宽的考虑。

    设置太小,可能会出现服务器证书接收不完整导致握手失败问题,但最大值也不能设置超过接收缓冲区的大小。

  • hanshake_timeout_ms:握手超时时间。

  • ca_cert:服务器的 ca 证书。

    如果要求校验证书,则必须设置。客户端校验服务器是否合法,单向认证。

  • client_cert:客户端证书。

    要求双向认证的时候必须设置,用于服务器校验客户端是否合法。同时还要设置 client_key。

  • psk :预定义共享密钥。

    psk 不需要证书认证,减少握手数据交互流程,但需要指定 psk_id 身份标识和指定加密套件。

接口定义:

接口实现:

测试例子

测试代码,连接 https 测试服务器 httpbin.org,发送一个 get 请求,并接收服务器回复。

测试日志:

继续阅读mbedtls tls 客户端应用详解

Xcode 16 调整 Provisioning Profiles 目录导致证书查不到

cronet demo 使用的 ninja 打包,查找 Provisioning Profiles 路径是 ~/Library/MobileDevice/Provisioning Profiles,但 Xcode 16 把该路径改为了 ~/Library/Developer/Xcode/UserData/Provisioning Profiles,导致在编译 cronetdemo 时找不到证书。

解决办法是把 Xcode 16 的路径下的证书拷贝一份到老的路径 ~/Library/MobileDevice/Provisioning Profiles 即可。

参考链接


Xcode16 调整 Provisioning Profiles 目录导致证书查不到

Mac应用第三方渠道发布指南

1.申请证书

Mac 应用有多种证书,主要包含以下几种:

Apple证书类型
Apple证书类型

  • Apple Development: Xcode 11之后Apple全平台开发证书
  • Apple Distribution: Xcode 11之后Apple全平台发布
  • Mac Development:用来开发和Debug的证书
  • Mac App Distribution:用来给APP文件签名后上传到Mac App Store
  • Mac Installer Distribution:用来给PKG文件签名后上传到Mac App Store
  • Developer ID Installer:用于给PKG文件签名,在非Mac App Store场景使用
  • Developer ID Application:用于给APP文件签名,在非Mac App Store场景使用

继续阅读Mac应用第三方渠道发布指南

Flutter编写HTTPS服务器

从磁盘加载证书:

从内存加载证书:

参考链接


Java环境下 SslSocket 服务端及客户端简单例子

客户端代码如下:

继续阅读Java环境下 SslSocket 服务端及客户端简单例子

网页检测 微信登录状态

现在很多网站、应用平台在登录的时候,都支持直接通过微信扫码登录。

最近我发现一个现象:以前需要扫二维码才能登录,而现在,如果你的电脑上已经运行了微信,它能直接检测到,然后点击一个按钮就可以实现登录了。

继续阅读网页检测 微信登录状态

Flutter 的生命周期

概述

生命周期是一个 widget 组件加载到卸载的整个周期,熟悉生命周期可以让我们在合适的时机做该做的事情。

Flutter 开发中,everything is widget,但我们一般都不用直接继承 Widget 类来实现一个新组件,我们通常会通过继承 StatelessWidgetStatefulWidget 来间接继承 Widget 类来实现。StatelessWidgetStatefulWidget 都是直接继承自 Widget 类,而这两个类也正是 Flutter 中非常重要的两个抽象类,它们引入了两种 Widget 模型。此文主要介绍这两种 widget 的生命周期。

StatelessWidget

StatelessWidget 是无状态的 Widget,一旦创建就不会发生变化,所以无法提供 setState 修改组件的状态,它内部属性应声明为 final,防止意外发生改变。所以 StatelessWidget 的生命周期只有一个,就是 buildbuild 是用来创建 Widget 的,但因为 build 在每次界面刷新的时候都会调用,所以不要在 build 里写业务逻辑,可以把业务逻辑写到你的 StatelessWidget 的构造函数里。其生命周期如下图:

继续阅读Flutter 的生命周期