Flutter iOS开发OC混编Swift动态库和静态库问题填坑

目录
  • 引言
  • OC接入Swift 插件
  • 静态库和 Framework 区别
  • 新的问题: non-modular heade
  • 不能在Framework Module中使用非Modular 的 Header

引言

Flutter 在 iOS 上的编译问题相信大家多多少少遇到过,不知道大家在搜索这方便的问题时,得到的答案是不是让你 clean 或者 install 多几次,很多时候就算解决完问题,也是处于薛定谔的状态,所以本篇也简单记录下 Flutter 开发中,OC 混编 Swift 遭遇动态库和静态库的问题,希望对“蒙圈”中的你有点帮助。

OC接入Swift 插件

首先,当我在一个 OC 项目里接入一个 Swift 插件,可能会遇到什么问题?

如下图所示,如果你是一个比较老的 Flutter 项目,那可能会出现 swift 插件出现 not found 的问题。

针对这个问题,一般都是建议在 Podfile 文件下添加 use_frameworks! ,有时候还会建议添加 use_modular_headers! ,那这两个标记位的作用是什么?

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 而不是静态库,而默认由于 Swift 不支持静态库,因此有一开始 Swift 必须使用 Framework 的限制。

静态库和 Framework 区别

静态库和 Framework 的区别在于:

  • *.a 的静态库类似于编译好的机械代码,源代码和库代码都被整合到单个可执行文件中,所以它会和设备架构绑定,并且不包含资源文件比如图片;
  • Framework 支持将动态库、头文件和资源文件封装到一起的一种格式,其中动态库的简单理解是:不会像静态库一样被整合到一起,而是在运行或者运行时动态链接;

另外一个配置 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 里有静态库导致。

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

新的问题: non-modular heade

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

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

当然,你也可以在出现问题的插件的 .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 中使用非 Modular 的 Header,也就问题是在 Framework Module 中加载了非当前 Module 的头文件,而由于 Header 是对外 public ,比如配置到了 s.public_header_files ,就会导致非 Modular 的 Header 也出现对外暴露的风险,所以我这边的解放方式也很简单:

*在 s.public_header_files 里只放需要公开的 Plugin.h ,使用了非 Modular 的 Header 不对外 public,从而符合规范达到编译成功。

所以这里面的核心是:不要在 Umbrella Header File 中引用不需要对外公开的 OC 头文件去作为子 module ,这也解释了为什么上面讲出问题的 #import语句移到 .m 就解决问题的逻辑。

例如有时候你还会引用一些系统的 C Module ,其实在 Framework Module 化过程中也会有类似的问题。

所以知道了为什么和怎么解决,就不会只是粗暴通过 LLVM 的配置来设置 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 ‘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

当然,最后一句话:珍爱头发,远离 Swift 混编。

以上就是Flutter iOS开发OC混编Swift动态库和静态库问题填坑的详细内容,更多关于Flutter iOS OC混编Swift的资料请关注我们其它相关文章!

(0)

相关推荐

  • WKWebview非全屏自动播放h5视频的实现方法(Swift、OC)

    前言 WKWebview加载一个视频播放的h5页面时,默认是需要用户点击一下才能播放视频,且视频播放时会全屏播放.如果想要h5页面视频非全屏自动播放该怎么做呢? Swift实现 这个时候就需要设置WKWebview的configuration参数,我们先来看一下Swift的实现,代码如下: let configuration = WKWebViewConfiguration() configuration.allowsInlineMediaPlayback = true if #availabl

  • Flutter项目在 iOS14 启动崩溃的解决方法

    Flutter是什么? Flutter是Google一个新的用于构建跨平台的手机App的SDK.写一份代码,在Android 和iOS平台上都可以运行. 下面看下Flutter项目在 iOS14 启动崩溃的问题及解决方法 崩溃现象 在iOS14发布之后,运行APP就出现闪退,和机型没关,只要是iOS 14就必闪退 崩溃分析 1.启动就闪退,多起几次可能有一次没有问题. 2.启动后到某个页面卡死(必卡跳不过) 根本原因尚不明确,个人分析Product Name会影响Header Folder Pa

  • ios开发Flutter之数据存储

    目录 偏好存储 sqlite 创建表 数据插入 数据查询 数据修改 删除表 删除数据库 偏好存储 shared_preferences 类比iOS中的UserDefaults,使用方法比较简单. 地址戳这里 pub get之后会自动出现一个这样的文件generated_plugin_registrant.dart 数据存储: void _incrementCounter() { //创建对象,用于操作存储和读取. SharedPreferences.getInstance().then((Sha

  • IOS开发OC代码中创建Swift编写的视图控制器

    IOS开发OC代码中创建Swift编写的视图控制器 背景 近日在和一群朋友做项目,我和另一位同学负责iOS客户端,我是一直使用OC的,而他只会Swift,因此在我们分工协作之后,就需要把代码合在一起,这就牵扯到如何在TabbarController中添加一个swift创建的子控制器的问题. 解决 首先在一个OC项目中新建一个Swift类,继承自UITableViewController,并且修改其view背景色,方便后续测试. import UIKit class ESSwiftTableVie

  • Flutter iOS开发OC混编Swift动态库和静态库问题填坑

    目录 引言 OC接入Swift 插件 静态库和 Framework 区别 新的问题: non-modular heade 不能在Framework Module中使用非Modular 的 Header 引言 Flutter 在 iOS 上的编译问题相信大家多多少少遇到过,不知道大家在搜索这方便的问题时,得到的答案是不是让你 clean 或者 install 多几次,很多时候就算解决完问题,也是处于薛定谔的状态,所以本篇也简单记录下 Flutter 开发中,OC 混编 Swift 遭遇动态库和静态

  • ios动态库和静态库的区别

    一.什么是库? 库是共享程序代码的方式,一般分为静态库和动态库. 静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝. 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存. 二.静态库和动态库的好处 使用静态库的好处: 1.模块化,分工合作 2.避免少量改动经常导致大量的重复编译连接 3.也可以重用,注意不是共享使用 动态库使用有如下好处: 1.使用动态库,可以将最终可执行文件体积缩小 2.使用动态库,多个应用程序共享内存中得

  • 浅谈Linux C语言动态库及静态库

    假设在math目录下已编辑好add.c sub.c div.c mul.c func_point.c文件,func_point.c为包含main()的源文件! 动态库的制作: 方法一: gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关 gcc -shared -o libmymath.so add.o sub.o mul.o div.o//创建共享库mymath,添加add.o,sub.o,mul.

  • 动态库调用静态库示例讲解

    生成动态库: 需要的目标文件得用-fPIC选项生成. 而静态库所需的目标文件可以不用-fPIC选项. 例: 复制代码 代码如下: /////// static.h void static_print(); ///////static.cpp #include <iostream> #include "static.h" void static_print() { std::cout<<"This is static_print function&quo

  • 在动态库和静态库中使用模板(dynamic libraries ,static libraries)

    动态导入库和静态库: 他们实质是不一样的东西.静态库本身就包含了实际执行代码.符号表等等 ,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息 问题分析: 模板函数和模板类在库中使用的时候 非常困难,但也不是不可能,因为只有相应参数类型的模板函数在库内部有实例,就能成功导出这个模板函数.对于模板类的公有成员函数们(包括构造/析构函数)全部都必须有实例存在. 为什么要将模板实例化: 只有将导出库里面的模板函数或者模板类实例化,才能将实

  • Swift使用CoreData时遇到的一些填坑记录

    前言 最近在做一个 App 练手,其中用到了 CoreData 来存储用户的播放列表,由于 CoreData 这部分的文章还是比较少的,所以遇到了不少坑,所以写篇随笔记录一下. 题外话:可以给大家看看这个 App 的界面,我觉得还是挺清新的

  • Linux下g++编译与使用静态库和动态库的方法

    在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库(*.a)与动态库(*.so)的生成与使用方式是不同的.刚开始可能会不适应,但是用多了应该会习惯这种使用,因为步骤上并没有VS下配置那么繁琐. 下面就分别总结下linux下生成并使用静态库与动态库的方法:(由于是C++项目,所以编译器用的g++,但是与gcc的使用是相通的) 首先是准备工作,把我们需

  • iOS创建与使用静态库

    在日常项目开发中,不论是为了两个公司项目上的业务交流还是为了减少项目的编译时间,有的时候我们会把项目中的私密内容打包成静态库,或者是把项目中变动较少一部分打包成静态库以便提高编译效率,那么下面我们就来学习一下"iOS-静态库的创建与使用": (一)iOS静态库.动态库与Framework静态库与动态库的区别 (1)什么是库? 库(Library)直白一点说就是一段编译好的二进制代码,加上头文件就可以供别人使用;(例如: iOS中Objective-C编译下的.h和.m文件,打包静态库后

  • xcode 详解创建静态库和动态库的方法

    xcode 创建静态库和动态库 1.linux中静态库和动态库区别: 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 静态库:这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译. 动态库:这类库的名字一般是lib

随机推荐