
如果你现在正坐在一台 mac 前面准备创建自己的第一个 Flutter 项目这篇内容应该能帮你少走不少弯路。我自己就是在这个环境里从零开始把 SDK 安装、环境变量、模拟器、依赖管理这些问题一个一个踩过来的中间报错报到自己都开始怀疑人生。但后来把这些坑整理清楚了回头看发现大部分问题都是套路而且几乎每个新人都会在同一批地方跌倒。这篇不是把官方文档原样念一遍而是专门写“在 mac 上创建 Flutter 项目”这件事本身环境怎么装、命令怎么敲、第一次运行到模拟器上会遇到哪些问题以及这些问题的排查逻辑。适合刚接触 Flutter 的新手也适合那种装完环境之后发现第一步始终迈不出去的人。1. 装环境前先把这三个问题想明白1.1 Flutter 项目依赖的“底料”到底有哪些先搞清楚一件事Flutter 本身是一个跨端 UI 框架界面逻辑用 Dart 语言来写编译之后可以运行在 iOS、Android、Web、桌面等多个平台。在 mac 上做 Flutter 开发有一个独特的优势——同一台电脑上你可以同时跑 iOS 和 Android 两端的模拟器Windows 用户想跑 iOS 是完全没有办法的。但 Flutter 并不是“装完 SDK 就能跑”它必须依赖系统里的原生工具链。在 mac 上这个链条大致是这样iOS 端需要 Xcode包含编译器和模拟器、iOS 模拟器运行时以及一个叫 CocoaPods 的工具。CocoaPods 是 iOS 生态里的依赖管理器Flutter 项目只要引入了带原生插件的包iOS 构建就会调用它。Android 端需要 Android 官方 IDE 或命令行工具、Android SDK Platform以及模拟器镜像。打个比方Flutter SDK 是菜谱和锅原生工具链是灶台和燃气。菜谱再全没有灶台你依然开不了火。很多人卡在第一步不是 Flutter 出了问题而是前置的“灶台”没准备好。1.2 下载 Flutter SDK压缩包还是包管理器在 mac 上安装 Flutter SDK主流方法有两种直接下载官方压缩包解压或者通过 mac 上的包管理器安装。我自己强烈推荐用压缩包的方式原因有三个安装路径完全可控。你知道 Flutter 解压在哪出问题可以直接顺着路径去查。不会自动升级。包管理器安装的版本可能跟着仓库更新走对于新手来说版本突变意味着环境不稳定。后期切换版本容易删掉旧目录换新目录就行不影响其他东西。解压之后的目录建议放在用户目录下面比如~/development/flutter。尽量不要往系统级目录放开发工具一方面写权限容易出问题另一方面系统升级时还可能出现冲突。下载完成后先看一眼目录结构确认flutter/bin/flutter这个文件确实存在再继续。很多人下载完解压后直接敲flutter发现没有这个命令顺着原因查下去多半是路径看错了或者根本没解压对层级。1.3 环境变量配置为什么 flutter 命令不生效在 mac 上终端默认使用的是 zsh对应的配置文件是~/.zshrc。所谓“配环境变量”本质上是告诉终端当你输入flutter的时候要去flutter/bin这个目录里找到一个同名可执行文件。打开~/.zshrc在末尾加一行export PATH$PATH:$HOME/development/flutter/bin然后执行source ~/.zshrc接着用flutter --version验证是否生效。这里面最常见的坑有两个。第一个是把 PATH 写成了文件本身比如写成了/Users/xxx/development/flutter/bin/flutter。这是错的PATH 里应该写“包含可执行文件的目录”不是可执行文件本身。第二个是改完配置之后忘了执行source或者直接新开了一个终端窗口发现还是找不到命令。新开窗口本身会加载 zshrc但如果你是在同一个终端里改的就需要主动 source 一次。提示如果flutter已经生效先跑一下flutter doctor。这个命令会检查环境缺什么缺 Xcode 组件、Android SDK、许可证之类的问题它都会列出来。后面遇到的大部分环境问题都能从这份报告里找到线索。2. 创建项目flutter create 的正确玩法2.1 命令格式与命名规则环境没问题之后找一个干净的目录执行创建命令flutter create first_flutter_app这时候有几个命名规范要特别注意项目名只能使用小写字母、数字和下划线不能以数字开头。不能使用连字符也就是中划线-。建议全部使用下划线风格也就是常见的 snake_case。原因很简单项目名会被同时用作 Android 的包名、iOS 的 bundle identifier、以及 Dart 的包名。如果名字里带了连字符Dart 标识符直接不合法生成出来的代码会在编译阶段报错。这种错误对新手来说非常迷惑因为你明明没有写错任何代码。如果你希望生成的包名带上组织标识可以这样flutter create --org com.example --project-name first_flutter_app .注意最后有一个点表示“在当前目录生成项目”。这种写法适合你已经建好了目录且目录名可能与项目名不一致的情况。项目名是给代码用的目录名只是你存放的位置两者没必要强行一致。2.2 生成出来的目录结构怎么读项目创建完成后会得到一堆目录和文件。新手看到这些很容易慌其实大多数内容在第一阶段根本不用碰。先认识几个关键的目录/文件作用lib/main.dartDart 代码入口默认是一个计数器 Demopubspec.yaml项目配置和依赖清单android/Android 原生工程目录ios/iOS 原生工程目录test/测试代码默认有一个 widget_test.dart.dart_tool/构建缓存目录不要手动修改我特别想强调一句android/和ios/是“受控目录”。如果不是很清楚自己在做什么不要手动去改里面的配置文件。因为 Flutter 在版本升级时可能会重新生成部分文件你手动改过后面就会冒出一堆莫名其妙的冲突。lib/main.dart是项目的主入口。默认代码是一个 StatefulWidget界面上有一个计数数字和一个浮动按钮点击一次数字加一。你可以不用完全读懂每一行但至少要知道void main()是入口函数runApp()用来启动根组件。2.3 pubspec.yaml 里藏着项目依赖用文本编辑器打开pubspec.yaml会看到一段依赖声明dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2版本号前面的^表示允许兼容性更新。比如^1.0.2的意思是允许自动升级到 1.x 系列的最新版本但不会跳到 2.0。这个机制叫做语义化版本控制它能让你既跟上小版本修复又不会因为主版本变化导致接口不兼容。cupertino_icons是 iOS 风格图标库默认带进来的暂时不管它就行。以后你要装第三方包比如网络请求、状态管理、图片加载之类的库就在dependencies:下面加一行然后执行flutter pub get这个命令会根据 yaml 文件里的声明下载依赖包并生成一个锁文件。依赖装没装上看这个命令的输出就能确认。3. 把项目跑到模拟器上的完整实操3.1 先跑 iOS 还是 Android第一次跑项目我的建议非常明确在 mac 上优先跑 iOS 模拟器而不是 Android。原因是 iOS 模拟器基本开箱即用不需要额外下载几百兆的系统镜像Android 那边则先要安装 IDE、下载 SDK Platform、创建虚拟设备光是这几个步骤就够新手绕一阵子了。第一次跑通的首要目标是尽量减少变量环境能少装一件就少装一件。Android 后面再补不迟反正 Flutter 项目本身是跨端的代码不用改只是换个设备跑。3.2 iOS 模拟器运行全流程第一步启动 iOS 模拟器在终端输入open -a Simulator也可以直接从启动台打开“模拟器”软件效果一样。第二步确认 Flutter 能识别到这个设备flutter devices看到类似 iOS Simulator 的设备条目就可以继续了。如果这里找不到设备八成是模拟器还没完全启动或者 Flutter SDK 版本与系统版本存在兼容问题。先等模拟器完全加载完再重新执行一次flutter devices很多时候问题就解决了。第三步进入项目目录并运行flutter run第一次运行会非常慢因为要完整编译原生工程几分钟到十几分钟都有可能取决于机器性能。看到控制台出现运行日志模拟器里出现计数器界面第一个 Flutter 项目就跑通了。3.3 热重载为什么按 r 一下代码就变了flutter run运行中终端会进入交互模式几个快捷键是新手一定要记住的小写r热重载Hot Reload把最新代码推送到正在运行的 App 里同时保留当前页面状态。大写R热重启Hot Restart重新执行整个 App状态重置但不需要重新安装。小写q退出运行。热重载的原理是Flutter 在调试模式下运行在一个 Dart 虚拟机里虚拟机可以接收新的编译产物不需要重新编译成原生 App、也不需要重新安装到模拟器。所以改完代码按一下 r几乎秒级就能看到界面变化。但也有些修改热重载是无效的。比如改了main()入口函数、改了 iOS 或 Android 原生目录里的代码、改了pubspec.yaml里的依赖声明。遇到这些情况直接按大写 R 做热重启或者干脆退出重新flutter run别在那干等。3.4 Android 模拟器绕不开的 SDK 和 AVD如果还是想体验一把 Android 端流程也并不复杂只是准备时间长一点安装 Android 官方 IDE。在 IDE 里安装 Android SDK Platform一般选择当前稳定版本的 API 级别即可。在终端执行flutter doctor --android-licenses按提示接受全部许可证。在 IDE 里创建虚拟设备选一个系统镜像。启动模拟器之后重新执行flutter devices再执行flutter run。这里面最耗时的环节是下载系统镜像动辄上百兆甚至更多。另外注意一点模拟器镜像的架构要跟你的 Mac 芯片匹配。自研芯片架构的 Mac优先选arm64-v8a镜像老款 x86_64 架构的 Mac选x86_64镜像。选错架构不是完全不能用但性能和稳定性都会打折扣碰到诡异问题也别奇怪。还有一个很多人会遇到的情况首次构建 Android 工程时Gradle 和依赖包要现下载这个过程可能比 iOS 首次编译还要慢。耐心等只要网络状况正常第一次成功之后后续构建就会快很多。4. 新手必看第一次跑 Flutter 一定会遇到的报错4.1 一直卡在 Waiting for another flutter command如果你在某个终端里强制中断过一次flutter命令比如按了 CtrlC之后你再执行flutter run有可能报一句很长的英文错误里面提到 “Waiting for another flutter command to release the startup lock”。原因是Flutter 在 SDK 目录下的bin/cache里留下了一个锁文件上一次命令非正常退出锁没释放新命令就一直等。解决方法是手动删掉锁文件。找到你的 Flutter SDK 解压目录执行rm -rf 你的 Flutter SDK 路径/bin/cache/lockfile然后重新运行flutter run就行。提示这一类开发工具尽量不要同时跑多个命令比如一边flutter run一边执行flutter upgrade非常容易触发锁竞争。命令行工具虽然支持并行但第一次接触时一个命令干完再敲下一个是最稳妥的。4.2 Xcode 首次使用要同意许可协议flutter doctor报告里如果出现 Xcode 相关问题或者运行 iOS 构建时提示需要同意许可协议不要慌这不是你的配置错误。这是因为 Xcode 装好以后还需要一个明确的“同意”动作法律上的确认步骤。在终端执行sudo xcodebuild -license accept输入密码等它执行完再重新跑一遍flutter doctor这个问题就消失了。这里再多说一句sudo不是万能的涉及系统级写入才需要它日常 Flutter 命令都不需要管理员权限。4.3 CocoaPods 安装卡住或失败iOS 构建过程中一旦你的项目加入了带原生插件的依赖Flutter 就会调用 CocoaPods 来管理原生依赖。也就是pod install这个步骤。第一次接触的新手大概率在“安装 CocoaPods 本身”或者“pod install 下载依赖”这两个环节卡住。安装 CocoaPods 比较省心的方法是用 mac 包管理器终端执行brew install cocoapods装完验证一下pod --version能输出版本号说明安装成功。如果 pod 相关命令提示 Ruby 环境错误不要急着去动系统的 Ruby 环境也不要拿着 sudo 到处乱试。直接把 CocoaPods 卸了重装一次大部分环境类问题都能解决。pod install 的持续卡顿基本都是网络状况导致的不是命令写错了。找一个网络顺畅的时间段再执行或者换一个网络环境会顺利很多。4.4 设备明明开着flutter devices 就是看不到这种情况在 iOS 和 Android 模拟器上都可能出现。排查顺序是这样的看模拟器是不是真的完成启动了。启动动画还没走完之前Flutter 经常扫描不到设备。重新执行flutter devices设备列表不会自动实时刷新命令行工具需要手动重新查询。执行flutter emulators看看 Flutter 视角下有哪些模拟器可用。以上都不行重启模拟器再重启终端然后再执行flutter devices。Android 那边还有一个特殊点模拟器从 IDE 启动后可能需要多等一会儿让系统服务和 ADB 完成连接。等一会儿再查询比反复重启要有效得多。4.5 芯片架构不匹配导致的编译问题现在的 mac 分两种主流架构旧款的 x86_64 和新款的自研芯片架构。如果你下载 Flutter SDK 时选错了架构或者接手的项目里带了针对另一种架构编译的原生依赖就可能看到架构相关的编译错误。检查当前 Flutter SDK 的架构可以执行file 你的 Flutter SDK 路径/bin/flutter如果输出显示 Mach-O 通用二进制文件但包含的架构与你的机器不对应直接重新下载对应架构的 Flutter SDK替换掉旧目录即可。模拟器镜像也一样记住自研芯片选 arm64旧款架构选 x86_64。4.6 别一上来就用升级命令折腾版本新手最容易犯的错误之一就是项目刚跑通马上执行flutter upgrade升级到最新版本结果项目里的依赖、Gradle 版本全部跟着不匹配报出一堆错误。这类环境问题排查起来非常消耗信心。我的建议很直接第一个项目阶段不要主动升级 Flutter SDK。稳定版本一用到底。等所有流程都摸熟了再考虑版本策略。Flutter 项目里的pubspec.yaml和原生工程配置都对版本敏感随意更新往往得不偿失。5. 下定决心把第一个项目做出点东西5.1 给自己定一个二十行代码就够的小目标Demo 跑通了接下来如果你不知道该学什么我的建议是不要急着啃复杂的架构设计先改手头的 Demo。把中间那个计数器数字改成一句你想显示的话把浮动按钮的颜色改掉再加一个重置按钮让数字回到零。控制在很小的改动范围内让身体记住“改代码、按 r、看效果”这个循环。第一次真正建立信心是把这个计数器改成“点击按钮后在屏幕上显示当前时间”。这个需求涉及文本展示、按钮事件、状态更新和时间处理覆盖了 Flutter 开发最常用的一组基础能力又不会复杂到让人放弃。5.2 学会读 Flutter 抛出来的错误运行阶段满屏红字是常态新手不要慌。先说一个关键技巧错误信息要读最后几行不是最前面那几行。最前面的通常是一长串调用栈最后一段才是错误原因和建议动作。比如编辑器里报Undefined class或者Target of URI doesnt exist翻译过来是“某个类找不到”或“某个导入路径不对”。对应检查两处文件开头有没有对应的 import 语句以及改完pubspec.yaml之后有没有执行flutter pub get。这两个问题占了新手报错的很大比例。5.3 把这个项目当成一套开发菜单这篇文章的核心是“在 mac 上创建第一个 Flutter 项目”但你真正拿到手的是一整套可以反复使用的开发流程。项目本身是个 Demo流程却是通用的。想上架 iOS后续去研究签名和发布配置。想上架 Android后续去关注打包体积和权限声明。想布局多端后续去研究响应式 UI。这些都是后话。当前最该做的是把这个最小可运行的 App 牢牢握在手里把环境问题清理干净把“创建项目-运行-改代码-看效果”这个循环变成肌肉记忆。5.4 两个提高效率的小习惯最后分享两个我直到现在都在用的小习惯。第一个flutter run最好指定设备。尤其是在 iOS 和 Android 模拟器同时开着的时候不指定设备终端会弹出一个设备列表让你手动选择很打断思路。设备比较多时我都是先执行flutter devices拿到设备 ID然后直接flutter run -d 设备ID第二个遇到报错先定位再搜索。把错误信息的最后几行复制下来再带着自己的操作上下文去搜比直接搜索整段报错效率高很多。这个方法在我后来做正式项目时一样管用新项目第一次跑通之后再回头处理版本升级、多端适配这些事心态就会完全不一样。