IOS Microapps Architecture — Part 1

Artem Kvasnetskyi
6 min readSep 1, 2023

--

Not so long ago I decided to understand what Microapps architecture is, how it differs from usual modularity, and in general, how to implement it.

This is the first part where we will understand what modular architecture is, why we need it, and how to implement it in iOS.

In Part 2, we will focus on what Microapps Architecture is and how to implement it. Also, we will start developing our first app using Microapps Architecture.

Part two is now available to read!

There is no solution without a problem. So let’s start there.

Problem

In projects with a large code base, it can be painful to build and launch projects. It’s time-consuming during development and testing. This is especially noticeable when working with SwiftUI Canvas, which is impossible to work with in Legacy projects.

Annoying canvas

In addition, when working in a large development team very often we have to solve merge conflicts related to the project file, which also becomes routine. The applications we are used to seeing consisting of a single project file and containing all the above-mentioned problems are called monolith.

But sometimes a part of the application is complex and large enough to be treated as a separate product, maybe even reused in other applications.

This is where modularity comes in and is the key to creating software that can be scaled up and maintained over time, forgetting the issues mentioned above.

Modular Architecture

Modular architecture is a software design method that emphasizes the separation of program functionality into independent interchangeable modules. The application runs modules, the modules can depend on each other without cyclic dependencies, and on external dependencies.

This is an abstract pattern. It does not work like MVC or MVVM. Within each module, you can use the desired architecture, which will vary depending on the specific functions of the application. For example, you may have modules written in UIKit with MVP architecture, and SwiftUI modules written in MVVM.

The advantages of this approach are:
- Build time
Changing one functional module will not affect other modules. And the application will compile faster by recompiling only the changed module.
- Isolation of Change
When developing modules, there is clear responsibility for an area of code in the project, and when doing merge requests it is easy to see which module is affected.
- Fast testing
Tests are run only under a specific module.

Sounds cool and promising, but how can we implement this approach?

Methods of implementing modularity

You can implement modularity in IOS in different ways, for example, you can put individual modules in:
- Framework
- Git Submodule
- Subproject
- Cocoapods/SPM

Let’s take a look at each of them.

Framework

You can create a separate framework using Xcode to store your modules.

The first thing you need is a workspace where your project will be stored. In the Xcode workspace, to create a framework you need to select:

File New Project Framework Place Framework in the folder with workspace Select Add To Workspace.

Once you have created a module, you can import it into your project. In order to do this, just select:

Target General Frameworks, Libraries, and Embedded Content Add button Select Module

Let’s create some simple class inside the framework, to test if we can get it from our application.

import Foundation

public final class MyModule {
public init() {
print("Init called")
}
}

And now, in our application, let’s import our module and try to initialize this class.

import SwiftUI
import MyModule

@main
struct MyProjectApp: App {
init() {
let module = MyModule()
}

var body: some Scene {
WindowGroup {
ContentView()
}
}
}

Running this code we see in the logs that our object has been initialized. Congratulations!

This way you can take the logic out of your application into separate frameworks. The frameworks can depend on each other, cool, right?

But what if I told you that individual teams could interact with different Git to work on their framework? That would be even cooler! To do this, let’s take a look at what a Git Submodule is.

Git Submodule

Git submodules allow you to keep a git repository as a subdirectory of another git repository. Git submodules are simply a reference to another repository at a particular snapshot in time. Git submodules enable a Git repository to incorporate and track version history of external code.

https://www.atlassian.com/git/tutorials/git-submodule

Well, Git Submodule allows you to link to other repositories. Locally it will look like the files are part of the project, but in fact, they will be in a separate repository.

This approach works well with the previous one. For example, if you are going to reuse the Xcode Framework in multiple projects, or if you simply want to work with different Git repositories for the convenience of a large team.

There are only a few steps to connect a module to your repository:
1. Create a separate repository with your module (e.g. framework).
2. Enter the following commands in the terminal to initialize and download this module:

cd <path to project>
git submodule add <link to module's repo>
git submodule update --init --recursive

Also, you can do this with Sourcetree if you use it:

3. Drag and drop your folder/framework into your project/workspace as if you just had it lying around locally.

After that, you can use the submodule as code for your project. If this module is a framework — just integrate it as described above.

Subproject

It’s hard to believe, but your project can contain other projects, and interact with them. Sounds cool, right? Let’s see how we can do that.

Let’s start by creating a module as a separate Xcode project and some class in it.

After that, we should create a Static Library Target and share with it all the files we are going to use in the project. You can do this simply by selecting:

Project Add target Static Library

This is the end of the module development work. Let’s move to our project. First, let’s create a separate folder where we will put the modules. I called it Modules.

We then move our module to this folder and drag and drop the module into Xcode. You don’t need to select it to be a member of any targets. After that — specify “Header search path” in “Build Settings”. Basically, this is just the path to the folder with your modules. If you have more than one module, select the recursive option.

The last step is to configure the Link binary and add Target Dependencies.
Build Phase Link Binary With Libraries → Select your Static Library Mark as Required.
Build Phase
Target Dependencies Select your Static Library.

Now you can import your library, and use the module files in your main project. Congratulations!

import SwiftUI
import MyLib

@main
struct MyProjectApp: App {
init() {
let _ = ModuleClass()
}

var body: some Scene {
WindowGroup {
EmptyView()
}
}
}

Conclusion

This concludes the first part of this article. Next time we will consider what Microapps architecture is and how to implement it. We will implement it using Swift Package, so this modularisation method is not covered in this article.

I’d love for you to subscribe to me here and on my GitHub. Thank you!

References

Getting Started with iOS App Modularization
Working with submodules
Git submodules
Sub-Projects in Xcode

--

--