前言
开发Flutter项目以来,第一次碰到这种奇怪问题,简直怀疑人生。
开发环境
- Flutter: 3.3.5
- Dart: 2.18.2
- Xcode: 14.0.1
- Android: 2021.3.1 Patch 1
问题描述
同事拉了最新的代码到自己电脑上,修复了一些问题,先在Android设备上运行测试没问题,接着问题来了,在iOS真机上运行时发现应用版本名称获取不到。可是,这个获取应用版本名称功能从实现完到现在就没改动过了。最奇怪的是,我电脑上的同个项目运行在同个iOS真机上是正常的。
问题分析
- 代码改动的原因?
我马上想到这不会是同事自己改代码改出的问题吧,同事马上跳出来反驳我说不可能,我review了下代码,发现这些改动确实不至于引发这个问题。 package_info_plus
版本不一致的原因?
对比pubspec.lock
文件中依赖版本,发现确实同事的比较新,去Pub看了下Changelog,也没说iOS获取应用版本名称有什么变化,按我多年iOS/Android的原生开发经验,这插件获取应用版本名称的方式应该不会变。尝试将两边的package_info_plus
版本号统一,问题并没有解决。- 开发环境不一致的原因?
首先检查Flutter版本,两边都升级到最新的3.3.5版本,问题还在。Xcode都升级到最新的14.0.1,问题依旧还在。 - Xcode命令行工具的原因?
执行xcode-select --install
命令提示command line tools are already installed
,好吧,应该也不是这个问题,删除重装Xcode命令行工具也不行。
经过以上操作,应用版本名称依旧获取不到,Android Studio中的运行日志也没看到报错信息。既然Flutter项目中获取不到,那我用Xcode打开对应的iOS项目,获取应用版本名称打印出来看看。
打印应用版本名称的源码:
print(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "")
运行后打印结果是空的,什么鬼!我又在我电脑上的试了以下是正常的,难道是Info.plist
配置不一样?对比两边的配置,一模一样,尝试获取里面的应用版本号,发现是可以的。难道是CFBundleShortVersionString
属性的值$(FLUTTER_BUILD_NAME)
有问题。找了下FLUTTER_BUILD_NAME
定义的地方,如下图:
通过图片可以看出这并没有什么问题,最主要的是,从项目创建到现在CFBundleShortVersionString
属性的值就没改过,这是Flutter项目默认的。 这下真的怀疑人生了,我这没问题,同事的有问题,没有报错信息,而且同事之前运行也没问题,要说最大的区别就是升级了Xcode,但是我也升级了。新建了一个Flutter项目,Info.plist
中配置应用版本名称的方式也没变。
就在我一筹莫展的时候,同事跟我说在iOS模拟器运行报错了。错误信息是The application's Info.plist does not contain a valid CFBundleShortVersionString
,这离了大谱,在项目中的Info.plist
肯定是没问题的,那肯定就是打包的时候出问题了。
先找到打包后的Runner.app
文件一探究竟,对于Android Studio运行的,Runner.app
文件在项目根目录/build/ios/iphonesimulator/
这个路径,对于Xcode运行的,可以选中Products
下的Runner
,右击选择Show in Finder
,在新打开的窗口中可以找到Runner.app
文件。选中Runner.app
显示包内容,找到里面的Info.plist
文件并打开,确实少了CFBundleShortVersionString
属性。
问题的原因找到了,但没完全找到,这还不能完全解释为什么会出现这个问题。不过,问题分析到这里,我已经想到解决方案了。写解决方案之前,先来说说我在iOS原生项目开发时对于应用版本名称是怎么配置的。
项目打包环境会分开发/预发/正式三种环境,所以会有三个Info.plist
文件(文件名称会带上环境名区分),CFBundleShortVersionString
属性配置的是$(MARKETING_VERSION)
,MARKETING_VERSION
属性的值其实就是下图所示位置设置的值。
所以,每次版本更新时,只需要在上图所示位置改一下就可以了。从这里可以看出,之所以会出现这个问题,很有可能是Flutter项目打包时,MARKETING_VERSION
属性值为空导致Info.plist
缺失CFBundleShortVersionString
属性。不过这也还不能完全解释为啥我电脑上运行是可以的,毕竟两边项目里面的配置是一样的。
解决方案
首先你需要用Xcode打开项目,如果没在下图所示位置设置过版本名称,请随便设置一个(后面应用版本名称会和FLUTTER_BUILD_NAME
的值同步,不会影响到正常的应用版本名称,所以请随意设置),不然MARKETING_VERSION
属性可能搜索不到。
然后按下图所示搜索Marketing Version
和设置属性值为$(FLUTTER_BUILD_NAME)
,设置完点击旁边空白处会自动保存。
设置完毕,MARKETING_VERSION
属性值自动变成了FLUTTER_BUILD_NAME
的值。
这边的应用版本名称也自动同步了。
到此,这个问题就完美解决了。虽然解决方案简单,但是找到解决方案的过程一言难尽。
补充内容
Fastlane打包的ipa包上传fir后不显示应用版本名称,本质还是同一个问题。找到打包上传的ipa文件,将.ipa
文件后缀名改为.zip
,然后解压缩,找到Payload
文件夹里的Runner.app
,右击显示包内容找到Info.plist
文件打开,会发现一样缺失CFBundleShortVersionString
属性。
总结
问题本身很简单,难就难在为什么我电脑上是正常的,运行在iOS真机也没有报错,而且这个配置是Flutter创建项目的时候默认配置的,这个项目都到尾声了突然出现这个问题,真是让人困惑。
最后
如果这篇文章对你有所帮助,请不要吝啬你的点赞👍加星🌟,谢谢~