phrase / ios-sdk

Phrase Over the Air iOS SDK
https://phrase.com
Other
14 stars 3 forks source link

Code signing fail when adding as sub-dependency #37

Closed lucasecf closed 3 years ago

lucasecf commented 3 years ago

What is it:

Crash Log

dyld: Library not loaded: @rpath/PhraseSDK.framework/PhraseSDK
  Referenced from: /private/var/containers/Bundle/Application/289B155F-C0DE-4031-9600-D2CF0224F887/PhraseTestApp.app/Frameworks/PhraseTestFramework.framework/PhraseTestFramework
  Reason: no suitable image found.  Did find:
    /private/var/containers/Bundle/Application/289B155F-C0DE-4031-9600-D2CF0224F887/PhraseTestApp.app/Frameworks/PhraseTestFramework.framework/Frameworks/PhraseSDK.framework/PhraseSDK: 
code signature in (/private/var/containers/Bundle/Application/289B155F-C0DE-4031-9600-D2CF0224F887/PhraseTestApp.app/Frameworks/PhraseTestFramework.framework/Frameworks/PhraseSDK.framework/PhraseSDK) not valid for use in process using Library Validation: mapped file has no cdhash, completely unsigned? Code has to be at least ad-hoc signed.
dyld: launch, loading dependent libraries
DYLD_LIBRARY_PATH=/usr/lib/system/introspection
DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib

Context

My company recently decided to integrate phrase's OTA SDK, and now I'm facing an issue a bit specific to our setup. Our project is modular, and all our external dependencies are added on an internal framework of ours, which is then linked to the main app target.

All other SPM packages are working totally fine on this setup. I'm not versed on Apple's code signing, but those other packages are regular open source projects, I guess the main difference here's that Phrase is using SPM to distribute the already compiled binary of the framework.

To highlight again, the issue only happens if Phrase is added through SPM in the internal framework - when adding to the main target directly it works fine.

Any feedback or suggestions are welcomed.

I created a sample workspace (app + framework + phrase added on framework) that reproduces the issue, you just have to run it on a real device.

PhraseTestApp.zip

winkelsdorf commented 3 years ago

Hi @lucasecf,

thanks for your report. As you already guessed, this is a signing issue (thus only affects the Device, not the Simulator). In this situation you likely need to take care of the signing of nested frameworks on your own. This is not related to Phrase SDK, it will happen with any Binary Framework.

See Apple TN2435 (https://developer.apple.com/library/archive/technotes/tn2435/_index.html), which I think is still valid. Under "Apps with Dependencies Between Frameworks" it points out that umbrella frameworks (a framework bundle that contains other frameworks) is not recommended and - here might be the solution - "The app target is responsible for embedding all of the frameworks, including any frameworks that other frameworks depend on".

I would try to embed the Framework with a weak link to the App Target itself, too (with Signing). Xcode's Linker & Code Signing should then be able to resolve the Issue for you.

I going to give your Demo a try later to see if that helps.

lucasecf commented 3 years ago

Hi @winkelsdorf , thanks for the quick feedback.

I'm aware of this signing issue/limitation from Apple side, but I'm new on adopting SPM, so I wondered if something changed or if there was any configuration that a binary framework could do in order to make this work.

I would try to embed the Framework with a weak link to the App Target itself, too (with Signing). Xcode's Linker & Code Signing should then be able to resolve the Issue for you.

I'm not sure how to do this actually, given Phrase is being added as a swift package on the internal framework with SPM.

I'd say that using Carthage or adding the framework manually is not an option, so I only see 2 ways right now:

Both are or course not desired. I'm currently following the second one, which has the obvious downside of having this single package declared "out of place" and us having to manage version in two places whenever needing to update the package etc.

If you have/know any other workarounds for the issue, it's highly appreciated!

winkelsdorf commented 3 years ago

Hi @lucasecf,

you're very welcome!

Yes, the problem are really the nested binary frameworks, that's why Xcode struggles to sign them properly (it's off-track as per TN) :( Please ignore my idea about integrating it in the App target itself with SPM. That would likely lead to duplicate framework targets within the App.

I did a bit of research and it looks like it's an Xcode issue even with 12.5.

It looks similar to https://bugs.swift.org/browse/SR-13343. Your message "mapped file has no cdhash" has been reported here, too: https://forums.swift.org/t/swiftpm-binarytarget-dependency-and-code-signing/38953/52. See the last ~ 6 posts there.

It looks like Xcode Code-Singing is applied after the files had been moved to the target location. If I were in your situation I would either create a Build Phase Script where I move and sign them manually (complicated) or just don't use SPM for Phrase and any other Binary Framework in your internal framework (or use CocoaPods for everything, where I know that they handle all Code-Signing and Copying Issues beautifully).

Without knowing Xcode Version, internal framework creation and usage (xcframework, framework, using SPM for publishing your framework, too), way of linking (static, dynamic) this is difficult to answer for me.

But..

Idea: Could you try integrating PhraseSDK directly into your internal framework (just drag the PhraseSDK.xcframework into it after removing it from SPM) and adjust the signing option for PhraseSDK in your framework:

image

I would guess that this might fix your issue.

lucasecf commented 3 years ago

Hi @winkelsdorf , Since there's nothing you can do/change in the framework side, I'll close this issue. Thanks again for the feedback/suggestions/links, I will evaluate with my team what's the best workaround for now.

winkelsdorf commented 3 years ago

Hi @lucasecf,

you're welcome and thank you for your feedback. Crossing my fingers for you and your team to find a suitable solution soon!

Best Frederik