Shipping a Library/Framework in iOS
In this article we will discuss all about Framework/Libraries in iOS, from choosing between framework/library, designing, architecture, security measures, testing and publishing..
Before we start, lets understand what is an module, how they are beneficial
What is an module
> encapsulates code and data to implement a particular functionality.
> has an interface that lets clients to access its functionality in an uniform manner.
> is easily pluggable with another module that expects its interface.
> is usually packaged in a single unit so that it can be easily deployed.
More on Modular architecture in iOS
Modules in iOS ecosystem
In iOS we can ship an module as an library or as an framework, lets see how they differ from each other
Library
library is an pre compiled binary in swift IR format, it can be in any executable format like .a, unix executable etc.. library cannot have resources like images, xib's shipped as part of their executable...
Framework
frameworks are containers, they can have compiled binary, resources like images, xib's, different versions of their own libraries, other libraries wrapped in Umbrella fashion
Static vs Dynamic
static and dynamic are attributed to libraries/frameworks based on how they are linked into the application
Static libraries/framework are shipped as part of the client application binary, i.e lib/fw are embedded in the binary of the application which is using it when archived and the same is used when app is brought to memory.
Dynamic libraries/framework are not shipped in client application binary, its not shipped in application binary because all dynamic libraries/framework are part of the OS i.e iOS operating system itself, so these libraries/framework are linked to application environment during lunch time by dynamic loader dyld 🤔, and these are shared among multiple application
Static library
In iOS we are entitled to ship only static libraries, since shipping dynamic libraries means something which can be part of iOS system so we can't do much about it.
Dynamic library
UIkit framework is an constituted of many libraries internally, which are shipped as part of OS, and these are updated as part of iOS update. As an developer we don't have an option to write code which can be part of iOS operating system. (unless you work for Apple 😎) so its out of our options.
Static framework
As said earlier frameworks are containers, and if any of the dependent modules of framework are shipped as part of our binary then then it becomes an static framework...
example: lets say our framework named "A-framework"has dependency on other modules like "x","y","z" which in-turn are shipped in our binary rather then referencing the OS as dependency, then it becomes static framework
Dynamic framework
if modules which are framework dependents are linked dynamically at runtime, then its said to be a dynamic framework
Embedding vs Linking
Metrics to choose between static/dynamic - library/framework
1. Speed
static modules are fatter in getting the task done since they are explicit to app memory, while in case of dynamic modules since they are shared among multiple tasks across different apps where they are competing to get tasks done
2. Launch time
this part is tricky, if there less dependencies on internal dynamic libraries then dynamic modules are faster but takes more time if there are more dynamic libraries needs to be loaded this is because dynamic loader needs to resolve and load all dependencies (like a topological sort) which may take lot of time.
In case of static launch time is faster since all dependencies are shipped as part of app binary itself, so dyld doesn't have to search and load, but static frameworks might take more time if they are heavy i.e larger binary size
3. Binary size
static modules are heavier as all dependent libraries are packed as part of the application binaries itself, but dynamic modules are lightweight since all reference/links to dependent libraries are present and additional resources like images, xib's etc...
Design/Architecture
Exposing functionality : public - open
exposing your functionality/service to client should be done meticulously and to very limited extent, exposing unnecessary part will always be troublesome, this also includes choosing open/public access specifier for your module classes and functions, which defines how client can interact to them
Designing / Architecture :
choose a suitable architecture for your module, discuss with team, take time, fit everything properly. Most of the interactions will be. through. one common interface (follow fascade pattern) - followed by delegating the responsibilities to individual components (follow chain of responsibilities), also further if we decide to change our any internal services (say network layer), design such that there is minimalistic changes needed to adopt(follow clean architecture)
Error and State management
error propagation to client is very important to debug issues, create your own custom framework error type using enum(recursive ?? check whether its needed in your case), where we can propagate all kinds of error like network, system error, user defined error etc ..
state management; while we serve requests from client, client will be waiting cluelessly until our module returns output, check whether you can propagate states as we serve requests, so that client can also update the UI accordingly to user.
Security
- code visibility : if you have a kind of service, whose code you wouldn't wish to ship, then just ship the .framework or .library, else you can ship entire code base like Alamofire does.
- networking: you should always have an secure connection in all your network communications made in module, you can do so by protecting your API calls with TrustKit library, further you can have an product-licence kind of an identifier which locally authenticates clients from using services
- hosting : if you wish to open source your library then you can host on GitHub and cocoa repository for public availability, else you can just ship them via any convenient protected means like mail, or behind any authorised service.
Resolving module dependency at client end
1. GitHub - private/public
you can host your module at Github, make it public/private as per needs and. provide reference to it in pod file at the client side,
2. Local reference - private/public
client can download modules from any of there known sources manually like email, GitHub and provide local directory reference to the module at pod file.
3. Cocoapods - public
if vendor has published the module at cocoapods central repository, then client can get them by specifying the registered name in pod file
4. SPM - swift package manager
client can also use Swift Package Manager to resolve module dependency
Testing
unit testing target
you can create an unit testing target in your module, specify all dependencies in pod file, and test each functionality
sample project
you can also create a sample project, integrate you module and test. this is the most preferred way as you can share this with your clients as an example project.
if you need to debug the functionalities on the fly, you can < xcode->debug->attach to process > to do stack trace of your module functionality
Comments
Post a Comment