# InAppSettingsKit: Reusing Settings.bundle for In-App Preferences on iOS

> InAppSettingsKit renders the same Settings.bundle plist inside your app, so one plist drives both the Settings app and an in-app screen. It fits UIKit apps with existing bundles and disappoints anyone expecting a SwiftUI-native settings model.

**futuretap/InAppSettingsKit** — This iOS framework allows settings to be in-app in addition to or instead of being in the Settings app.

- Repository: https://github.com/futuretap/InAppSettingsKit
- Website: https://www.futuretap.com/blog/inappsettingskit-3-0
- Stars: 3,215 · Forks: 539
- Language: Objective-C
- License: NOASSERTION
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/futuretap-inappsettingskit

## The duplication problem InAppSettingsKit removes

An iOS app that offers preferences has two places to put them: the system Settings app, driven by a Settings.bundle, and a screen inside the app. Building both by hand means describing the same toggle, the same slider bounds and the same default value twice, then keeping the two descriptions in sync as the app changes. InAppSettingsKit takes the position that the bundle is the single source of truth. Its README states that it "basically just uses the same Settings.bundle to do its work", so adding a parameter means editing Root.plist once and it appears in both surfaces.

The audience is narrow and specific. This is a UIKit framework written in Objective-C, aimed at apps that already ship a Settings.bundle and want an in-app equivalent of it. The README names iOS, Catalyst and visionOS as targets. If your app has no bundle and no intention of appearing in the Settings app, the framework's central premise does not apply to you, and a hand-written settings screen will be less work than adopting this.

## How the plist becomes a view controller

The mechanism is a reader, not a store. The app supplies a Settings.bundle containing at least a Root.plist, which maps UI elements to NSUserDefaults keys. IASKAppSettingsViewController parses that plist and builds the table view from the specifier types it finds: text fields, sliders, toggles, child panes and the rest. Values are read from and written to NSUserDefaults under the keys named in the plist. The framework does not introduce a parallel persistence layer, and the README's settings storage and register default values sections describe how defaults are handled rather than a new database.

Because the plist schema is the contract, the framework's own feature set is expressed as extensions to that schema. The README lists custom in-app plists, privacy links, open URL, a web view controller, mail composer, buttons, multiline text views, date pickers, list groups, custom views, section headers and footers, dynamic multivalue lists, notifications and dynamic cell hiding. Each of those is a specifier or an attribute the framework understands on top of what Apple's Settings schema defines. The practical consequence: your settings screen is only as expressive as the plist you write, and anything the plist cannot say has to be handled through the custom view and child pane extension points.

## Installing InAppSettingsKit and pushing the first settings screen

The README documents three installation routes. With Swift Package Manager, add the repository URL as a package dependency in Xcode. With CocoaPods, add the pod to your Podfile and run pod install. With Carthage, add the GitHub line to your Cartfile. The README does not document a manual drag-and-drop installation as a supported path, so pick one of the three package managers.

For CocoaPods, the entry is a single line:

```ruby
pod 'InAppSettingsKit'
```

After running pod install, the framework is available to import. The next step is the bundle: the README instructs you to add a Settings.bundle to the project through File, then Add File, then Settings bundle, and to edit Root.plist with your settings. Without a Root.plist there is nothing for the view controller to render.

Displaying the screen is two lines in Swift. Instantiate the view controller and push it onto a navigation stack:

```swift
let appSettingsViewController = IASKAppSettingsViewController()
navigationController.pushViewController(appSettingsViewController, animated: true)
```

The README also shows embedding it as the root view controller of a navigation controller, which is the modal-style presentation. What you should see after running is a grouped table matching the specifiers in Root.plist, with edits landing in NSUserDefaults under the keys you declared. If the screen is empty, the usual cause is a missing or malformed Root.plist rather than a problem with the controller.

In a modularised app the bundle moves into a Swift package, and the README is explicit that this changes one thing: the controller's bundle property must point at the package's bundle.

```swift
iask.bundle = Bundle.module // IMPORTANT
```

The README marks that line as important because the default lookup will not find a bundle that now lives inside a package rather than the main app. It is the single most common integration mistake this framework invites, and the fix is one assignment.

## Where InAppSettingsKit stops being the right tool

The framework is UIKit-bound. The README's integration examples are a UIViewController subclass pushed onto a navigation stack, plus a UIViewControllerRepresentable wrapper for SwiftUI that exists precisely because the controller is not native to SwiftUI. If your settings screen is written in SwiftUI and you have no bundle, you are wrapping a UIKit controller to get a plist-driven table you did not need. The wrapper in the README is short, but it is a bridge, and bridges accumulate constraints.

A second limit is the plist itself. Settings.bundle is Apple's format with Apple's specifier vocabulary, and the framework extends it rather than replacing it. Anything that does not map onto a specifier has to go through custom views, custom child panes or the extension points for text fields and toggles. The README's Goodies section is long precisely because the base schema is not enough for many apps. If your settings need validation logic, dependent fields computed at runtime, or a layout that is not a grouped table, you will spend your time in the extension points, and at that point the plist is no longer saving you work.

The README also does not document rollback or migration behaviour for settings written by a newer version of the app and read by an older one. That is a gap worth knowing about before you ship a release that renames a key.

## InAppSettingsKit compared with building the screen yourself

The realistic alternative is not another framework. It is a hand-written settings screen backed by NSUserDefaults, with or without a Settings.bundle. The difference in approach is where the description of a setting lives. With a hand-written screen, each setting is a Swift or Objective-C declaration plus a view plus a binding, and the Settings app version, if it exists, is a separate plist that must be kept aligned. With InAppSettingsKit, the plist is the description and the screen is generated from it.

That trade favours the framework when your settings are numerous, conventional and stable: toggles, sliders, text fields, a few child panes. It favours the hand-written screen when your settings are few, or when they are entangled with app state in ways a specifier cannot express. There is also a maintenance dimension. A generated screen inherits the framework's rendering decisions, including how it handles new iOS appearance changes; the 3.9 release notes mention Liquid Glass improvements, which tells you the project tracks platform visual changes on your behalf. A hand-written screen gives you control and puts that work on your team.

## Maintenance, licensing and upgrade cost

The repository is not archived, and its last push was on 2026-05-04. Recent releases are 3.9, 3.9.1 and 3.9.2, all dated 2025-11-04, covering Liquid Glass improvements, an IASKWebViewFullscreen option and a web view content inset fix. That is a release cadence measured in months, not weeks, and the changes in that window are platform-compatibility work rather than new subsystems. Plan for the framework to keep working across iOS releases without expecting frequent feature additions.

Upgrade cost concentrates in two places. The first is the 2.x to 3.x transition, which the README handles by pointing at RELEASE_NOTES.md rather than summarising the break; read that file before upgrading a long-lived app. The second is the plist schema, which is your own code and therefore your own migration problem.

The licence field in the repository metadata reads NOASSERTION, meaning no recognised SPDX identifier was detected. The repository does contain a LICENSE file, and the README links to it. Read that file directly to determine your obligations; the metadata alone will not tell you. This is a factual gap in the packaging, not a statement about the terms.

## Conclusion

Adopt InAppSettingsKit if you already maintain a Settings.bundle and want the same preferences reachable inside a UIKit app without describing them twice. Do not adopt it if your settings screen is SwiftUI-first, if you cannot ship a bundle, or if you expect the framework to hold your values: it reads and writes NSUserDefaults through the plist, and the README does not document a rollback path if a specifier type misbehaves. Before writing code, check the LICENSE file, since the repository does not carry a recognised SPDX identifier, and read RELEASE_NOTES.md if you are coming from 2.x. Then open InAppSettingsKit.xcworkspace and run the Sample App scheme to see which specifier types you actually need.

## FAQ

### Does InAppSettingsKit replace the Settings app entry for my app?

No. The README describes it as presenting the same settings screen within your app so the user has a choice of where to change settings, and it reads the same Settings.bundle you already ship for the system Settings app.

### Which package managers can install InAppSettingsKit?

The README documents Swift Package Manager, CocoaPods and Carthage. For CocoaPods you add pod 'InAppSettingsKit' to your Podfile and run pod install.

### Why does my settings screen come up empty?

The framework builds its table from the Settings.bundle, and the README requires at least a Root.plist to specify the connection between UI elements and NSUserDefaults keys. With no Root.plist there are no specifiers to render.

### Can I use InAppSettingsKit from SwiftUI?

The README shows a UIViewControllerRepresentable wrapper that creates an IASKAppSettingsViewController in makeUIViewController. It is a bridge to a UIKit controller rather than a SwiftUI-native component.

### What has to change when the Settings.bundle lives in a Swift package?

The README notes that the InAppSettings.bundle directory becomes part of the package, and that creating the controller then requires setting its bundle property to Bundle.module, which the README marks as important.

## Sources

- [futuretap/InAppSettingsKit on GitHub](https://github.com/futuretap/InAppSettingsKit)
- [Issues](https://github.com/futuretap/InAppSettingsKit/issues)
- [Project website](https://www.futuretap.com/blog/inappsettingskit-3-0)
- [README](https://github.com/futuretap/InAppSettingsKit/blob/master/README.md)
- [Releases](https://github.com/futuretap/InAppSettingsKit/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/futuretap-inappsettingskit
