This library allows you to create and manage multiple environments with a single application, just as if you were swapping containers.
This is useful when you want to test multiple accounts in a staging application.
Language Switch: 日本語.
Normally there is one environment (Directory, UserDefaults, Cookies, Cache, ...) for one app.
To have multiple environments for debugging or to handle multiple accounts, multiple identical apps must be installed. (with different bundle IDs).
In debugging, there may be cases where accounts are repeatedly checked by logging in and logging out.
Therefore, we thought it would be possible to create multiple environments within the same app and switch between them easily.
This is why we created this library called AppContainer
.
Default | Debug1 |
---|---|
Selet Container | Container List | Container Info |
---|---|---|
extension AppContainer {
static let group = .init(groupIdentifier: "YOUR APP GROUP IDENTIFIER")
}
let container = try AppContainer.standard.createNewContainer(name: "Debug1")
The original container is named DEFAULT
and has a UUID of 00000000-0000-0000-0000-0000-0000-00000000000000000000
.
You can check it with the property isDefault
.
let containers: [Container] = AppContainer.standard.containers
let activeContainer: Container? = AppContainer.standard.activeContainer
It is recommended to restart the application after calling this method.
try AppContainer.standard.activate(container: container)
try AppContainer.standard.activateContainer(uuid: uuid)
If the container you are deleting is in use, activate the Default container before deleting it.
try AppContainer.standard.delete(container: container)
try AppContainer.standard.deleteContainer(uuid: uuid)
try AppContainer.standard.clean(container: container)
try AppContainer.standard.cleanContainer(uuid: uuid)
Revert to the state before this library was used. Specifically, the DEFAULT container will be enabled and all other AppContainer-related files will be removed.
try AppContainer.standard.reset()
You can receive notifications when switching containers. If you want to add additional processing to be done strictly before and after the switch, use delegate as described below.
- containerWillChangeNotification Before container switching
- containerDidChangeNotification After container change
Delegate can be used to add optional processing when switching containers. The actions are performed in the following order.
// the `activate` method is called
// ↓↓↓↓↓↓↓↓↓↓
func appContainer(_ appContainer: AppContainer, willChangeTo toContainer: Container, from fromContainer: Container?) // Delegate(before container switch)
// ↓↓↓↓↓↓↓↓↓↓
// Container switching process (library)
// ↓↓↓↓↓↓↓↓↓↓
func appContainer(_ appContainer: AppContainer, didChangeTo toContainer: Container, from fromContainer: Container?) // Delegate (after container switch)
This library allows multiple delegates to be set. Add the following.
AppContainer.standard.delegates.add(self) // if self is AppContainerDelegate compliant
It is held in a weak reference and will be automatically released when the object is freed. If you want to unset the delegate, write the following.
AppContainer.standard.delegates.remove(self) // if self conforms to AppContainerDelegate
When switching containers, almost all files except for some system files are saved and restored to the container directory. You can set files to be excluded from these moves.
For example, the following is an example of a case where you want to use UserDefault commonly in all containers. This file will not be saved or restored when switching containers.
appcontainer.customExcludeFiles = [
"Library/Preferences/<Bundle Identifier>.plist"
]
All file paths that end with the contents of customExcludeFiles will be excluded from the move.
For example, the following configuration will exclude the file named XXX.yy
under all directories.
appcontainer.customExcludeFiles = [
"XXX.yy"
]
Provides UI for using AppContainer. SwiftUI and UIKit are supported.
import AppContainerUI
// show Container List
ContainerListView(appContainer: .standard, title: String = "Containers")
// container info view
ContainerInfoView(appContainer: .standard, container: container)
import AppContainerUI
// show Container List
ContainerListViewController(appContainer: .standard, title: String = "Containers")
// container info view
ContainerInfoViewController(appContainer: .standard, container: container)