13

I have an xcode framework project that I've created, which I can compile into a myframework.framework file. After compiling, I drag this framework into the Frameworks project folder of my application, and then to make use of classes from the framework I add the proper import statement to any class that needs it; this allows my app to successfully compile with references to classes defined in the framework. To get the app to deploy successfully to my device, I also add my custom framework to the "Embedded Binaries" section for my target. With all this in place, I can build my app from xcode and run it on my device.

My problem comes when I attempt to Archive my application for the app store. When I attempt to do this, I get a ton of compiler errors where xcode says it cannot find the declarations for any of the classes defined in my custom framework.

How can I set up Archive in xcode so that it properly references and embeds my custom framework?

MusiGenesis
  • 71,592
  • 38
  • 183
  • 324
  • I'm having a similar problem to this, the only workaround I've been able to find was to import the entire framework project as a subproject of the app project. Would love to know if there's a better solution. – Danny Bravo Feb 26 '16 at 15:39
  • have you imported the headers for your framework ? – tgyhlsb Feb 26 '16 at 15:43
  • @Tanguy: where/how do I do that? – MusiGenesis Feb 26 '16 at 15:49
  • Have a look here http://www.raywenderlich.com/65964/create-a-framework-for-ios, and try to find some step you'd missed – tgyhlsb Feb 26 '16 at 16:03
  • @Tanguy: that's the tutorial I used to build my framework. Unfortunately, that tutorial says nothing about how to Archive a project for the app store (as I mentioned in my question, I'm able to build the app and deploy it from Xcode without any problems). – MusiGenesis Feb 26 '16 at 18:14
  • Could you share your project somewhere? Could you also show the very first error message you get? – sergio Feb 29 '16 at 15:29

4 Answers4

24

You actually don't need to put it in the "embedded binaries" section. You only need it in the "linked frameworks and libraries section. Make sure that your framework is a Universal Framework (meaning it can compile for all architectures), and make sure you have the right compiler flags set (-ObjC if your framework has any categories etc) There may be some other things you need to set as well like "Other C Flags" if your framework includes any c code and you want to enable bitcode in your client app then you should put "-fembed-bitcode" in your framework Other C Flags. Those were the things I needed to do to get my framework app to the store. I think its a just a misconception that you need to put this in embedded binaries as well to get it to archive for the store.

This is the build script I use to generate the universal framework. It builds right to my desktop. You can uncomment section 8 if your framework is in Swift. You want to create an aggregate target and add this as a run script in build phases.

# Merge Script

# 1
# Set bash script to exit immediately if any commands fail.
set -e

# 2
# Setup some constants for use later on.
FRAMEWORK_NAME="MyFramework"

# 3
# If remnants from a previous build exist, delete them.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

# 4
# Build the framework for device and for simulator (using
# all needed architectures).
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch arm64 -arch armv7 -arch armv7s only_active_arch=no defines_module=yes -sdk "iphoneos"
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch x86_64 -arch i386 only_active_arch=no defines_module=yes -sdk "iphonesimulator"

# 5
# Remove .framework file if exists on Desktop from previous run.
if [ -d "${HOME}/Desktop/${FRAMEWORK_NAME}.framework" ]; then
rm -rf "${HOME}/Desktop/${FRAMEWORK_NAME}.framework"
fi

# 6
# Copy the device version of framework to Desktop.
cp -r "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework" "${HOME}/Desktop/${FRAMEWORK_NAME}.framework"

# 7
# Replace the framework executable within the framework with
# a new version created by merging the device and simulator
# frameworks' executables with lipo.
lipo -create -output "${HOME}/Desktop/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"

# 8
# Copy the Swift module mappings for the simulator into the
# framework.  The device mappings already exist from step 6.
#cp -r "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule/" "${HOME}/Desktop/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule"

# 9
# Delete the most recent build.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

Once your framework is on the desktop, if you go inside of it there will be a text document with the same name as your framework. If you navigate to that and run the command "lipo -info" on it in terminal you should get the following output:

Architectures in the fat file: MyFramework are: armv7 armv7s i386 x86_64 arm64 
arc4randall
  • 3,146
  • 3
  • 23
  • 39
  • Well, I had to add the framework to the Embedded Binaries section in order to get the app+framework to deploy to my device from xcode (otherwise it will just compile but fail when you attempt to run it since the framework isn't deployed). When I remove it from Embedded Binaries the attempt to Archive still fails, but at least with a different error. – MusiGenesis Feb 29 '16 at 15:30
  • 1
    Are you sure that you have a universal framework with "Build Active Architectures Only" set to NO? When you build the framework make sure you build to a "Generic iOS Device" – arc4randall Feb 29 '16 at 15:35
  • 1
    Where do I tell if it's a universal framework? I currently have "Build Active Architectures Only" set to YES and I'm building for a specific device rather than the generic ones. I'll give this a try with those changes. – MusiGenesis Feb 29 '16 at 15:37
  • Thanks for your help, I think I'm almost there (based on the changes in build errors I'm seeing). Can you tell me exactly how to put "-fembed-bitcode" in my framework's Other C Flags? I can't find "Other C Flags" anywhere - is this "Other Linker Flags" from the "Linking" section? – MusiGenesis Feb 29 '16 at 15:49
  • updated my answer for the full steps. If your framework doesnt say that it has all of those architectures when you run lipo-info then it is not a universal library – arc4randall Feb 29 '16 at 15:50
  • In the framework target build settings (the normal one not the aggregate) search for Other C Flags, and that's where you put it – arc4randall Feb 29 '16 at 15:51
  • so I'm attempting to run your build script. I changed FRAMEWORK_NAME to "CILDataFramework" which is the name of my project and the target. But when I run the script I get `xcodebuild: error: The project 'CILDataFramework.xcodeproj' does not contain a target named '“CILDataFramework”'.` But I'm pretty sure it *does* have a target named that. – MusiGenesis Feb 29 '16 at 16:45
  • Try looking through this; https://medium.com/@syshen/create-an-ios-universal-framework-148eb130a46c#.1yogxxwoq and make sure you set up your aggregate correctly – arc4randall Feb 29 '16 at 17:15
  • Did this end up working out for you? What part are you stuck on? – arc4randall Mar 02 '16 at 15:42
  • it got me started, and I was eventually able to archive my app successfully (there was some additional Swift-specific weirdness I had to figure out). Unfortunately the app installed from the archive immediately crashes when trying to run it, so I'm trying to debug that bit. It crashes at the place where the xcode-deployed version crashes whenever I forget to embed/deploy the framework, so I suspect I still don't have the archive built correctly. – MusiGenesis Mar 03 '16 at 14:21
  • What does the crash message say? – arc4randall Mar 03 '16 at 14:26
  • Dunno yet, just got in this morning (haven't looked at any of this since Monday). Currently trying to figure out itunes connect which is a) telling me I can add up to 25 internal testers for testflight, but b) won't let me add any more than the 7 I currently have listed. – MusiGenesis Mar 03 '16 at 14:28
  • yeah, the crash is because the app installed from testflight isn't loading the framework: `Dyld Error Message: Dyld Message: Library not loaded: @rpath/CILDataFramework.framework/CILDataFramework Referenced from: /var/mobile/Containers/Bundle/Application/83A7AC56-8979-4D0B-AB95-6E89F409BD63/Chime.app/Chime Reason: image not found Dyld Version: 370.1` – MusiGenesis Mar 03 '16 at 15:11
  • Well, I added it to the project by dragging into the "Frameworks" folder in xcode, but it appears that if I do this the actual framework file is placed in the root project folder (in the same folder as the project and workspace files). – MusiGenesis Mar 03 '16 at 15:32
  • I believe this is your problem. You should place the framework in the folder with your project name (on the same level as your .h and .m files) from there you should drag it into the navigation panel in Xcode and select "copy items if needed" – arc4randall Mar 03 '16 at 15:34
  • I tried that, but it doesn't appear to have had any effect. I have the framework in my Linked Frameworks section, and I manually added it to the Embedded Binaries. I placed the framework into my project folder as you suggested, and then dragged it into my frameworks folder in xcode - and I see that my framework is now still in the project folder (not at the root like it was before). But when I archive my app and open up the .archive file, I see all the other frameworks that my project uses in the DSym folder, but nothing for my one custom framework. It does not appear to be embedded ... – MusiGenesis Mar 03 '16 at 15:44
  • ... in the archive anywhere. – MusiGenesis Mar 03 '16 at 15:44
  • Question: when I build my framework (like, just the framework and not the app) do I also need to Archive the framework (instead of just building it)? – MusiGenesis Mar 03 '16 at 15:45
  • you need to take it out of embedded. It does not need to go in there. I have my own custom framework installed in an app which i push to testflight then the store all the time, and it is not in embedded binaries. I had trouble archiving when I put it there – arc4randall Mar 03 '16 at 15:47
  • you should not need to archive the framework. When you build the framework make sure you have "build active architectures only" set to NO, and make sure you build for a "Generic iOS Device" – arc4randall Mar 03 '16 at 15:48
  • Ah, it IS included in the archive, but it's actually embedded in the {appname}.app file created in the archive. Going to try this all again. – MusiGenesis Mar 03 '16 at 15:51
  • So, if I don't add the framework to the embedded binaries section, the archive build is created but does not contain my framework anywhere in the archive, so the first attempt to run fails. If I add the framework to the embedded binaries section and then archive, I see my framework in the "Frameworks" folder of my .app file (inside the archive) but when I attempt to upload the archive to the app store, it fails with ERROR ITMS-90206 "Invalid Bundle ... {myframework}.framework' contains disallowed file 'Frameworks'. This appears to be a cocoapods problem, sigh. – MusiGenesis Mar 03 '16 at 17:46
  • I don't know about frameworks folder and .app. I just know it should not be in embedded binaries. The only places I see my framework are: The Navigation Panel, Linked Frameworks and Libraries, Link Binary With Libraries, The Project Files Folder. If you compile the framework using the aforementioned build script, and check that it is universal, this should all work for a framework written in Objective-C. If you are using Swift, you need to enable Modules and edit your frameworks modulemap – arc4randall Mar 03 '16 at 17:58
  • This shouldnt be in any frameworks folder or apps folder, it is just linked when you build the project because it is in your bundle – arc4randall Mar 03 '16 at 17:58
  • I am using Swift, I probably should have mentioned that (there's an additional glitch where you have to manually copy the Swift-related dylib files from one location in the archive to another, or else you get "Invalid File" when you attempt to upload to testflight). How/where do I enable Modules and edit the frameworks modulemap? – MusiGenesis Mar 03 '16 at 18:12
  • thanks so much for your help, I finally got everything working. The final thing that was killing me was that my custom Framework itself contained a `/Frameworks/` folder with the Swift-related dylibs in it, which the App Uploader flagged on and refused to upload. I had to go into the archive and just delete this entire folder; then I was able to upload to testflight and when I install the app the framework is properly referenced. WHEW!!!! – MusiGenesis Mar 03 '16 at 18:31
  • You'll get the bounty for this, but I'm going to leave the question open in case other users see this and have any additional information. I'm still not at all comfortable with how much manual hacking of the archive I have to do for this to work at all. – MusiGenesis Mar 03 '16 at 18:33
  • I seem I need a guard to avoid loops when I put this in run script. – Mickaël Rémond May 04 '16 at 16:49
  • Hi Guys The Framework not created on Desktop Automatically. Project build successfully Build folder create successfully in my project directory but in build folder i can not find any framework – Ankur Patel Nov 23 '16 at 06:26
  • I usually use a different approach - I don't try to pigyback the existing target framework with fat lipo code, but create a new Aggregate build target and create a script that builds all archs in a row and then lipo them and copy to /build folder inside the project. – JustAMartin Jan 20 '17 at 14:01
  • Do the script require any change if the framework have pod dependency also? In my case I added this script but it is showing me error as "no such module" and the module is the framework installed from Pod. – Nandkishor Chaudhari Mar 19 '19 at 13:31
11

Not sure if the existing answers help you. I'll just give my solution. First, I want to explain several important Build Phases.

Target Dependencies

If you want to rebuild your own framework (which you linked to the same workspace) every time you build your host app. You'll need to added the framework target here.

Link Binary With Libraries

If you want to use your library in your code (say you want to do import MyFramework), then you need to linked it in this phase.

Embed Framework

This is the tricky part. Embed means to bundle the framework together with your app when distributing. For a system framework, such as AVFoundation, you don't need to embed it into your app since it already exists inside the iOS operation system. However, for your custom frameworks or third-party frameworks, you'll have to embed them into your app bundle so that when you deploy your app on the device, the app can actually find it. That's why if you use Cocoapods or Carthage, they all have an extra build phase to copy the frameworks to the app bundle. (For Cocoapods, it's called Embed Pods Framework and for Carthage, it's an action that runs copy-frameworks script) So for your custom framework, you'll either use the existing Embed Frameworks build phase or create a New Run Script Phase to copy the frameworks to your app bundle.

-- Update on 2017-05-17 --

For the embed framework stuff, there's another important fact I found recently:

You can use file PATH/TO/Framework to check whether a framework is static or dynamic. Check this stackoverflow question for details.

Dynamic Frameworks

Only dynamic frameworks need to be embedded into the app. These include the ones created by Carthage and Cocoapods. If you open the app bundle after you build your project, there's a Frameworks folder that contains all your embedded frameworks and you'll find the ones created by Carthage and Cocoapods as well as the ones you specified in the Embed Framework phase.

Static Frameworks

So now you might wonder where are those static frameworks? How can we still use it if it's missing from the app bundle? You're right. They are in the bundle but not in the Frameworks folder. They have been merged into the executable of your app. If you check the size of executable, you'll realise every time you add a static framework to your target, it will increase.

Static frameworks don't have to be embedded (just Link them), it's like a .swift or a .xib file that will be compiled into your executable.


And then, there's one more step to go before you can use any framework. The Framework Search Paths inside target Build Settings. Again, if you look at Carthage or Cocoapods, they all add extra paths into this setting. This tells Xcode (or the underlying compiler) where to find these linked or embedded frameworks.


So every time you'd want to use a framework, make sure you think about the above settings and you're all set. I've been using this method for a while and feel more confident when I encounter any linking issue.


Finally, there's a very important article from Apple you should read https://developer.apple.com/library/content/technotes/tn2435/_index.html

Community
  • 1
  • 1
J.Wang
  • 1,088
  • 7
  • 12
  • Also, important fact from Apple Dev docs: "The app target is responsible for embedding all of the frameworks, including any frameworks that other frameworks depend on." - else you will have problems with nested dependent frameworks that will not get signed because they won't appear in the Copy step. – JustAMartin Jan 20 '17 at 13:34
0

I had the exact same problem. If you use app extension like me, and the archive error message is only associated with the app extension.

Remember that you have to MANUALLY add your custom framework into the "Linked Frameworks and Libraries" section of your app extension. example pic

mate00
  • 2,181
  • 5
  • 21
  • 31
Sam
  • 5
  • 2
0

Hope this will help you

  1. Select your Project in Targets. 2.Then search for Skip install.
  2. Change it into NO.
  3. Then archive your custom framework. (make sure to use Generic iOS Device ) as a target device.
  4. Export it to where you want. Then use it with your project.
Chen Yin
  • 338
  • 4
  • 15