Batch-iOS-SDK icon indicating copy to clipboard operation
Batch-iOS-SDK copied to clipboard

Batch 2.x is not linked at runtime using CocoaPods 1.15.2 (last version)

Open Narayane opened this issue 1 year ago • 11 comments

Summary

I try to upgrade Batch SDK from 1.21.2 to 2.0.1 with CocoaPods last version (1.15.2). No problems at Xcode compilation time but crash when I try to launch my app on an iPhone.

Reproduction steps

In my Podfile, I change

pod 'Batch', '~> 1.21.0'

for

pod 'Batch', '~> 2.0.0'

Logs

dyld[957]: Library not loaded: @rpath/Batch.framework/Batch
  Referenced from: <CEB1D1E5-FB69-3312-BB76-22708083FE33> /private/var/containers/Bundle/Application/3291B63B-EE83-47ED-8AB7-EE895CBB5BC4/MyApp.app/MyApp
  Reason: tried: '/Users/me/Library/Developer/Xcode/DerivedData/MyApp-ddejunqweisyqocnsoxzgngmnpnw/Build/Products/Debug-iphoneos/PackageFrameworks/Batch.framework/Batch' (no such file), '/private/preboot/Cryptexes/OS/Users/me/Library/Developer/Xcode/DerivedData/MyApp-ddejunqweisyqocnsoxzgngmnpnw/Build/Products/Debug-iphoneos/PackageFrameworks/Batch.framework/Batch' (no such file), '/usr/lib/swift/Batch.framework/Batch' (no such file, not in dyld cache), '/private/preboot/Cryptexes/OS/usr/lib/swift/Batch.framework/Batch' (no such file), '/private/var/containers/Bundle/Application/3291B63B-EE83-47ED-8AB7-EE895CBB5BC4/MyApp.app/Frameworks/Batch.framework/Batch' (no such file), '/private/var/containers/Bundle/Application/3291B63B-EE83-47ED-8AB7-EE895CBB5BC4/MyApp.app/Frameworks/Batch.framework/Batch' (no such file), '/Users/me/Library/Developer/Xcode/DerivedData/MyApp-ddejunqweisyqocnsoxzgngmnpnw/Build/Products/Debug-iphoneos/PackageFrameworks/Batch.framework/Batch' (no such file), '/private/preboot/Cryptexes/OS/Users/me/Library/Developer/Xcode/DerivedData/MyApp-ddejunqweisyqocnsoxzgngmnpnw/Build/Products/Debug-iphoneos/PackageFrameworks/Batch.framework/Batch' (no such file), '/usr/lib/swift/Batch.framework/Batch' (no such file, not in dyld cache), '/private/preboot/Cryptexes/OS/usr/lib/swift/Batch.framework/Batch' (no such file), '/private/var/containers/Bundle/Application/3291B63B-EE83-47ED-8AB7-EE895CBB5BC4/MyApp.app/Frameworks/Batch.framework/Batch' (no such file), '/private/var/containers/Bundle/Application/3291B63B-EE83-47ED-8AB7-EE895CBB5BC4/MyApp.app/Frameworks/Batch.framework/Batch' (no such file)

Specifications

SDK Version

2.0.1

Installation method

CocoaPods

Relevant development tools versions

Xcode 15.3 (15E204a) CocoaPods 1.15.2 (via Bundler) Swift

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

Additional information

My Podfile header

platform :ios, '15.0'
install! 'cocoapods', :warn_for_unused_master_specs_repo => false

# ignore all warnings from all pods
inhibit_all_warnings!
use_frameworks!

# Pod repositories
source 'https://cdn.cocoapods.org/'

Narayane avatar May 14 '24 09:05 Narayane

Hi,

Is the Batch pod in your main target or is it in a framework?

2.0 became a dynamic library, so you need to make sure that the pod is linked in your main target and that Xcode knows that it must copy it on build

abarisain avatar May 14 '24 11:05 abarisain

Hi,

Your are not in my main target and your are a xcframework (like Facebook which did the same thing as you with theirs SDKs)

Capture d’écran 2024-05-14 à 14 32 57

Capture d’écran 2024-05-14 à 14 42 57

But you are well declared in my relative Pods project in the same way as Facebook ones (in my example FBSDKLoginKit) and with them, I had nothing special to do in addition when I upgrade to theirs dynamic frameworks to work.

Capture d’écran 2024-05-14 à 14 34 28

Capture d’écran 2024-05-14 à 14 34 45

What have I missed?

Narayane avatar May 14 '24 12:05 Narayane

I'm gonna have to try to reproduce it on my end.

In the meantime, could you try adding it to the main target? I think it's not linked because it's a transitive dependency

You could look in your app's Build phases in "Copy Frameworks" and see if FBSDKLoginKit is there and if Batch is too

abarisain avatar May 14 '24 12:05 abarisain

Hi,

FYI you are neither defined (Batch.framework) in the ${PODS_ROOT}/Target Support Files/Pods-MyApp/Pods-MyApp-frameworks-${CONFIGURATION}-input-files.xcfilelist

${PODS_ROOT}/Target Support Files/Pods-MyApp/Pods-MyApp-frameworks.sh
...
${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework
${BUILT_PRODUCTS_DIR}/RxSwiftExt/RxSwiftExt.framework
${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework
${BUILT_PRODUCTS_DIR}/SigmaSwiftStatistics/SigmaSwiftStatistics.framework
${BUILT_PRODUCTS_DIR}/Solar/Solar.framework
${BUILT_PRODUCTS_DIR}/Surge/Surge.framework
${BUILT_PRODUCTS_DIR}/SwiftQueue/SwiftQueue.framework
${BUILT_PRODUCTS_DIR}/SwiftyBeaver/SwiftyBeaver.framework
${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework
${BUILT_PRODUCTS_DIR}/SwiftyMarkdown/SwiftyMarkdown.framework
${BUILT_PRODUCTS_DIR}/TinyConstraints/TinyConstraints.framework
${BUILT_PRODUCTS_DIR}/Turf/Turf.framework
${BUILT_PRODUCTS_DIR}/ViewAnimator/ViewAnimator.framework
${BUILT_PRODUCTS_DIR}/YouTubePlayer/YouTubePlayer.framework
${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework
${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework
${PODS_XCFRAMEWORKS_BUILD_DIR}/FBAEMKit/FBAEMKit.framework/FBAEMKit
${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKCoreKit/FBSDKCoreKit.framework/FBSDKCoreKit
${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKCoreKit_Basics/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKLoginKit/FBSDKLoginKit.framework/FBSDKLoginKit
${PODS_XCFRAMEWORKS_BUILD_DIR}/FBSDKShareKit/FBSDKShareKit.framework/FBSDKShareKit
${PODS_XCFRAMEWORKS_BUILD_DIR}/HEREMaps/NMAKit.framework/NMAKit

nor in the ${PODS_ROOT}/Target Support Files/Pods-MyApp/Pods-MyApp-frameworks-${CONFIGURATION}-output-files.xcfilelist

...
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwiftExt.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SQLite.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SigmaSwiftStatistics.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Solar.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Surge.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftQueue.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyBeaver.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyMarkdown.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TinyConstraints.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ViewAnimator.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YouTubePlayer.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBAEMKit.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit_Basics.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKLoginKit.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKShareKit.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NMAKit.framework

generated by my project build phase [CP] Embed Pods Frameworks unlike those from Facebook.

Narayane avatar May 14 '24 16:05 Narayane

Thanks

I can indeed reproduce that on a clean project. I wonder why Cocoapods isn't recognizing we're a dynamic framework while it did on our private testing podspec

abarisain avatar May 14 '24 16:05 abarisain

Perfect Let me know when you've fixed it. Thanks.

Narayane avatar May 14 '24 17:05 Narayane

We've yet to figure out a way to tame Cocoapods. It sets up the filelist in Pods/Target Support Files/Batch , we get a Batch-xcframeworks script and it even copies it into XCFrameworkIntermediates in the DerivedData build directory, but it forgets to tell Xcode to copy the framework.

I do not understand why. I tried mimicing PSPDFKit's podspec, adding preserve_paths, moving stuff around in the zip to match facebook's, etc... Nothing works so far.

In the meantime, just telling Xcode about the framework is enough to make it copy it.

https://github.com/BatchLabs/Batch-iOS-SDK/assets/312529/fe55dd6c-2072-45f4-8453-faee0d17da8c

Note that Xcode gives a warning about "changes being made to the file will invalidate the code signature": that's a cocoapod issue. We codesign the XCFramework as recommended by Apple, but cocoapods breaks down the XCFramework into a framework for no reason during build

abarisain avatar May 15 '24 16:05 abarisain

Hi, Maybe it is a problem with CocoaPods but by transitivity, it is a problem for you for the users who use CocoaPods to get your SDK... I pause my upgrade to 2.x for now, thanks.

Narayane avatar May 17 '24 10:05 Narayane

We're still working on finding a fix/workaround

abarisain avatar May 17 '24 10:05 abarisain

The issue is that CocoaPods's dynamic library detection relies on "ruby-macho". If it fails to open the framework binary, cocoapods assumes that it is a static library : https://github.com/CocoaPods/CocoaPods/blob/master/lib/cocoapods/xcode/linkage_analyzer.rb

This has the unfortunate side effect that if the library has a format that ruby-macho does not understand, the detection is broken.

I added print statements to this file, and this shows up:

MachoError for Pods/Batch/XCFrameworks/Batch.xcframework/ios-arm64/Batch.framework/Batch
Exception: Unrecognized Mach-O load command: 0x36

We don't know why we run into this. It may be because we added support for mergable libraries so that we can be used as a dynamic or static framework. It may also be that frameworks emitted by Xcode 15 with a specific configuration are not understood.

There are multiple CocoaPods issues here:

  • There is no way for us in a Podspec to say that we are a dynamic library and bypass auto detection
  • Cocoapods is severly out of date with its ruby-macho dependency. It is currently requiring ruby-macho-2.5.1 while ruby-macho is at version 4.0.1

We will raise an upstream issue while we debate about what our course of action is after additional testing to understand why our binary can't be parsed by their mach-o lib.

The two workarounds we have are:

  • Use SPM. Even with a Flutter project, as they give you access to the Xcode project, you should be able to use SPM.
  • Manually link the xcframework. This something you only have to do once, and it's better anyway as you keep the Privacy Manifest and code signature.

abarisain avatar May 17 '24 15:05 abarisain

Upstream issue: https://github.com/CocoaPods/CocoaPods/issues/12388

We're working on a workaround. It will take a bit of time as our release pipeline isn't designed to have specific builds for package managers, only a single universal one.

abarisain avatar May 20 '24 12:05 abarisain

Hello,

2.0.2 is out with a workaround. The CocoaPods build is no longer a mergable library nor is it codesigned due to bugs in CocoaPods.

Thanks for the report,

abarisain avatar May 23 '24 09:05 abarisain

Hi, Thanks for the fix 👍

Narayane avatar May 23 '24 12:05 Narayane