網(wǎng)站首頁 編程語言 正文
引言
Flutter 在 iOS 上的編譯問題相信大家多多少少遇到過,不知道大家在搜索這方便的問題時,得到的答案是不是讓你 clean 或者 install 多幾次,很多時候就算解決完問題,也是處于薛定諤的狀態(tài),所以本篇也簡單記錄下 Flutter 開發(fā)中,OC 混編 Swift 遭遇動態(tài)庫和靜態(tài)庫的問題,希望對“蒙圈”中的你有點(diǎn)幫助。
OC接入Swift 插件
首先,當(dāng)我在一個 OC 項目里接入一個 Swift 插件,可能會遇到什么問題?
如下圖所示,如果你是一個比較老的 Flutter 項目,那可能會出現(xiàn) swift 插件出現(xiàn) not found 的問題。
針對這個問題,一般都是建議在 Podfile 文件下添加 use_frameworks!
,有時候還會建議添加 use_modular_headers!
,那這兩個標(biāo)記位的作用是什么?
target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end
我們知道 Podfile 的作用是處理 CocoaPads ,而 use_frameworks!
告訴 CocoaPods 你想使用 Framework 而不是靜態(tài)庫,而默認(rèn)由于 Swift 不支持靜態(tài)庫,因此有一開始 Swift 必須使用 Framework 的限制。
靜態(tài)庫和 Framework 區(qū)別
靜態(tài)庫和 Framework 的區(qū)別在于:
- *.a 的靜態(tài)庫類似于編譯好的機(jī)械代碼,源代碼和庫代碼都被整合到單個可執(zhí)行文件中,所以它會和設(shè)備架構(gòu)綁定,并且不包含資源文件比如圖片;
- Framework 支持將動態(tài)庫、頭文件和資源文件封裝到一起的一種格式,其中動態(tài)庫的簡單理解是:不會像靜態(tài)庫一樣被整合到一起,而是在運(yùn)行或者運(yùn)行時動態(tài)鏈接;
另外一個配置 use_modular_headers!
,它主要是將 pods 轉(zhuǎn)為 Modular,因?yàn)?Modular 是可以直接在 Swift中 import ,所以不需要再經(jīng)過 bridging-header 的橋接。
但是開啟 use_modular_headers!
之后,會使用更嚴(yán)格的 header 搜索路徑,開啟后 pod 會啟用更嚴(yán)格的搜索路徑和生成模塊映射,歷史項目可能會出現(xiàn)重復(fù)引用等問題,因?yàn)樵谝恍├享椖坷?CocoaPods 是利用Header Search Paths 來完成引入編譯,當(dāng)然使用 use_modular_headers!
可以提高加載性能和減少體積。
繼續(xù)回到問題上,我們在添加完 use_frameworks!
之后,有一定幾率中獎各種 Undefined symbol 的錯誤問題,這時候不要慌,因?yàn)檫@是 Swfit 里有靜態(tài)庫導(dǎo)致。
很明顯 Swift 不支持靜態(tài)庫的行為不科學(xué),所以從 Xcode 9 開始 Swift 就開始支持靜態(tài)庫,而 CocoaPods 1.9.0 開始,引入了 use_frameworks! :linkage => :static
來生支持有靜態(tài)庫和 Framework 的情況。
新的問題: non-modular heade
所以修改 use_frameworks 配置,增加 static 之后可以看到 Undefined symbol 的錯誤都消失了,但是運(yùn)行之后,可能會喜提新的問題: non-modular header 。
如果你去搜索答案,有很多答案會告訴你如下圖所示,通過 Allow Non-modular Includes in Framework Modules
設(shè)置為 true
就可以解決問題,但是很明顯這并不是正解,它更多適用于臨時的緊急狀體下。
當(dāng)然,你也可以在出現(xiàn)問題的插件的 .podspec
下單獨(dú)配置 ALLOW ,效果相同,更輕量級,但是這也只是臨時解決方案。
s.user_target_xcconfig = { 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES' }
為什么說這種方式不靠譜,因?yàn)槟悴恢拦俜綍裁磿r候刪除這種允許,當(dāng)然這個問題網(wǎng)友提供的解決方案其實(shí)千奇百怪:
- 如果是 App 使用 dynamic framework 里的 header 導(dǎo)致錯誤,可以使用
#import "MyFile.h"
而不是#import <MyFramework/MyFile.h>
; - 將
#import
語句移到.m
(而不是將其放在.h
頭文件中), 這樣它就不會有包含 non-modular header 的問題,例如: github.com/AFNetworkin… ; - 重命名 header ,不要讓 header 和模塊名一樣,變?yōu)?
#import <FrameworkName/Header.h>
- 在 build setting 配置 OTHER_SWIFT_FLAGS -Xcc -Wno-error=non-modular-include-in-framework-module 解決 Swift 的問題;
有可能它們都能解決你的問題,但是為什么呢?下次遇到這些問題要選哪個解決?
不能在Framework Module中使用非Modular 的 Header
回歸到我們的問題,其實(shí)我的問題關(guān)鍵是:不能在 Framework Module 中使用非 Modular 的 Header,也就問題是在 Framework Module 中加載了非當(dāng)前 Module 的頭文件,而由于 Header 是對外 public ,比如配置到了 s.public_header_files
,就會導(dǎo)致非 Modular 的 Header 也出現(xiàn)對外暴露的風(fēng)險,所以我這邊的解放方式也很簡單:
*在 s.public_header_files
里只放需要公開的 Plugin.h ,使用了非 Modular 的 Header 不對外 public,從而符合規(guī)范達(dá)到編譯成功。
所以這里面的核心是:不要在 Umbrella Header File 中引用不需要對外公開的 OC 頭文件去作為子 module ,這也解釋了為什么上面講出問題的 #import
語句移到 .m
就解決問題的邏輯。
例如有時候你還會引用一些系統(tǒng)的 C Module ,其實(shí)在 Framework Module 化過程中也會有類似的問題。
所以知道了為什么和怎么解決,就不會只是粗暴通過 LLVM 的配置來設(shè)置 Allow Non-modular Includes in Framework Modules
去解決薛定諤的問題。
另外你可能還有用到的,比如模擬器編譯提示 unsupport arm64、 BITCODE 失敗,SWIFT_VERSION 版本沖突等等:
post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| # building for iOS Simulator, but linking in an object file built for iOS, for architecture ‘a(chǎn)rm64' config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64' #不支持 BITCODE config.build_settings['ENABLE_BITCODE'] = 'NO' #解決swift模塊問題 config.build_settings['SWIFT_VERSION'] = '5.0' end end end
當(dāng)然,最后一句話:珍愛頭發(fā),遠(yuǎn)離 Swift 混編。
原文鏈接:https://juejin.cn/post/7089338745941393438
相關(guān)推薦
- 2022-07-09 Dockerfile文件介紹
- 2022-10-21 Go語言基于HTTP的內(nèi)存緩存服務(wù)的實(shí)現(xiàn)_Golang
- 2022-08-21 golang協(xié)程與線程區(qū)別簡要介紹_Golang
- 2022-07-22 在windows上配置git支持多賬號
- 2022-11-12 Python教程之成員和身份運(yùn)算符的用法詳解_python
- 2022-08-11 利用python繪制線型圖_python
- 2023-07-05 Spring Boot 啟動報錯 XXX\Tomcat\apache-tomcat-9.0.65\b
- 2023-04-14 拯救強(qiáng)迫癥Android?Builder模式_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支