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 的生命周期

Flutter手势冲突难题怎么破?几种解决方式大揭秘!

Flutter 应用开发中,手势处理是构建交互式界面的核心环节。然而当多个手势识别器或可滚动组件嵌套使用时,经常会出现手势冲突问题。

本文将深入探讨 Flutter 中解决手势冲突的各种方法,并分析其适用场景,帮助您掌握高效的手势管理策略。

1 手势冲突的根源

在理解如何解决手势冲突之前,我们需要先了解 Flutter 中手势系统的基本原理 :

Flutter 的手势识别基于 GestureRecognizer 竞争机制。当用户触发指针事件(PointerDown)时,多个手势识别器会进入 gesture arena 竞争,最终只有一个胜出。竞争的过程主要有两个阶段:

  • 命中测试阶段(Hit Test Phase):确定哪些 Widget 接收了手势事件。
  • 手势识别阶段(Gesture Recognition Phase):多个 Widget 可能会识别相同的手势,从而产生冲突。

开发过程中比较常见的手势冲突场景包括:

  • 嵌套滚动组件(如 PageView 中的 ListView
  • 多层手势检测器(如 InkWell 内部的 GestureDetector
  • 父子组件都监听相同类型手势事件
  • 多个手势识别器同时竞争同一区域

2 解决手势冲突的方式

针对不同的应用场景,Flutter 提供了不同的冲突的处理方式

2.1 HitTestBehavior (最轻量级)

通过控制 GestureDetectorbehavior 参数控制手势事件如何在Widget 树中传递。常见的 behavior 值有:

  • HitTestBehavior.translucent : 自身和子组件都能接收事件
  • HitTestBehavior.opaque: 拦截所有事件(即使透明区域)
  • HitTestBehavior.deferToChild: 默认值,优先传给子组件

有兴趣的话,可以尝试改变内外两个 GestureDetectorbehavior 的值来加深理解对这个处理方式的理解

适用场景

  • 父子组件都需要响应手势
  • 需要控制手势事件的传递层次(通过 behavior )
  • 简单按钮嵌套
2.2 AbsorbPointer/IgnorePointer组件

这两个组件在使用时,会完成拦截或忽略掉所有的手势:

  • IgnorePointer:使子 Widget 忽略所有手势事件,但仍会参与布局和绘制;
  • AbsorbPointer:拦截并消耗所有手势事件,子 Widget 无法接收手势,自身可以接收并处理事件。

适用场景

  • 临时禁用某个区域的手势
  • 阻止下层 Widget 接收手势事件;
  • 复杂UI中动态切换交互状态;

2.3 RawGestureDetector与手势竞技场

Flutter 的手势竞技场( GestureArena )机制允许自定义手势识别的竞争规则,通过使用底层的 RawGestureDetector 注册多个手势识别器,由手势竞技场决定胜出者,整个竞技的过程会经历

  1. 当指针按下时,所有识别器进入竞技场
  2. 通过 addPointer() 处理事件流
  3. 识别器声明是否"准备好"处理事件
  4. 竞技场选择获胜者(首个声明准备就绪的识别器)
  5. 胜出者接收后续事件,其他被拒绝

适用场景

  • 需要同时识别多种手势
  • 复杂手势组合(缩放+旋转+平移)
  • 自定义手势识别逻辑
2.4 Listener组件处理原始指针事件

直接通过 Listener 去处理最原始的指针事件,自由控制:

适用场景

  • 需要底层事件控制的场景
  • 高度定制化的交互需求
  • 性能关键型的手势处理
2.5 自定义 ScrollPhysics

通过继承 ScrollPhysics 类,可以自定义滚动行为,控制滚动事件的传递和处理。

适用场景

  • 嵌套滚动组件(如 PageViewListView 的冲突)
  • 需要精确控制滚动阈值和边界条件
2.6 使用 NotificationListener

通过监听滚动通知(如 ScrollNotification),可以在父组件中捕获并处理滚动事件,从而控制子组件的行为。

适用场景

  • 监听滚动状态并作出响应
  • 协调多层级滚动组件的行为

3 手势冲突的例子

项目的某一个场景中,会有一个 PageView 里面嵌套 ScrollView 的场景,而且这两个的滚动方向是一致的(都是竖向的滚动)。

这种情况下要怎样保证当 ScrollView 滑动到最底(最顶)时,能触发 PageView的 翻页呢?结合前面的介绍的处理手势冲突的几种方式,大家会选择哪个呢?

最开始笔者是选择了自定义 ScrollPhysics 的方式来尝试处理的,但发现最终也只能有一个组件能滚动(中间尝试不同解决方案的痛苦就一一细说了),这里最终是通过NotificationListener 来协调这两者的滚动的。(这个方案不一定是最好的)

4 总结

本文主要介绍了 Flutter 中手势冲突几种解决方案,从简单高效的 AbsorbPointer 到底层强大的 Listener,可以应对不同复杂度的交互场景。

可以根据不同的业务场景选择不同的解决方案,这里给几点在选择解决方案时可参考的点:

  • 准确识别冲突来源和类型
  • 评估交互的复杂程度
  • 考虑性能和维护成本

参考链接


Flutter手势冲突难题怎么破?几种解决方式大揭秘!