在使用 Catalyst 迁移至 Mac 时排除 Pod

28

由于Catalyst,现在可以将应用程序移植到 Mac 上了。问题是,许多库不支持 AppKit。其中最常见的是 Crashlytics/Firebase。

In [...]/Pods/Crashlytics/iOS/Crashlytics.framework/Crashlytics(CLSInternalReport.o), building for Mac Catalyst, but linking in object file built for iOS Simulator, file '[...]/Pods/Crashlytics/iOS/Crashlytics.framework/Crashlytics' for architecture x86_64

因为这是一个近期的话题,我找不到有关如何在macOS上删除pod但保留它用于iOS和iPadOS的文档。

可以在代码中使用以下方法:

#if !targetEnvironment(macCatalyst) 
// Code to exclude for your macOS app
#endif

但这只是问题的一部分,另一部分是仅将 pod 链接到 iOS...

如果库对 macOS 并非必需,但仍希望在 iOS 上使用,最简单/最好的方法是什么?


嘿,楼主!如果我的回答对你有帮助的话,那就太好了!如果是这样,请将该回答标记为正确答案。 - Oz Shabat
6个回答

25

对于处理Catalyst不支持的框架,最好的方法是阅读Fernando Moya de Rivas的解决方案,他在这里提供了更为实时的信息,并在Github上提供了解决方案。

他基本上说,您只需要定义一个数组来列出所有不想在Mac OS X上安装的库,就像这样:['Fabric', 'Crashlytics', 'Firebase / Core',...]

然后,你的pod文件看起来就像这样简单:

# Podfile
load 'remove_unsupported_libraries.rb'

target 'My target' do
   use_frameworks!
   # Install your pods
   pod ...
end

# define unsupported pods
def catalyst_unsupported_pods
    ['Fabric', 'Crashlytics', 'Firebase/Core', ...]
end

# Remove unsupported pods from your project
post_install do |installer|   
    installer.configure_support_catalyst
end

2
我认为现在应该接受这个答案。只是请注意,我认为它需要Ruby 2.6.3才能避免调用“filter”时出错。 - andygeers
2
我现在将其切换为被接受的答案,因为这似乎是共识 :) - Tancrede Chazallet

19

在@ajgryc的答案的指导下,我成功制作了一个简洁的解决方案:

在您的podfile中添加以下内容


In your podfile add
post_install do |installer|
    installer.pods_project.targets.each do |target|
        if target.name == "Pods-[Name of Project]"
            puts "Updating #{target.name} OTHER_LDFLAGS to OTHER_LDFLAGS[sdk=iphone*]"
            target.build_configurations.each do |config|
                xcconfig_path = config.base_configuration_reference.real_path
                xcconfig = File.read(xcconfig_path)
                new_xcconfig = xcconfig.sub('OTHER_LDFLAGS =', 'OTHER_LDFLAGS[sdk=iphone*] =')
                File.open(xcconfig_path, "w") { |file| file << new_xcconfig }
            end
        end
    end
end

自 Cocoapods 1.8.4 版本以来

post_install do |installer|
  installer.pods_project.targets.each do |target|
    if target.name == "Pods-[Name of Project]"
      puts "Updating #{target.name} to exclude Crashlytics/Fabric"
      target.build_configurations.each do |config|
        xcconfig_path = config.base_configuration_reference.real_path
        xcconfig = File.read(xcconfig_path)
        xcconfig.sub!('-framework "Crashlytics"', '')
        xcconfig.sub!('-framework "Fabric"', '')
        new_xcconfig = xcconfig + 'OTHER_LDFLAGS[sdk=iphone*] = -framework "Crashlytics" -framework "Fabric"'
        File.open(xcconfig_path, "w") { |file| file << new_xcconfig }
      end
    end
  end
end

然后在Fabric的运行脚本构建阶段:

if [[$ARCHS != "x86_64"]]; then
  "${PODS_ROOT}/Fabric/run" [your usual key]
fi

3
将第三行代码更改为 if target.name.start_with?("Pods") 可以成功禁用 MacCatalyst 中所有的 CocoaPods。这样做可以捕获所有 Pod 目标。 - William Denniss
这似乎在cocoapods 1.8.4中不再起作用了。 - tmm1
1
我尝试了两种方式 "if target.name.start_with?("Pods")",但对于我来说都不起作用,即使使用cocoapods 1.8.4,我得到了以下错误,请问有人可以指导我吗?在 /Users/ios/Desktop/xxxxxx/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector(FIRConnectorUtils_d79571aba36a7d46e5c6ca87a6fec1c1.o) 中,为Mac Catalyst构建,但链接到为iOS Simulator构建的对象文件,文件 '/Users/ios/Desktop/xxxxxx/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector' 的架构是x86_64。 - Ankur Patel
4
对于运行脚本,您也可以使用以下内容:if [[ ${IS_MACCATALYST} != "YES" ]]; then "${PODS_ROOT}/Fabric/run" fi - Honghao Z
你能否更新一个答案,包括一个指向 CocoaPods 问题的链接,以便阅读答案的人可以投票支持它?在我看来,这应该是开箱即用的功能。https://github.com/CocoaPods/CocoaPods/issues/9364 - KleMiX
@AnkurPatel 在执行以上步骤后,我遇到了以下错误。 未定义的符号架构 x86_64: “___gxx_personality_v0”,引用自: FirebaseCrashlytics(FIRCLSDemangleOperation.o)中的+[FIRCLSDemangleOperation demangleBlockInvokeCppSymbol:]完整的错误日志请参见:https://drive.google.com/file/d/1Za3gGH8F-7iq4DBTXkXe9UnZmSg4legH/view?usp=sharing - Yogendra Patel

13

在项目的Pods目录中打开Pods-$projectname.release.xcconfig文件,找到OTHER_LDFLAGS行。在变量名后面立即添加[sdk=iphone*](例如,我的现在看起来像这样):

OTHER_LDFLAGS[sdk=iphone*] = $(inherited) -ObjC -l"MailCore-ios" -l"c++" -l"iconv" -l"resolv" -l"xml2" -l"z"

在构建iPhone变体时,有条件地设置链接选项,以防止Pod在OSX上被链接。当然,正如您所提到的,这需要与调用该Pod的代码周围的#if !targetEnvironment(macCatalyst)#endif结合使用,否则您将会得到链接器错误。

这使我成功解决了同样的问题。(如果您想知道除了条件变量之外,您可以在.xcconfig文件中添加哪些其他酷炫的东西,请查看我找到的参考链接:https://pewpewthespells.com/blog/xcconfig_guide.html


1
我已经给了你奖励,但是我接受了自己的答案,因为我提供了一个独特的解决方案,可以让人们的生活更加轻松。非常感谢! - Tancrede Chazallet
抱歉,但是Pods-$projectname.release.xcconfig文件在哪里呢?我找不到它。 - Ankur Patel
在我的配置中,它位于<Project Directory>/Pods/Target Support Files/Pods-<Project Name>。 - ajgryc
这个解决方案并不推荐,因为xcconfig总是在每次pod install时自行构建。我建议阅读Fernando Moya de Rivas的答案,以获得最佳替代方案。 - Oz Shabat

10

我有一个更新的解决方案,适用于我使用以下 Google 车间:

  pod 'FirebaseUI/Auth'
  pod 'FirebaseUI/Phone'
  pod 'FirebaseUI/Email'
  pod 'Firebase/Auth'
  pod 'Firebase/Analytics'
  pod 'Fabric', '~> 1.10.2'
  pod 'Firebase/Crashlytics'
  pod 'Firebase/AdMob'
post_install do |installer|
  installer.pods_project.targets.each do |target|
    if target.name.start_with?("Pods")
        puts "Updating #{target.name} to exclude Crashlytics/Fabric"
      target.build_configurations.each do |config|
        xcconfig_path = config.base_configuration_reference.real_path
        xcconfig = File.read(xcconfig_path)
        xcconfig.sub!('-framework "FirebaseAnalytics"', '')
        xcconfig.sub!('-framework "FIRAnalyticsConnector"', '')
        xcconfig.sub!('-framework "GoogleMobileAds"', '')
        xcconfig.sub!('-framework "Google-Mobile-Ads-SDK"', '')
        xcconfig.sub!('-framework "GoogleAppMeasurement"', '')
        xcconfig.sub!('-framework "Fabric"', '')
        new_xcconfig = xcconfig + 'OTHER_LDFLAGS[sdk=iphone*] = $(inherited) -framework "FirebaseAnalytics"  -framework "FIRAnalyticsConnector"  -framework "GoogleMobileAds" -framework "GoogleAppMeasurement" -framework "GoogleUtilities" "-AppMeasurement" -framework "Fabric"'
        File.open(xcconfig_path, "w") { |file| file << new_xcconfig }
      end
    end
  end
end

我正在尝试使用这个解决方案,因为它看起来最干净,但是我得到了这个错误:ld: in /Users/<name>/source/<app>/Pods/Fabric/iOS/Fabric.framework/Fabric(Fabric.o), building for Mac Catalyst, but linking in object file built for iOS Simulator, for architecture x86_64 我使用的与您上面提供的完全相同,除了GoogleMobileAdsGoogle-Mobile-Ads-SDK。我为什么会遇到这个问题? - fphelp
我不确定。现在是时候移除Fabric了,不是吗?我不同意Google有权购买它们,但他们确实这样做并关闭了它... - Andy
遗憾的是,使用“pod Crashlytics”会自动安装Fabric(1.10.2)。不确定为什么会发生这种情况,并且对使用“Firebase/Crashlytics” pod 持谨慎态度,因为Google表示该版本仍处于测试阶段 :( - fphelp
有人在执行此操作时遇到“包根目录中存在未封存的内容”错误导致构建失败吗? - Sam Spencer
@user13138159,我正在尝试上面的解决方案,但它给了我一个错误:ld: 在 /Users/<name>/Desktop/<app>/Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a(GAITrackerImpl.o) 中,为 Mac Catalyst 构建,但链接到为 iOS Simulator 构建的对象文件,文件 '/Users/<name>/Desktop/<app>/Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a' 适用于架构 x86_64 clang: 错误: 链接器命令失败,退出码为 1 (使用 -v 查看调用)。请问您具体做了什么? - iMinion

7

使用cocoapods 1.8.4,我需要对@AncAinu的优秀答案进行如下调整:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    if target.name == "Pods-[Name of Project]"
      puts "Updating #{target.name} to exclude Crashlytics/Fabric"
      target.build_configurations.each do |config|
        xcconfig_path = config.base_configuration_reference.real_path
        xcconfig = File.read(xcconfig_path)
        xcconfig.sub!('-framework "Crashlytics"', '')
        xcconfig.sub!('-framework "Fabric"', '')
        new_xcconfig = xcconfig + 'OTHER_LDFLAGS[sdk=iphone*] = -framework "Crashlytics" -framework "Fabric"'
        File.open(xcconfig_path, "w") { |file| file << new_xcconfig }
      end
    end
  end
end

最新版本的Crashlytics现在已经开源,因此在需要时可以直接编译为Catalyst。在Crashlytics的情况下,这种hack不再需要,但在其他旧版pod中可能仍然有用。 - tmm1
在"Name of the Project"部分,我们需要写项目文件的名称吗?如果目标是 "Pods-[MyProjectExample]",类似这样还是直接粘贴答案?因为对我来说它行不通。 - Bartu Akman
是的,您必须用您的项目名称替换它。 - tmm1
我已经做了一切正确的事情。如果目标名称为“Pods-[VPNoid]”,则清理并重新构建我的项目。但是仍然出现错误。你有任何想法吗? - Bartu Akman
1
移除 [] - tmm1

3

基于此前已经讨论的内容,这是我在处理多目标项目时提供的解决方案。其基本思路是对每个目标验证库的使用情况,而非按照目标名称来进行。

post_install do |installer|
    
    installer.pods_project.targets.each do |target|
        
        # handle non catalyst libs
        libs = ["FirebaseAnalytics", "Google-Mobile-Ads-SDK"]
        
        target.build_configurations.each do |config|
            xcconfig_path = config.base_configuration_reference.real_path
            xcconfig = File.read(xcconfig_path)
            values = ""
            
            libs.each { |lib|
                if xcconfig["-framework \"#{lib}\""]
                    puts "Found '#{lib}' on target '#{target.name}'"
                    xcconfig.sub!(" -framework \"#{lib}\"", '')
                    values += " -framework \"#{lib}\""
                end
            }
            
            if values.length > 0
                puts "Preparing '#{target.name}' for Catalyst\n\n"
                new_xcconfig = xcconfig + 'OTHER_LDFLAGS[sdk=iphone*] = $(inherited)' + values
                File.open(xcconfig_path, "w") { |file| file << new_xcconfig }
            end
        end
    end
end


它会输出类似于这样的结果

Generating Pods project

Found 'Google-Mobile-Ads-SDK' on target 'Pods-TheApp'
Found 'FirebaseAnalytics' on target 'Pods-TheApp'
Preparing 'Pods-TheApp' for Catalyst

Found 'Google-Mobile-Ads-SDK' on target 'Pods-TheApp-TheAppTests'
Found 'FirebaseAnalytics' on target 'Pods-TheApp-TheAppTests'
Preparing 'Pods-TheApp-TheAppTests' for Catalyst

Found 'Google-Mobile-Ads-SDK' on target 'Pods-TheApp-TheApp_iOS_UI_Tests'
Found 'FirebaseAnalytics' on target 'Pods-TheApp-TheApp_iOS_UI_Tests'
Preparing 'Pods-TheApp-TheApp_iOS_UI_Tests' for Catalyst

Found 'Google-Mobile-Ads-SDK' on target 'Pods-TheAppIntentsExtension'
Found 'FirebaseAnalytics' on target 'Pods-TheAppIntentsExtension'
Preparing 'Pods-TheAppIntentsExtension' for Catalyst

Found 'Google-Mobile-Ads-SDK' on target 'Pods-TheAppTodayExtension'
Found 'FirebaseAnalytics' on target 'Pods-TheAppTodayExtension'
Preparing 'Pods-TheAppTodayExtension' for Catalyst

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