Search code examples
iosswiftcocoapodscodesignumbrella

iOS Umbrella Framework - codesign problem


I have an Umbrella Framework distributed throughs Cocoapods as vendored framework and compiled in release mode.

It works perfectly with simulator, but I have a problem with the code sign on the sub-framework nested in the umbrella layer.

This is the error:

dyld: Library not loaded: @rpath/Subframework.framework/Subframework
Referenced from: /private/var/containers/Bundle/Application/02AD328F-9E78-4D53-9C39-0C8639B00D81/sdkInteTest.app/Frameworks/Umbrella.framework/Umbrella
Reason: no suitable image found. Did find:
/private/var/containers/Bundle/Application/02AD328F-9E78-4D53-9C39-0C8639B00D81/sdkInteTest.app/Frameworks/Umbrella.framework/Frameworks/Subframework.framework/Subframework: code signature in (/private/var/containers/Bundle/Application/02AD328F-9E78-4D53-9C39-0C8639B00D81/sdkInteTest.app/Frameworks/Umnrella.framework/Frameworks/Subframework.framework/Subframework) 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.

Then, if I launch the application to sign the sub-framework with the following script:

pushd ${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Frameworks/Umbrella.framework/Frameworks
for EACH in *.framework; do
echo "-- signing ${EACH}"
/usr/bin/codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --entitlements "${TARGET_TEMP_DIR}/${PRODUCT_NAME}.app.xcent" --timestamp=none $EACH
done
popd

I get this error:

/Users/xxx/Library/Developer/Xcode/DerivedData/sdkInteTest-bbfpzsxuhjomfmaumywyncnbwbla/Build/Intermediates.noindex/sdkInteTest.build/Debug-iphoneos/sdkInteTest.build/Script-F9547ACC224017BF0030EA0B.sh: line 3: pushd: /Users/xxx/Library/Developer/Xcode/DerivedData/sdkInteTest-bbfpzsxuhjomfmaumywyncnbwbla/Build/Products/Debug-iphoneos/sdkInteTest.app/Frameworks/Umbrella.framework/Frameworks: No such file or directory
-- signing *.framework
*.framework: No such file or directory
/Users/xxx/Library/Developer/Xcode/DerivedData/sdkInteTest-bbfpzsxuhjomfmaumywyncnbwbla/Build/Intermediates.noindex/sdkInteTest.build/Debug-iphoneos/sdkInteTest.build/Script-F9547ACC224017BF0030EA0B.sh: line 8: popd: directory stack empty

Solution

  • The Solution

    The problem is that the script was starting when the pod wasn't already attached. The script should be run when all the pod jobs are done.

    I wrote a full guide to build an iOS Umbrella framework!

    The solution I found is the following:

    1) Step one:

    In the podfile of the integration project (not the umbrella project) add the following line of code where you add dependencies:

    script_phase :name => 'Sign', :script => './sign.sh'
    

    like this:

    target 'yourTarget' do
    
        # Pods for sdkInteTest
        #your pods goes here
    
        script_phase :name => 'Sign', :script => './sign.sh'
    end
    

    2) Step two:

    Than in the terminal at the root of your test Integration project:

    In the terminal type:

    touch sign.sh
    chmod 777 sign.sh
    open sign.sh
    

    And in the script file add this code:

    echo "Signing subframeworks"
    pushd "${TARGET_BUILD_DIR}"/"${PRODUCT_NAME}".app/Frameworks/YOURFRAMEWORKNAME.framework/Frameworks
    for EACH in *.framework; do
    echo "-- signing ${EACH}"
    /usr/bin/codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --entitlements "${TARGET_TEMP_DIR}/${PRODUCT_NAME}.app.xcent" --timestamp=none $EACH
    done
    popd
    
    echo "BUILD DIR ${TARGET_BUILD_DIR}"
    

    remember to rename your framework name.

    In this way you are telling to CocoaPods to run a script phase after the pod installation. Unfortunately this is a "client" solution, I tried to find a solution to apply at framework level without any luck.