How to make sure whether my static library works fine - ios

We are developing a Xamarin iOS application by making use of SUP MBOs. We have generated the code in Objective C and in order to access it from C# code base(Xamarin), this generated code should be bundled as a static library (.a file) with some SUP specific static libraries and SUP header classes. We are able to create universal static library file(.a file) with help of Build fat static library (device + simulator) using Xcode and SDK 4+
Now my question is how to make sure whether the universal static library file which we have created is working or not?
We have created a sample static library file by just implementing a add method and were able to access it through C# code(using Xamarin) but we are getting this error -## MT5211: Native linking failed, undefined Objective-C class: _OBJC_CLASS ## when using SUP generated code. we are giving all correct values to all properties in build setting of Xcode "other linker flags", "library search path", "header search path" but I have no idea how we can go ahead with this. We are not sure whether we are missing something or in wrong path?

The best option is to create a Binding project for the native library (and a corresponding test application that exercises the binding project to make sure it works).
If you have any problems (build/linker/runtime errors), we'll need to see the header file, the binding code you've created and the full build output in order to diagnose the problem properly.

Related

How to create SDK for iOS in Swift?

I have my own Xcode project which contains some controllers. I want to make its SDK, for use it in another application. In parent application it works as child. Parent app will share some data with my controller and my controller works on it and gives back some result. So kindly guide for me. Examples are - Payment Gateway SDK's. I am looking for the same.
I can see you add tag for swift. In Swift, static libraries are not supported, so you must exclusively use a framework (aka dynamic library) when linking an app to a library. Framework is similar to sdk.
Here are the steps:
1)Create the Framework using New > Project under IOS > Framework & Library, select Cocoa Touch Framework
2)To avoid the "ld: warning: directory not found for option..." goto Library Search Paths in Build Settings for your target and delete the paths.
3)You can't mix Objective-C with Swift so don't even consider adding the Swift-Header bridge file in your code.
4)There are some cases in swift where you need to import code from unexposed Frameworks. I've successfully used the module-map inside the framework to deal with these case.
5)I also select CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES in the Build Settings to solve 'include of non-modular header inside framework module'. That seems to work
6)I make sure that the header file that gets generated is marked as Public (not Project). Click on the file and you'll see the selection in the inspector under 'Target Membership'
Link
Also you can follow this tutorial. Since you have already created project.
Create a framework target, make all source code files a member of the new target, add the new target as target to the podfile. For everything else the tutorial should work. It should help you in understanding the steps.
Build framework

How to build iOS framework with XCode 6

I know of familiar tutorials on this, but introduction of framework XCode 6 template has changed the game.
I already watched WWDC 2014 video about building modern frameworks but it talks more about building extensions, framework & app all inside single project. It does not specify if the framework I make with it is truly reusable across any project.
I am building framework the XCode 6 way (File->New Project->Framework and Library->Cocoa Touch Framework), but when I import it inside my test app project (separate from framework project) - I keep getting various errors.
Example: Include of non-modular header inside framework, and so on.
I know this is not what it says, and there are quite some missing steps in whatever I am doing. The older tricks may have worked for everyone, but I simply don't find which way to follow after XCode 6.
For example, there is some folder structure that a framework needs, but XCode 6 doesn't comply to it while building it. Is it right? If not, how can I change the way the XCode builds framework folder hierarchy?
Do I go back to old school or am I screwing some tiny thing in XCode 6 that I am unable to create a reusable framework?
I am not sure if you are trying to build a framework with Objective-C or Swift as your question doesn't state it. I've encountered errors you are mentioning with Swift so I'll give you my method to build Swift frameworks.
I found the process for Objective-C to be very straightforward and well documented, so I'll skip this.
As for Swift, there are a few things to consider. First, Swift static libraries are not supported, so you must exclusively use a framework (aka dynamic library) when linking an app to a library.
Here are the steps:
Create the Framework using New > Project under IOS > Framework & Library, select Cocoa Touch Framework
To avoid the "ld: warning: directory not found for option..." goto Library Search Paths in Build Settings for your target and delete the paths.
You can't mix Objective-C with Swift so don't even consider adding the Swift-Header bridge file in your code.
There are some cases in swift where you need to import code from unexposed Frameworks. I've successfully used the module-map inside the framework to deal with these case.
I also select CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES in the Build Settings to solve 'include of non-modular header inside framework module'. That seems to work
I make sure that the header file that gets generated is marked as Public (not Project). Click on the file and you'll see the selection in the inspector under 'Target Membership'
You may run into some bizarre error messages when building. Xcode has a tendency to report linker errors when your code can't compile correctly resulting in missing files the linker needs to output its binaries. Sometimes XCode won't show the errors in the files you are compiling and you need to go manually on the build output and go back to the files. Some other time, you'll get a problem where you need to delete the cache. Those issues I call XCode blues and deal with it constantly. I found this type of problems happens more often when building libraries. The rest should work as expected.

Swift: using private framework

I have built an iOS Swift framework with Xcode.
After writing the code I have build the project and took the .framework file inside the Products folder to test it.
To test the framework have open a new application and drag and drop the .framework file previously built and I added it into the embedded binaries list of my application project.
To import it into my ViewController.swift class I wrote:
import frameworkName
No problem until here, this means that the project sees the framework.
When I try to use a public class inside the framework with:
var x : className?
I get the following error:
'className' is unavailable: cannot find Swift declaration for this class
What does it mean? What is the problem?
When you're referencing a framework in the products directory from your workspace, ensure that the location is "Built Products" and the filename is just the framework name, without any additional path components.
If you're referencing a framework that isn't in your workspace, I would recommend using Carthage instead of copying it directly into your repository. This will make versioning much easier, and will ensure that it is built correctly for both simulator and device.
To actual a self defined framework, u really have to do a lot of things.
Firstly, make sure ur framework is used on right device. It's to say framework can only be used on corresponding device(either one of Simulator, Device and Mac). In other words, if framework A built on simulator, project import framework A can only pass compile and successfully built on simulator.
P.S. if universal version desired, -lipo command is what u need to further explore.
Secondly, during implementing ur framework , make sure all the classes, methods and variables u want use outside start with Public.
Thirdly, check ur project setting Embedded Binaries and linked Frameworks and Libraries do contain ur framework.

What is a dynamic framework as opposed to a non-dynamic one?

Xcode 6 allows for dynamic frameworks.
What is a dynamic framework?
Both dynamic framework and static framework is a bundle containing a binary and some other things. The binary is called dynamic library or static library.
The binary is what you code is after compiling, your functions, classes, method become binary form, and they are called symbols.
When building your project.
Your code will be built into a binary, let's call it MyProjectBinary.
If your project links to a static library, then after building MyProjectBinary, linker check the symbols in MyProjectBinary and if it uses some part of the static library, for example, use a class in the static library), then linker will copy all the symbols related to the class and combine them in to MyProjectBinary. So no matter how many static library you use, you only get one building result, which is MyProjectBinary.
If you link to dynamic library, then you are telling the linker that, when MyProjectBinary is running, there will be that dynamic library at a suitable place. Dynamic library is not magic, in fact, you've used them for long time. All the frameworks Apple provides are dynamic libraries. They are guaranteed to exist when you app is running on device/simulator.
Let's assume that your project links to a dynamic library called MyDynamicLibrary. When building your project, first MyProjectBinary is still generated the same as using static library. Then, linker just add some information to MyProjectBinary, mark where to find "MyDynamicLibrary" at runtime. Nothing from MyDynamicLibrary will be add to MyProjectBinary
When running your project:
For the project using static library, nothing special happens, since all the code needed is inside MyProjectBinary, it just runs.
For the project using dynamic library, when your code calls a function which is in MyDynamicLibrary, the system tries to find MyDynamicLibrary according to the information stored in MyProjectBinary, if it finds MyDynamicLibrary, then for MyProjectBinary, the function is used like in MyProjectBinary. If it can't find MyDynamicLibrary, them an error will happen and you app will be terminated.
So why do we need dynamic library for iOS 8?
Before iOS8, an app can have only one executable binary, so using static library is OK.
But when iOS 8 comes, you can deliver multiple executable binary in one app, the additional binaries are extensions' executable binaries. This brings up a problem, if there are some code that are uses by multiple executable binaries, and if using static library, same symbols will be copied into every executable, thus takes more space. This is the time when dynamic library comes in handy, we can put these code in dynamic library, and deliver only one copy of the dynamic library for app, the app and its extensions can use the same dynamic library.

Don't we need to link framework to XCode project anymore?

Base on this question
Why don't iOS framework dependencies need to be explicitly linked to a static library
I read the selected answer and still don't understand so I made an example project
Test Project on Github
In the test project, I remove all framework from Link Binary With Libraries and File navigation for both main project and the static library (including Foundation.framework and UIKit.framework too), basically, both project link to 0 frameworks.
Questions are
In static library, it's including MapKit/MapKit.h without referencing the Mapkit.framework to the project, why is its still working?
In main project, I remove UIKit.framework and Foundation.framework from the project, why is it still working?
Since it's working for now, will there be any issue later?
Thank you for your comment.
P.S. By working, I mean I can run on the simulator and I can archive the main project without any error.
Edit 25/07/2014
I tried with the real app that I'm working on, it's the same.
I highlight Foundation, UIKit, CoreData and 10 another frameworks in File Navigation, well, all of them.
Uncheck the target in Utilities Panel --> Target Membership
Build : Pass, Run : Pass
Every functionality of my app is still working as expected. I don't get this.
Check your project build settings. Underneath LLVM 5.1 — Language — Modules you should see the option 'Link Frameworks Automatically'. In your case it sounds like it's set to 'YES', the default.
In that case, instead of producing an error when you reference a class that the compiler doesn't know, it'll figure out which Framework contains that class and link it. In your code it'll be MKMapView or one of the other MapKit classes that triggers the linkage.
EDIT: from the relevant 'What's New?' document:
Auto Linking is enabled for frameworks imported by code modules. When
a source file includes a header from a framework that supports
modules, the compiler generates extra information in the object file
to automatically link in that framework. The result is that, in most
cases, you will not need to specify a separate list of the frameworks
to link with your target when you use a framework API that supports
modules.
Another way of looking at it is that the compiler is smart enough to mutate #import to #import when the framework has been built appropriately. All system frameworks have been.
To elaborate #Tommy's answer, a framework that supports modules satisfies the following 2 conditions:
Under Build Settings > Packaging
Define Modules is set to YES
Module Map File exists.
So, if you're certain that the framework you're using in your code modularizes like that, you can choose to not explicitly add it in the link phase as it will be automatically added as long as in the project file, under Apple Clang - Language - Modules, The option Link Frameworks Automatically is set to YES.

Resources