👨🏻‍🏫 SwiftyLaunch Basics
SwiftyLaunch Modules

SwiftyLaunch Modules Overview

SwiftyLaunch Basics - Project Strcture

A SwiftyLaunch Module is a self-contained unit of code that is responsible for a specific feature or functionality of your app.

It should only contain the code that is relevant to fulfil the functionality of the module.

For example, if we take the AdsKit Module, it will only contain the code that is responsible for displaying ads in your application and nothing else.

A module exposes Views and View Models to other app modules, using the public keyword that is defined within the module source code.

AdBanner.swift
import GoogleMobileAds
 
public struct AdBanner: View {
 
    public init(adUnitID: String) { /* ... */ }
 
    public var body: some View { /* ... */ }
}

In order to use the AdBanner View in your app, we would first have to add AdsKit it to the Target we want to use it in

Adding the AdBanner View to a Target

After doing that, we can then import the module and use the AdBanner View in our code.

import AdsKit // import the AdsKit module
 
struct ContentView: View {
    var body: some View {
        VStack {
            AdBanner(adUnitID: "some-ad-unit-id") // use the publicly-defined AdBanner View
        }
    }
}

A module under the hood is a Framework project target (opens in a new tab) in Xcode, which has a up-stream working logic and is to be seen as a "dependency".

So, when a module X includes a module Y (as a "dependency"), it means that X can access anything that is public in Y. But Y does not have access to anything in X.

So, if we again take AdsKit as an example: AdsKit includes AnalyticsKit as one of its modules, in order to track events such as when a user views an ad.

AdsKit Dependency

Meaning that we can access features exposed by AnalyticsKit in AdsKit, such as the .capture function. So, when AdMob calls one of its delegate methods, we can capture it using AnalyticsKit.

import AnalyticsKit
import GoogleMobileAds
 
extension NativeAdBannerViewModel: GADNativeAdDelegate {
 
    /// Track when your users views an ad
    public func nativeAdDidRecordImpression(_ nativeAd: GADNativeAd) {
        Analytics.capture(.info, id: "ad_impression", source: .adsKit)
    }
 
    /// Track when your users click on an ad
    public func nativeAdDidRecordClick(_ nativeAd: GADNativeAd) {
        Analytics.capture(.info, id: "ad_click", source: .adsKit)
    }
}

If a part of the code is often used across multiple modules, it should be added to the SharedKit module, which represents the lowest common module of the app.

Here is a visual example of how the data flow works withing an app generated by SwiftyLaunch:

Example Data Flow

Module Structure

Every SwiftyLaunch Module follows the same semi-MVVM structure:

Module Inside Structure

Creating a new Module

To add a new SwiftyLaunch Module, in Xcode go to File > New > Target.

Adding a new module

In the dialog that appears, select Framework, and click on Next.

Selecting a framework

Enter Module's information and press on Finish.

Module information

After creation, delete the newly created folder (In the Alert dialog press "Move to Trash").

Folder Deletion

In Targets, create a new group with the same module name, and create a new Swift file in the group.

Creating a new group

Creating a Swift File

Make sure that the Swift file is belonging to the right module, by selecting the module in the right sidebar.

Selecting the module

Now, to test it out, define a new function, but make sure to mark it with the public keyword.

// ModuleContent.swift
public func twoPlusTwo() -> Int {
    return 4
}

Using the new Module

To call this function, we first need to make sure that the module is selected as a framework in the target we want to use it in.

The module will be added to to the App Target by default, but you can also include it in another module (in this example, AnalyticsKit).

Adding a module to a target

Now to call the function, import the module in the file you want to use it in, and call the function.

import MyModule
import SwiftUI
 
struct ContentView: View {
    var body: some View {
        Text("\(twoPlusTwo())") // 4
    }
}

Creating a Module via Tuist

If you're using the Tuist integration, refer to Defining a new module to see how to add a new module to your app.