Lazy Loading Dynamic Libraries and the Plugin-Architecture on iOS | by Scott Yelvington | MediumSitemapOpen in appSign up<br>Sign in
Medium Logo
Get app<br>Write
Search
Sign up<br>Sign in
Lazy Loading Dynamic Libraries and the Plugin-Architecture on iOS
Scott Yelvington
15 min read·<br>Apr 21, 2025
Listen
Share
Press enter or click to view image in full size
A few weeks ago I found myself merrily galivanting with my husband on a whirlwind vacation through Japan. Of course, I’m want to fully unplug, so on occasion while there’s downtime, I find myself giving social media a good scroll and a nerdy post caught my eye (truly deep and nerdy things do). The developer bravely took a dive into the performance tradeoffs of dynamic libraries vs static libraries. Naturally as a former desktop developer who spent a year researching Xcode’s build system, I got sucked into the discussion and was eventually challenged to prove out that lazy linking dylibs is still possible on iOS. Challenge accepted!<br>To recap: back in the early aughts, a concept was introduced within the linux community. Dynamic Libraries. Picture yourself in the thick of it. Binaries were getting big. Latency was much higher than it is now. What if you, on a humble dev team, wanted to update some module in your source code, but didn’t want to push the entirety of a new build. Tools like rsync were new unto the world using exchanges of hashes quickly transmitted over highly latent networks between remote end systems to determine file changes. Or perhaps your concern was that launch times were ballooning in your growing app. Again think of it from the standpoint of a build engineer. Maybe you’re publishing Adobe Photoshop or Microsoft Word. Your users are experiencing slow launch times. And your users may not even be touching above 5% of your actual source code during the entire app lifecycle, much less to complete a successful launch.<br>Do you really need a single massive binary just to launch your app? Do you really want to bog down your CDNs redundantly pushing modules that haven’t changed on latent connections when the minor update being pushed only affects a tiny fraction of the total binary? A natural conclusion one might reach as an enterprising build engineer is that it might be advantageous, rather than compiling a single gargantuine binary that’s linked at compile time, to build a tree of binaries that are linked at or after launch time. And thus the dynamic library was born. While static libraries are highly advantageous in lots of situations, dynamic libraries pair well with Plugin Architecture and allow developers to choose when to load the appropriate modules of code into and out of memory.<br>Picture this: a modern Plugin Architecture<br>You’re building the Facebook app. At launch you know your users will need a few things. You’ll want the UI components system for sure because duh there will be a UI. You’ll want the base models and API layer of your app because it’s cloud based. Your users will probably see videos and photos shortly after launch so you’ll want your core media decoder library to decode images and video. But then what? Do you need the camera and vfx module for those cool AR selfies? No. What about the calendar and/or events module? No. How about the marketplace module? In fact, what if your user hasn’t authenticated yet, and you’d like to shorten launch times even further by loading the security, UI, and API modules only?<br>This is where dynamic libraries and the plugin architecture shine. For most developers working on most apps, it’s probably best to stick with statically compiling your dependencies into a single binary. But in huge apps where users need a single digit percentage of the source code at launch, and perhaps even for the entire app lifecycle, dynamic libraries make a lot of sense. The app can determine conditionally when it’s appropriate to pull a module into memory.<br>But how?<br>We’re going to build a sample POC app that loads a dynamic library. To do this we’re going to do 4 things:<br>Create a sample framework, an interface framework, and a sample app, and load the frameworks into our sample app target’s build graph.<br>Configure our build architecture by ensuring that the sample framework isn’t linked at compile/link time.<br>Add the interface framework to the sample framework.<br>Load the sample framework at runtime on command and verify that it is not loaded at launch.<br>Step 1: Create the app and dynamic libraries<br>In Xcode, start by creating a sample SwiftUI iOS app project called MyHappyApp. You’ll will also want to create two framework projects called MyHappyFramework and MyHappyInterfaceFramework. Notice I didn’t create a workspace as we’re not using shared code between the modules outside of explicitly linked frameworks. Open the app project, go to the project settings and the MyHappyApp build target.<br>Press enter or click to view image in full size
Under the general tab, scroll down and look out for a section called Frameworks,...