Flutter iOS OC mezcla Swift, encuentra problemas de biblioteca dinámica y biblioteca estática y llena el hoyo

Creo que te has encontrado con el problema de compilación de Flutter en iOS más o menos, me pregunto si la respuesta que obtienes cuando buscas esta conveniente pregunta es si necesitas limpiarlo o instalarlo varias veces , en muchos casos, incluso si el problema está resuelto, todavía está en el estado de Schrödinger, por lo que este artículo también registra brevemente que en el desarrollo de Flutter, OC mezclado con Swift se encuentra con el problema de la biblioteca dinámica y la biblioteca estática , espero que te ayude en el "círculo".

imagen-20220422091858815

En primer lugar, cuando integro un complemento de Swift en un proyecto de Objective-C, ¿qué problemas puedo encontrar?

Como se muestra en la figura a continuación, si es un proyecto de Flutter más antiguo, puede haber un problema de que no se encuentra el complemento rápido .

imagen-20220422093205569

En respuesta a este problema, generalmente se recomienda agregarlo en el archivo Podfile use_frameworks!y, a veces, se recomienda agregarlo use_modular_headers!. ¿Cuál es el papel de estas dos banderas?

target 'Runner' do
  use_frameworks! 
  use_modular_headers!
  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
复制代码

Sabemos que la función de Podfile es lidiar con CocoaPads y use_frameworks!decirle a CocoaPods que desea usar Framework en lugar de una biblioteca estática, y debido a que Swift no es compatible con la biblioteca estática de forma predeterminada, existe la limitación de que Swift debe usar Framework al principio.

La diferencia entre una biblioteca estática y un Framework es:

  • *.una biblioteca estática es similar al código mecánico compilado, el código fuente y el código de la biblioteca están integrados en un solo archivo ejecutable, por lo que está vinculado a la arquitectura del dispositivo y no contiene archivos de recursos como imágenes;
  • Framework admite un formato que encapsula bibliotecas dinámicas, archivos de encabezado y archivos de recursos juntos. La comprensión simple de las bibliotecas dinámicas es que no se integrarán juntas como bibliotecas estáticas, sino que se vincularán dinámicamente en tiempo de ejecución o en tiempo de ejecución;

另外一个配置 use_modular_headers! ,它主要是将 pods 转为 Modular,因为 Modular 是可以直接在 Swift中 import ,所以不需要再经过 bridging-header 的桥接。

但是开启 use_modular_headers! 之后,会使用更严格的 header 搜索路径,开启后 pod 会启用更严格的搜索路径和生成模块映射,历史项目可能会出现重复引用等问题,因为在一些老项目里 CocoaPods 是利用Header Search Paths 来完成引入编译,当然使用 use_modular_headers!可以提高加载性能和减少体积。

继续回到问题上,我们在添加完 use_frameworks! 之后,有一定几率中奖各种 Undefined symbol 的错误问题,这时候不要慌,因为这是 Swfit 里有静态库导致。

imagen-20220422103410759

很明显 Swift 不支持静态库的行为不科学,所以从 Xcode 9 开始 Swift 就开始支持静态库,而 CocoaPods 1.9.0 开始,引入了 use_frameworks! :linkage => :static 来生支持有静态库和 Framework 的情况。

所以修改 use_frameworks 配置,增加 static 之后可以看到 Undefined symbol 的错误都消失了,但是运行之后,可能会喜提新的问题: non-modular header

imagen-20220422104501881

如果你去搜索答案,有很多答案会告诉你如下图所示,通过 Allow Non-modular Includes in Framework Modules 设置为 true 就可以解决问题,但是很明显这并不是正解,它更多适用于临时的紧急状体下

imagen-20220422105705987

当然,你也可以在出现问题的插件的 .podspec 下单独配置 ALLOW ,效果相同,更轻量级,但是这也只是临时解决方案。

s.user_target_xcconfig = { 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES' }
复制代码

为什么说这种方式不靠谱,因为你不知道官方会什么时候删除这种允许,当然这个问题网友提供的解决方案其实千奇百怪:

  • 如果是 App 使用 dynamic framework 里的 header 导致错误,可以使用 #import "MyFile.h" 而不是 #import <MyFramework/MyFile.h>
  • #import语句移到 .m(而不是将其放在.h头文件中), 这样它就不会有包含 non-modular header 的问题,例如: github.com/AFNetworkin…
  • 重命名 header ,不要让 header 和模块名一样,变为 #import <FrameworkName/Header.h>
  • 在 build setting 配置 OTHER_SWIFT_FLAGS -Xcc -Wno-error=non-modular-include-in-framework-module 解决 Swift 的问题;

有可能它们都能解决你的问题,但是为什么呢?下次遇到这些问题要选哪个解决?

回归到我们的问题,其实我的问题关键是:不能在 Framework Module 中使用非 Modular 的 Header,也就问题是在 Framework Module 中加载了非当前 Module 的头文件,而由于 Header 是对外 public ,比如配置到了 s.public_header_files ,就会导致非 Modular 的 Header 也出现对外暴露的风险,所以我这边的解放方式也很简单:

* Coloque solo el Plugin.h que debe divulgarse en el , y use el encabezado no modular para que no sea público para el mundo exterior, a fin de cumplir con la especificación y lograr una compilación exitosas.public_header_files .

Entonces, el núcleo de esto es: no se refiera al archivo de encabezado OC que no necesita estar expuesto al mundo exterior en el archivo de encabezado paraguas como un submódulo, lo que también explica por qué la #importdeclaración trasladó .ma La lógica de resolver el problema.

Por ejemplo, a veces también se referirá a algunos Módulos del sistema C, de hecho, habrá problemas similares en el proceso de Modularización del Marco.

Entonces, si sabe por qué y cómo resolverlo, no lo configurará de manera grosera a través de la configuración de LLVM Allow Non-modular Includes in Framework Modulespara resolver el problema de Schrödinger.

Además, también puede usarlo, como solicitudes de compilación del emulador que no admiten arm64, falla de BITCODE, conflicto de versión SWIFT_VERSION, etc.:

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 ‘arm64’
        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
复制代码

Y por supuesto, la última palabra: cuida tu cabello y aléjate de la mezcla de Swift .

Supongo que te gusta

Origin juejin.im/post/7089338745941393438
Recomendado
Clasificación