28

Porting apps to mac is finally possible thanks to Catalyst, problem is, numerous pods don't support AppKit. Most common one would be 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

Since it's a recent topic, I couldn't find doc on how to remove a pod from my build for macOS but keep it for iOS and iPadOS.

It is possible to use in code:

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

But that one part of the problem, the other part is to link the pod only for iOS...

What would be the easiest/best course of action when the library is not vital for macOS but still wanted on iOS?

Tancrede Chazallet
  • 7,035
  • 6
  • 41
  • 62
  • Hey op! It would be great to know if my answer helped you! if it does, please mark the answer as the right answer – Oz Shabat Aug 25 '20 at 10:13

6 Answers6

25

For the best approach of handling unsupported framweorks for Catalyst, you guys should read the solution of Fernando Moya de Rivas, he has a github with a solution here with more up to date information.

He basically said you just need to define an array of all of the libs you don't want to install on mac osx, like this: ['Fabric', 'Crashlytics', 'Firebase/Core', ...].

Then, your pod file can look simple as this:

# 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
thecoolwinter
  • 861
  • 7
  • 22
Oz Shabat
  • 1,434
  • 17
  • 16
19

Following @ajgryc answer, I was able to make a sleek solution:

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

Since 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

And then in run script build phase for Fabric:

if [[$ARCHS != "x86_64"]]; then
  "${PODS_ROOT}/Fabric/run" [your usual key]
fi
Tancrede Chazallet
  • 7,035
  • 6
  • 41
  • 62
  • 3
    This works well to disable all CocoaPods from being linked in MacCatalyst. Change the third line to `if target.name.start_with?("Pods")` to catch all Pod targets. – William Denniss Dec 01 '19 at 19:33
  • This doesn't seem to work anymore with cocoapods 1.8.4 – tmm1 Dec 20 '19 at 23:03
  • 1
    I tried both way "if target.name.start_with?("Pods")" does not work for me also with cocoapods 1.8.4, I got below error, anybody can guide me. in /Users/ios/Desktop/xxxxxx/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector(FIRConnectorUtils_d79571aba36a7d46e5c6ca87a6fec1c1.o), building for Mac Catalyst, but linking in object file built for iOS Simulator, file '/Users/ios/Desktop/xxxxxx/Pods/FirebaseAnalytics/Frameworks/FIRAnalyticsConnector.framework/FIRAnalyticsConnector' for architecture x86_64 – Ankur Patel Jan 01 '20 at 04:14
  • 4
    For the run script, you can also use: `if [[ ${IS_MACCATALYST} != "YES" ]]; then "${PODS_ROOT}/Fabric/run" fi` – Honghao Z Jan 11 '20 at 07:31
  • Can you update an answer to include a link to an issue in cocoa pods so that people reading an answer can upvote it? This should be supported out of the box in my opinion. https://github.com/CocoaPods/CocoaPods/issues/9364 – KleMiX Jan 15 '20 at 17:45
  • @AnkurPatel After do above step i get below error. Undefined symbols for architecture x86_64: "___gxx_personality_v0", referenced from: +[FIRCLSDemangleOperation demangleBlockInvokeCppSymbol:] in FirebaseCrashlytics(FIRCLSDemangleOperation.o) For full error log: https://drive.google.com/file/d/1Za3gGH8F-7iq4DBTXkXe9UnZmSg4legH/view?usp=sharing – Yogendra Patel Dec 24 '20 at 09:17
13

Open your Pods-$projectname.release.xcconfig file in your project's Pods directory, and locate the OTHER_LDFLAGS line. Add [sdk=iphone*] immediately after the variable name (as an example, mine now looks like this):

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

That conditionally sets the link options only when building iphone variants, preventing the pod from being linked on OSX. Of course as you mention, this needs to be combined with #if !targetEnvironment(macCatalyst) and #endif surrounding the code calling the pod or you'll get linker errors.

This allowed me to get past the same problem. (And in case you're wondering what other cool things besides conditional variables you can add to your .xcconfig files, here's a reference I found: https://pewpewthespells.com/blog/xcconfig_guide.html )

ajgryc
  • 445
  • 3
  • 6
  • 1
    I have given you the bounty, but accepted my own answer as I give a solution out of the box which will make people's life easier, thank you very much! – Tancrede Chazallet Nov 08 '19 at 14:51
  • sorry, but where is a Pods-$projectname.release.xcconfig file. I am not able to find it. – Ankur Patel Jan 01 '20 at 04:52
  • In my config it is in /Pods/Target Support Files/Pods- – ajgryc Jan 03 '20 at 14:41
  • this solution isn't recommended as the xcconfig always build itself in every `pod install`. I would recommend to read [this Fernando Moya de Rivas's answer](https://medium.com/better-programming/macos-catalyst-debugging-problems-using-catalyst-and-cocoapods-579679150fa9) for the best alternative – Oz Shabat Mar 10 '20 at 06:50
10

I have an updated solution that works for me with the following Google pods:

  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
Andy
  • 1,815
  • 2
  • 22
  • 49
  • I'm trying to use this solution as it looks the most clean, but I get this error: `ld: in /Users//source//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` I use exactly what you have above minus the `GoogleMobileAds` and `Google-Mobile-Ads-SDK`. Why am I getting this? – fphelp Apr 01 '20 at 22:07
  • I’m not sure. At this point it’s time to remove Fabric isn’t it? I don’t agree that Google had the right to buy them, but they did and are shutting it down so... – Andy Apr 01 '20 at 22:28
  • Sadly using 'pod Crashlytics' automatically installs Fabric (1.10.2). Not sure why that happens and am cautious about using the 'Firebase/Crashlytics' pod because Google says that that's still in the beta stage :( – fphelp Apr 02 '20 at 00:17
  • Does anyone get a build failure with error "unsealed contents present in the bundle root" when doing this? – Sam Spencer Jun 16 '20 at 17:21
  • @user13138159 I m trying the above solution but it gives me the error ld: in /Users//Desktop//Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a(GAITrackerImpl.o), building for Mac Catalyst, but linking in object file built for iOS Simulator, file '/Users//Desktop//Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a' for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) what ekzactly you did? – iMinion Jul 10 '20 at 19:52
7

With cocoapods 1.8.4, I had to adapt @AncAinu's excellent answer as follows:

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
tmm1
  • 2,025
  • 1
  • 20
  • 35
  • FYI, the latest release of Crashlytics is now open-source and thus compiles directly for Catalyst when needed. This hack is no longer required in the case of Crashlytics, but can be useful with other legacy pods. – tmm1 Jan 15 '20 at 21:00
  • in above Name of the Project part, we have to write name of the project file ? if target.name == "Pods-[MyProjectExample]". something like that or just paste the answer ? because it doest work for me – Bartu Akman Jan 16 '20 at 14:41
  • Yes you have to replace with your project name. – tmm1 Jan 17 '20 at 00:51
  • I done everything right. if target.name == "Pods-[VPNoid]" clean and build my project again. but still error is complaining. Do u have any idea ? – Bartu Akman Jan 17 '20 at 06:30
  • 1
    Remove the `[]` – tmm1 Jan 17 '20 at 21:02
3

Based on what has already been discussed here... here is my solution for projects with multiple targets. It basically is validating the usage of the libs on each target instead of following the target name.

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


It outputs something like this

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
ZYiOS
  • 5,204
  • 3
  • 39
  • 45
JMiguel
  • 1,459
  • 1
  • 10
  • 12