Bundles are folders that the OS treats as one file .app is a bundle .framework is a bundle .bundle is a bundle .a is NOT a bundle
The Bundle API in Foundation is useful for navigating and loading resources inside of a bundle The simplest -- .bundle -- is used to share files and resources. We use .bundles for sharing APIEnvironment files: certificates, plists, etc needed to communicate with our APIs. Bundles can be shared between targets. For example, TestHarness in toolbox copies the API bundles during it's copy bundle phase into the .app bundle's Resources folder. You can load resources from these bundles using Bundle.main.urlForResource:extension: which will return the path to the bundle. You can then use the Bundle(url:) to get a representation of that Bundle. Or alternatively, you can give a bundle an identifier and use the Bundle(identifier:) initializer.
All bundles have a well defined directory structure with the Bundle API knows how to traverse. .app -> executable -> Resources -> Some.bundle -> Frameworks -> MyFramework.framework -> Resources -> MyFramework.bundle -> executable (.dylib, in this case) -> & more
Most resource related APIs: UIImage, NSLocalizedString, for example use the .main bundle for which Resources directory to check for the request resource, but for resources located in a framework, we have to locate the /Resouces directory inside of the Framework bundle, as the main bundle only contains the bundles copied in the Copy Resources Phase (the build system places these files in the /Resources directory of the .app bundle). This is why when you're developing your plugins you have to use the UIImage(named:bundle:compatibleWith:) API, passing in a reference to the Framework's resource bundle. Which you can obtain by using the Bundle(identifier:) or Bundle(forClass:) (the latter you must pass a class metatype that is a part of the framework target) to locate the aproprate bundle.
Dynamic Frameworks are a bundle where a .dylib is located inside the /Executable path of the Framework bundle. When you use a dynamic framework, iOS must "rebase" the instruction addresses in the dynamic framework to "line up" with the executable's address space. This rebasing is why apps are slower to launch when using dynamic frameworks. The benefit of dynamic frameworks, is that it effectively acts a promise that the code will be available in a certain locations (/Frameworks) so that symbols are only loaded as needed.
Static Libraries are at the other end of this spectrum. With static libraries, the product of a build is a .a
file, which contains the addresses, symbols, etc that are then included as part of the main application's symbol and address table. The drawback to using static libraries is that they can not include resources as part or their built product. This means that any resources that may be used inside the static library must utilize a separate resource bundle, that must be added to the consuming target's copy build phase. This also means that the location of that bundle will be in the app bundle's Resources directory.