How can frameworks used by a static library be automatically imported on iOS? - ios

My company makes a static library for iOS apps. One annoying step for developers is that they have to manually link against all the required frameworks that the library uses, and failing to do so leads to somewhat confusing compiler errors.
I would have previously thought this wasn't possible, but the company Chartboost claims to automatically link against non-default frameworks like AdSupport and StoreKit. Based on my testing in their sample app (available from the linked page), so far this appears to be the case (Even when disabling "Enable Modules" and "Link Frameworks Automatically" in the app that links against the static library).
Is there some way to enable this feature when creating a static library? I've tried enabling modules and the "Link Frameworks Automatically" LLVM options in Xcode, but so far haven't been able to get it working.

There's a piece of code called CBDynamicallyLoadedDependencies that calls dlopen() on the appropriate system library before making the function or method call.
My original answer wasn't correct. the dlopen() call is just in the x86 code. On the device, it's something different, but my ARM assembly isn't strong enough to figure it out. All I can say is that there's a piece of code that's acting as a trampoline to the desired functions and that references the system library files (like /System/Library/Frameworks/AdSupport.framework/AdSupport).
But the point is that it's not a simple project trick that makes it work normally. There's internal code involved.

They might use modules you mentioned and #import instead of #import, which should make the libraries link automatically.
For reference, check this question.

This might not be what you're looking for, but if you don't yet support Cocoapods, I would strongly advise taking a look:
http://cocoapods.org/
(Edit: Cocoapods is essentially linked to Xcode. Other IDEs will need another solution.)
You can advertise Cocoapods to developers as the "easy" way to work with your library, and the manual method as...well, the manual method. ;)
I'm not aware of any industry resistance to Cocoapods, so I don't see a downside to supporting it, and it does solve the problem you're talking about (albeit in a roundabout sort of way).
Also I've found Chartboost VERY developer-friendly. You might even reach out to them and ask.

Related

How to correctly build a swift framework for iOS

My goal is to build a swift iOS framework which uses two other frameworks (included as separate projects) and which shouldn't reveal the source code after built.
Is there some text/guide/documentation which would explain and navigate me through the process of building such a framework properly and correctly?
I built framework with aggregate target adding and linking frameworks on which my custom framework is dependent using run script as indicated here. I was able to add built of my custom framework to my custom app, together with other two dependencies (again as a separate projects), and run it on the device. However, I am not convinced by the correctness of my custom framework built.
Moreover, I was not able to upload the archive to the Appstore due to the various errors of "Unsupported architectures...", "CFBundleIdentifier Collision...", "Invalid Bundle...", "Invalid Binary" and so on. After sorting these errors out according to the various stackoverflow answers and installing the app from the TestFlight, the app crashed after launch and wasn't working at all.
I was checking various blog posts, stackoverflow questions/answers and Apple Framework Programming Guide but nothing gave me comprehensive understanding on building custom framework under conditions described above.
Everything I did was just following step-by-step tutorials without explanation of the purpose of the steps. I am sure I am missing the basics. Could you please help me and give me some guides?
I can understand you frustration. I, a while ago too searched probably for many documents on how to write a framework correctly but like you I also didn't find anything really that satisfying. From my own experiences I can give a couple of advices.
NO External Libraries
In my opinion DO NOT use external libraries in your own framework. I don't really know what your frameworks purpose is but most of the stuff you want to do can be done without using external libraries. Depending on other libraries is not a good idea especially if its a framework you are working on. Anytime these libraries get updated or even worse if they don't you will have to wait for them to be updated or find another library.So rather than this happening later on I think its better if you do it from the start. So loose the external libraries.
Universal Framework Binary
Second one is pretty easy. Generating a universal framework. I suggest you don't use a script. Most of the scripts I found were either outdated or they didn't work at all. Later on I found out that actually it was pretty easy to generate one on your own. You can do this by building your project once for a real device and one for the simulator.Then you can generate a universal binary by using the command lipo -create "Your simulator executable path" "your iOS device executable path" -output "your framework name". What this does is that it combines your two executable files and generates a universal one. Then you can just go and copy your simulator documents from the modules file and paste them in you iphoneos modules file. I am going to share a link were you can go through the walkthrough yourself. https://medium.com/wireless-registry-engineering/create-a-universal-fat-swift-framework-b7409bbfa18f
Use Objective-C(If you can)
This one is bit of a tricky one unless you know objective-c. What I would recommend is that you implement your framework using Objective-C and writing a swift wrapper around it. I would not have said this if you were creating an iOS app but in case of a framework I still think you should go for objective-c. This is because Objective-c has been around for over 30 years and most of the very old apps are in objective-c. If you want your framework to easily be used by older apps coded in objective-c I recommend you go with it. I have read tons of posts on how people have problems trying to use frameworks written in swift in their objective-c apps. Swift will be the first and probably only choice in the near future but not just yet. On the plus side if you still haven't you will have learnt Objective-C which will give definitely give you a better understanding on how things work. It will be challenging but I promise you it will be worth your while .I have a good read on this which you can checkout yourself. https://academy.realm.io/posts/altconf-conrad-kramer-writing-iOS-sdk/
Naming Conventions
This is a pretty straight forward one. I suggest you stick to apples naming conventions. This is because you will be sharing your code this time and people will look for familiarity when trying to integrate your framework. This will make your code easier to understand. You can check out these two links for more info.https://github.com/raywenderlich/objective-c-style-guide (obj-c) https://github.com/raywenderlich/swift-style-guide (swift)
Access Control
This in my opinion is an important one. When working on you framework think before you implement a class or a function. Consider if you would like someone else to be able to use that part of your code. You may want to limit the user while they use your framework and correct access control is the way to do it. You can easily guide the users so the users do exactly what you want them to do with your framework.
Document Your Code
This is a must if you want your framework be a professional one. You should be documenting every function and variable the user will use. Documenting and explaining what your code does makes a lot of peoples lives easy. You don't one anyone trying to understand what your code does for half an hour while you could have easily written a small explanation for what the parameters do and one that function or variable should be used for.
Test Your Code
Last but not least do write tests for your code. This does take some time but it assures you that your code works the way it should.
Look at other good frameworks
You should definitely checkout other open source libraries and look at what they have done. Usually there is no point in reinventing the wheel unless you are doing something absolutely different but even then there are very familiar ways to do things. I can suggest you check out the mantle sdk(https://github.com/Mantle/Mantle). Another one is the very popular Alamofire sdk(https://github.com/Alamofire/Alamofire) and also the Realm sdk(https://github.com/realm/realm-cocoa). These are good examples of frameworks. Take a look at them. Look how they have done things. It will give you an insight on how your framework should look like.
I know all of these points may also be valid if you were writing an app but what makes these a must is the fact that you will be sharing your code with others. You may manage by not doing some of these while implementing an app but for a framework things do change a little bit. It is always a pleasure to work with easy to use frameworks which make coding a pleasure. These types of small things will make your framework preferable. Happy coding.

Basic Mechanics of iOS Frameworks and Xcode (and Swift)

I think I just must be stupid.
I'm having a lot trouble understanding very basic things concerning frameworks in Xcode/iOs/Swift. While I've certainly gotten some things to work, I've gotten more and more confused about what I'm actually doing. And the documentation on the web just confuses me more.
When I see discussions about how to import particular frameworks (e.g. https://github.com/danielgindi/Charts is the library I'm playing with, but I've seen this pattern repeated in other libraries) they seem to always tell me include the Xcode project file as a child project of my project, in addition to linking things as an embedded binary. This confuses me. Is it not possible to link an already compiled framework to my project without including all the source code of the project?
That is, can't I just take a library.framework file, and add it to my embedded libraries list and be done with it?
In the frameworks I've played with (again https://github.com/danielgindi/Charts is my primary example, but this is true in many others I've played with) I can't seem to use the framework without Carthage or CocoaPods. For me at this stage, that is just confusing... I accept that they are useful tools to automate a difficult process, but I'd really like to understand what that process actually is before I let a tool automate it for me. As I search the web I just seem to always be led back to these tools as being the correct way to do things.
So here are my questions.
If I find a framework library on the web... do I need its source code or can I somehow just link to a compiled version of the framework?
In my reading, it seems that libraries made with Swift are somehow second-class citizens because Swift is a newer thing. Is that still the case? (The articles I read about this seems to date from 2014-2015).
Is there are good place to understand how Apple expects me to add a framework to a project, without using CocoaPods or Carthage?
No need to add source code. Just add the framework to Target ->
General -> Linked Framework and Libraries -> Tap on + and select
your framework.
In my opinion, many new libraries are being written is Swift. So you won't be left behind for using swift.
Apple has documentation about adding frameworks to XCode. But I would suggest to use Cocoapods , as its easy to manage libraries.
Cheers :)

Framework using library crash

I have 2 frameworks created by me that use (both of them) a library also created by me.
The first framework initialize the library and makes all its workflow. After finishing the first framework, the second one must start.
But when the second one is going to start, after initializing the library, the app using both frameworks crashes with a exc_bad_access error.
Apparently the library is created correctly, but if i comment the line of code to initialize the library in the second framework, the workflow continues (it crashes later because it has no library initialization).
Is there anything I'm doing wrong? Should I use two separate libraries instead?
EDIT:
Imagine the situation:
Framework A has this methods: start, stop. And while it works it delegate to the methods: infoFromA,frameworkAFinished.
Framework B has this methods: start, stop. And while it works it delegate to the methods: infoFromB,frameworkBFinished.
Both start methods initialize the static library mentioned (lets call it problematicLibrary).
Both frameworks present some views to make its functionality. So lets make an example of the app workflow.
At the app view viewWillAppear method, I start the Framework A just using:
[FrameworkA start]; , this will initialize the library and present a view. With this view (using my problematicLibrary) some info will be delegated to the infoFromA delegated method. And after all the info is delegated, it will delegate to frameworkAFinished.
When the FrameworkA has delegated to the frameworkAFinished I start the next Framework: [FrameworkB start]. As the other Framework, it will initialize the library and present a view. While debugging, all the initialization of the library is done (create the instances of the needed objects and a new instance of the library is created) and while its presenting the view it goes through the viewDidLoad method and then it throws an exc_bad_access error at the problematicLibrary initialization line (which has been done before and continued to present the view!!) without going into any other method from the view.
I have checked if the initialization is doing well, and all the variables were at null value before the initialization, and a new memory address is given to the library object.
This sounds strongly like a symbol conflict to me. I'm just surprised the linker didn't catch it, but I assume that's because you're using a static library in both your frameworks instead of simply yet another framework.
Generally speaking, I'd warn that "this is a bad idea™". What you're trying to introduce into your design is basically dependency management. Like a lot of blog articles and specifically this SO answer suggest, you should avoid packaging frameworks (and by extension libraries) into frameworks.
What most likely happens in your scenario is this (I admit I'm guessing a bit here): You linked the library into Framework A. Thus, the library becomes a fixed part of it. Its symbols are in it, even if you did not expose them to the app in any header files or the like. As long as you use only that, everything works smoothly. Then comes Framework B, of which the library is also a fixed part. Even though you can't see it from your app, the very same symbols are inside it. This, however, clashes with the symbols that were already loaded by Framework A, hence a crash (as said, this would usually be caught by the linker, but I guess you "tricked" it by building the frameworks beforehand and packaged the library in them). Maybe somebody else can explain this in more detail, but that quickly becomes besides the point as to how you would go for a solution. From how I see it, it just won't work this way.
So here's a suggestion for how you can solve your problem:
If you really, really need to split like this (two frameworks used in your app using the same dependency), I'd suggest removing the library from the frameworks (i.e. make them depend on it, but not package the actual .a file in them) and documenting that properly. Then add the library to your app project, just like you added the frameworks.
If you want to make this fancy and easily installable into other apps, I'd recommend setting up a private CocoaPods repository and turn your frameworks into private pods. You can then easily define the library (or rather "new Framework C") as a dependency for Framework A and Framework B. When you then pod install in your app, cocoapods figures out the dependency and adds Framework C automatically to your project. This scenario is exactly what cocoapods (or any dependency manager for that matter) was designed for. It automates and helps in the project setup, so that the final build (the app) doesn't have to figure out dynamically what it can and can't use. The end result is the same.
Trying to duplicate that "in code" quickly becomes messy. Frameworks trying to figure out things of the surrounding app/project that uses them (like "is my dependency so-and-so already linked? if not, can I load my own version of the library?") can lead to a lot of pain.
Okay, in response to your comment I'll try my hand at a more detailed How-To for the non-cocoapods setup. As a preface, though, let me say that that's kinda hard to do on top of my head, as I have no ready sample project to toy around with. Since this is one of those "set it up once and then forget aout it for a long time" I have to admit my recollection of these things is a bit fuzzy, so consider this as a sort of "rough direction". There might be things you need to configure differently than how I recall them. Other SO user are thus hereby invited to edit and correct my answer here, too. :)
First, I have to say I am not exactly sure whether you need to convert your static library into a framework or not for this, I think you don't so I'll go from here (I have never used a static library in that way).
That means you can leave the project that builds your library as is. On second thought, you probably have to do this to be able to link against the library without making it a part of the framework that uses it. I will still refer to this code as "library" in the below points, but assume that you're able to turn it into a dynamic framework as well.
The projects building Framework A and Framework B should be changed. I don't know how you have this set up (as one project with various targets, whether you have a "development application" as part of it to test the frameworks on themselves, etc.), but the important thing is that in the target that builds a framework, the library should be linked (i.e. in the "Link Binary With Libraries" build phase), but not copied (i.e. it must not be in the "Copy Bundle Ressources" build phase). It might be tricky to set up any development/test target you use to run, depending on how you did that so far. For example you might have to manually edit Library Search paths in your build settings to be able to properly compile the framework.
Lastly, you need to change your final app's project settings, obviously. The library that was originally part of Framework A and B now needs to be linked to from its project directly, and, obviously, it needs to be copied into the bundle as well. Note that any projects that include either of your frameworks (A or B or both) in the future must do so, otherwise they won't work, because these frameworks expect the library to be present (but no longer "bring it with them").
In spite of this long-ish text wall, it shouldn't be that complicated, I think, but you may still want to check out how cocoapods can support you with something like this, perhaps it's helpful in the future. The linked article expects basic knowledge on how to use a pod and write one, but the other guides on the site explain that pretty well. I am just saying this because in the end, when using cocoapods in a project to add multiple libraries/frameworks that introduce dependencies, it basically sets up your project in the way I described above. It uses some fancy shell scripts that ensure everything is copied to the correct folders and such, but overall speaking that's how it works: A pod's podspec tells cocoapods what additional pods to include in your app for it to work (a dependecy the pod expects to be there, but doesn't "bring in" by itself).
Check if they are both compiling for the same target.
Check if they have access to the same target membership.
Check build phases to see that they are both there.
I think because the first library is not 'well' referencing the second one.
Also i think that you can't import a framework inside another one.
To make things easier, you can merge the two frameworks on a single one.
Also you can add a callback (using protocols or closures) that informs for the end of the first workflow, and you use this callback to initialize the second framework. This way the initialization will not be made automatically.

Multiple frameworks and common library

Using iOS 8, Xcode 6.
Let's say I have 2 dynamic frameworks, frameworkA and frameworkB and they are both dependent on libC. In addition, I have an app that uses both frameworkA and frameworkB. My original thought was to make frameworkA and frameworkB umbrella frameworks and libC a subframework. However, Apple advises against umbrella framework and this post describes why umbrella framework is a bad idea due to potential linker conflict issue.
My second option is to use cocoapods (still new to this so a bit fuzzy on details) to use libC as a pod which then gets compiled into frameworkA and frameworkB. However, it occurred to me that both frameworks still has its own copy of the libC. Since the app uses both frameworks, will this result in a linker conflict issue as well? Is there a better way to solve this problem?
UPDATE
#Rob The projects I work on do require complex dependency management but I kept the problem domain simple in the question to try to better understand how and if using cocoapods can help solve the linker conflict issue with umbrella frameworks. I work with a team of developers who write libraries and can depend on each other's base libraries that provide versioned common APIs. We are required to package and deliver as few libraries as possible to a different organization that is building an app with our libraries and one of their key requirement is that we deliver a dynamic framework.
The best way to solve most problems is to put all the code in a project and compile it. When you have specialized problems that make that problematic, then you should look at other solutions, such as static libraries, and finally frameworks.
Static libraries can make sense if you have a code base that has pieces which require different build requirements. If all the pieces have the same build settings, then just "add files" them into your project from a "common" directory and build your project. Static libraries can be attractive if your build times are very significant and some pieces never change and you want to be able to "clean" without rebuilding those parts. But wait until you start having that problem before you go making complicated multi-package projects.
If you sell closed-source libraries, then frameworks are very attractive. You should strongly avoid adding third-party dependencies for the reasons you note. If you must, the best way is to help your customers package all the pieces as frameworks and have them link everything at the end. But that adds a lot of annoyance; so make sure you really need that third-party piece.
You might also consider frameworks if you have a very large piece of reusable code that has its own lifecycle separate from the main products. But again, keep it simple. Avoid third party stuff inside of it, and if you must have third party stuff, then have the consumers link it at the end.
(This isn't a new solution, BTW. When you use curl, if you want SSL, you need to also download and build OpenSSL and link them together yourself. Curl doesn't come with OpenSSL built in.)
But in the vast majority of cases, this is all overkill. Don't jump to frameworks. Don't jump to libraries. Just put all the code in the project and compile it. 90% of your problems will evaporate. iOS projects in particular just aren't that big usually. What problem is a framework solving?
If you have a lot of code that your organization uses repeatedly in lots of products, then I have heard many teams have good luck using internal CocoaPods to manage that. But that's just to simplify checking the code out. It still all goes into a project and you compile it together into one binary; no frameworks needed. Dynamic frameworks are a nice feature in for certain kinds of problems that were really painful before. But, for most situations, they're just complexity looking for a problem.
(If you have one of those specialized problems, edit your question and I'm happy to discuss further how you might approach it.)
EDIT: (You fall into that "specialized problem," so let's talk about it. I did, too, for many years inside of a large multi-team Mac and iOS dev environment. And we tried just about every different solution, including Frameworks. They're only new on iOS.)
Within an org like you describe, I would strongly recommend packaging each dependency as its own framework (AFNetworking, JSONKit, etc) and each of your pieces as a framework, and then have the app devs link all of them together at the end. In this way, it is identical to other dynamic libraries (libcurl, openssl, etc.) which require the app dev to link everything together.
In no case should dynamic frameworks include other frameworks that could otherwise be required (i.e. frameworks should never package "third party" stuff). That will explode. You cannot make that not explode. You'll either have bloat, build conflicts, or runtime conflicts. It's like merge conflicts. There's a point at which a developer has to make a choice. App-level linking is making that choice.
Making components over-dependent on other components is the source of decades of trouble, from Windows DLL Hell to iOS apps with competing crash handlers. All the best component systems look like Legos, where the end user assembles small pieces that have minimal dependencies. As much as possible, make your internal frameworks rely on nothing but Cocoa. This has some tangible design influences:
Avoid directly requiring logging or analytic engines. Provide a delegate interface that can be adapted to the engines of the caller.
Avoid trivial categories (methods that save just a few lines of code). Just write the code directly.
Avoid adding framework dependencies that aren't buying you a lot. Don't add AFNetworking just to save a few lines of code over NSURLConnection. Of course if you're heavily relying on the features of another framework, that's different. But as a framework developer your threshold should be quite high before requiring another framework.
Strongly avoid being clever in the build or version control. I've seen too many cases where people want to make everything "automatic" for the app-level developer, and so make the system really complicated. Just say "you need to link this and import this and put this in your app delegate startup." Don't create complicated build and version control systems to save 2 minutes on the first build or two lines of initialization logic. These things blow up and waste hours to work around. Don't get clever with +load magic. Just make it clear and consistent.
And of course, good luck. Supporting other devs is always an interesting challenge.

iOS SDKs: Renaming a lot of classes

I'm developing an iOS SDK that integrates other SDKs (Facebook SDK 3.5, for example).
To prevent collisions and allow my customers to import those SDKs as well, I want to rename all of the classes/enums in my code (for example, rename FBSession to RDFBSession, etc).
Is there an easy way to do this instead of going class-by-class and using Xcode's rename feature?
Apple provide a command-line tool called tops(1) that is designed for scripting large-scale code refactoring (renaming C functions, Objective-C methods, classes, and other tokens):
tops -verbose replace "FBSession" with "RDFBSession" Sources/*.[hm]
If you have a lot of replacements, you can put all of the replace... commands into a file that you pass with the -scriptfile option. The man page has more information on the more complex commands/options (and examples).
Xcode also offers textual Search and Replace. This will be faster than individual refactors, but it is ultimately less automated. You can make the step by step refactoring faster by first minimizing the project to the relevant dependencies/sources (if possible).
However, renaming the declarations in a library will not alter the symbol names of its associated binary. If it is distributed with a binary, then renaming will just result in linker errors or (in some cases) runtime errors.
The best idea if you need to use a 3rd party library which your clients might also use is to simply inform them they need to link the library with their app, then publish the version(s) the current release supports so they know they have some extra testing if they go too far ahead with some libraries.
I think that a better approach than simply renaming your classes would be to download Facebook's open source code, rename the classes there and compile a new static library with a set of renamed header files. Then you can be sure that no collisions occur and that you're using symbols that you named yourself.
I must warn you though - working like this may make updating the SDK a nightmare regardless of how you tackle this specific issue.

Resources