如何手动将 .xcframework 添加到 Flutter iOS 插件中?

16

我正在尝试创建一个Flutter插件,以使用本地库。这个库存储在私有仓库中,并且可以使用Swift依赖管理器。

这给我带来了一些麻烦,因为我无法在插件中添加私有仓库依赖(我无法在.podspec文件中找到方法来实现此功能),所以我所做的是:

  1. 我已经使用Swift Package Manager将插件添加到示例项目中
  2. MyDependency.xcframework文件夹手动复制到MyPlugin/ios文件夹中
  3. 在podspec文件中引用它,像这样:
s.preserve_paths = 'MyDependency.xcframework'
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework MyDependency' }
s.vendored_frameworks = 'MyDependency.xcframework'

通过这样做,我能够在插件的源代码中使用MyDependency。

我的当前问题是:这只在模拟器中工作。

在做这个之前,该项目在真实设备上运行没有任何问题。

每次我尝试在真实设备上运行时,我都会收到以下错误消息:enter image description here

此外,我已经直接从Swift依赖管理器中使用依赖项进行了测试,并且运行良好。 我认为问题在于我添加框架到我的插件的方式。

enter image description here


你是否成功在iOS实体设备上构建了一个没有.xcframework的应用程序?此外,你不需要添加所有三个步骤(Cocoapods、SPM和xcframework)。只需将.xcframework拖入你的项目即可。 - Ben Butterworth
那么你对于那个闭源代码的分发策略有什么期望?如果它是闭源的,我不明白你如何使用SPM。 - Ben Butterworth
第二张截图(显示您的示例项目Runner中的SPM)只是您的库,它可能/可能没有.xcframework。此外,当用户将您的插件添加到其项目中时,您的插件会通过cocoapods添加,而不是SPM。当您屏蔽名称时,会使事情变得更加困难。在我看来,SPM对您不适用。 - Ben Butterworth
我的备选方案是将此依赖项添加到使用 SPM 的其他项目中,并手动将 .xcframework 复制到我的插件文件夹中。但如果你要将 XCF 拖入插件文件夹,那么为什么要使用 SPM 就不是很清楚了。不过,这两种方法都不适合 Flutter 插件。你应该在 Cocoapods 中使用 vendored_frameworks 配置 XCF。虽然这不是一个很好的文档功能:这个 问题有一个示例项目。我从未使用过它。 - Ben Butterworth
Flutter中SPM不好的一个原因是,安装Flutter中的包不会在Xcodeproj中添加Package.resolved。它只会改变Podfile的依赖关系/pod install的输出。 - Ben Butterworth
显示剩余3条评论
3个回答

19
我通过在 xxx.podspec 中添加以下行使其正常工作:
s.preserve_paths = 'xxxxxx.xcframework/**/*'
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework xxxxxx' }
s.vendored_frameworks = 'xxxxxx.xcframework'

注意在s.preserve_paths末尾的/**/*

以下是完整的xxx.podspec文件:

#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint xxx.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
  s.name             = 'xxx'
  s.version          = '1.0.0'
  s.summary          = 'xxx'
  s.description      = <<-DESC
xxx is a flutter plugin
                       DESC
  s.homepage         = 'https://example.com'
  s.license          = { :file => '../LICENSE', :type => 'BSD' }
  s.author           = { 'xxx' => 'email@example.com' }
  s.source           = { :path => '.' }
  s.source_files = 'Classes/**/*'
  s.dependency 'Flutter'
  s.platform = :ios, '10.0'

  # Flutter.framework does not contain a i386 slice.
  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
  s.swift_version = '5.0'

  s.preserve_paths = 'xxxxxx.xcframework/**/*'
  s.xcconfig = { 'OTHER_LDFLAGS' => '-framework xxxxxx' }
  s.vendored_frameworks = 'xxxxxx.xcframework'
end

请确保将xxxxxx.xcframework目录复制到.../xxx/ios/xxxxxx.xcframework(与您的插件xxx.podspec位于同一目录下)


xxxxxx.xcframework添加到Pods方案中,以便能够导入它

在运行flutter命令创建插件时,Frameworks目录应该位于Pods方案下面,例如:

flutter create --org com.xxx --template=plugin --platforms=android,ios -a java -i swift xxx

来源: 开发包和插件

(如果没有,请添加)

Adding framework 1

  1. 打开 Pods 方案,然后右键点击 Frameworks
  2. 选择 Add Files to "Pods"...

enter image description here

  1. 导航到包含xxxxxx.xcframeworkios目录根目录
  2. 取消选中如果需要,复制项目
  3. 选择创建文件夹引用
  4. 选中Pods-Runner
  5. 选中您的插件,例如xxx
  6. 点击添加

xxxxxx.xcframework嵌入您的项目中

(这样可以让您在真实设备上运行/发布)

enter image description here

  1. 点击 Pods 方案
  2. TARGETS 中选择 Pods-Runner
  3. 点击 General 选项卡
  4. 确保 xxxxx.xcframework 出现在 Frameworks and Libraries 下(如果没有,则通过点击 + 添加)
  5. Embed 更改为 Embed & Sign

enter image description here

  1. 点击您的插件,例如:xxx
  2. 确保xxxxx.xcframework出现在框架和库下面
  3. 嵌入更改为嵌入并签名

enter image description here

  1. 对于下面两个目标:Pods方案,接下来的步骤应该已经正确了,但请再次确认一下。
  2. 点击Build Phases
  3. 点击Link Binary With Libraries
  4. 确保xxxxx.xcframework存在,如果不存在,请通过单击+添加,并将Status设置为Required

现在,您应该能够导入框架并在您的代码中引用它,而且发布也应该非常顺利。

希望这可以帮助您,祝您好运。希望这不会很快再次改变。

祈祷万事顺利


感谢您发布解决方案!我正在阅读并有一个疑问,也许您可以解释一下...我注意到您手动将框架文件添加到了Pods中...在Flutter默认的.gitignore文件中,这个文件夹被列为不需要版本控制...这对其他开发人员真的有效吗?还是只是本地解决方案? - siega
1
@ siega 只要您嵌入(步骤8)xcframework,它就可以正常工作。 - Pierre
@Neigaard 在 Flutter 插件的根目录中,pubspec.yml 基本上只是描述了 Flutter 插件的版本、参考等信息,以及不同平台中 pluginClass 的引用(对于 iOS -> 指向 YourPlugin.h 头文件)。这个答案与插件的 iOS 端有关,与其他方面无关。对于多个框架,您需要在 ios/xxx.podspec 文件中引用每个框架(此答案的前三行重复出现 s.preserve_paths, s.xcconfig, s.vendored_frameworks,然后再次出现 s.preserve_paths, s.xcconfig, s.vendored_frameworks)。 - Pierre
@Pierre 抱歉,我是指 podspec 而不是 pubspec :) 我应该复制这些行,以便我有多个 s.preserve_paths 行,或者像这样:s.preserve_paths = 'X1.xcframework//*, X2.xcframework//*' s.xcconfig = {'OTHER_LDFLAGS' => '-framework WebRTC -framework X1 -framework X2'} s.vendored_frameworks = 'X1.xcframework, X2.xcframework' - Neigaard
@Pierre 如果我有一个 .a 文件怎么办?它是一个 Objective-C 静态库。流程是一样的吗?感谢您的任何帮助! - pasty
显示剩余8条评论

1

经过一些研究,我发现一些链接让我对真正的问题有了一个想法...

为了解决这个问题,我在我的主项目的构建过程中添加了一个简单的脚本。

此脚本将代码签名添加到内部的.framework文件中。

cd "${CODESIGNING_FOLDER_PATH}/Frameworks/"

# flatten nested frameworks by copying to APP.app/Frameworks
for framework in *; do
    if [ -d "$framework" ]; then
        if [ -d "${framework}/Frameworks" ]; then
            echo "Moving embedded frameworks from ${framework} to ${PRODUCT_NAME}.app/Frameworks"
            cp -R "${framework}/Frameworks/" .
            rm -rf "${framework}/Frameworks"
        fi
    fi
done

# remove any leftover nested frameworks (i.e. 'PackageName_359AFEED79E48935_PackageProduct.framework')
for framework in *; do
    if [ -d "$framework" ]; then
        if [ -d "${framework}/Frameworks" ]; then
            echo "Removing embedded frameworks from ${framework} to ${PRODUCT_NAME}.app/Frameworks"
            rm -rf "${framework}/Frameworks"
        fi
    fi
done

# codesign for Debugging on device
if [ "${CONFIGURATION}" == "Debug" ] & [ "${SDKROOT}" != *Simulator* ] ; then

    echo "Code signing frameworks..."
    find "${CODESIGNING_FOLDER_PATH}/Frameworks" -maxdepth 1 -name '*.framework' -print0 | while read -d $'\0' framework
    do
        # only sign frameworks without a signature
        if ! codesign -v "${framework}"; then
            codesign --force --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}"
            echo "Added missing signature to '${framework}'"
        fi
    done
fi

你把这个脚本添加(并调用)在哪里? - undefined

0
如果以上解决方法都不起作用,仍然出现“找不到框架xxx”的错误,请确认xxx.xcframeworkxxx.framework文件夹内的名称是否相同。
我花了几天时间试图将.xcframework添加到Flutter插件中,结果发现命名不匹配。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接