skip to Main Content

Background

I’m developing a macOS applications that consists of a plugin and main application. I would like for both targets to be able to share the same settings. I want to manipulate my settings using the Defaults class.

Implementation

Defaults

First I extend the UserDefaults in the following manner:

extension UserDefaults {
    static let group = UserDefaults(suiteName: "the same as app group????")
}

I subsequently create my Defaults class:

import SwiftUI

class Defaults: ObservableObject {
    // Initial set of user settings
    @AppStorage("some_value", store: .group) var someValue: Bool = false
}

I would then conveniently reference values and bidings in that class using

@StateObject var defaults = Defaults()

App Groups

I would then add App Group capability for each of my targets:
app Grpup

Background

Puneet, in this useful answer defines suiteName as:

suiteName:is kind of an identifier which helps you create preferences(UserDefaults) store. By using a particular suiteName, you are creating a preferences store, that is not bounded to a particular application (whereas standard UserDefaults are different for every application).

The documentation on implementing App Groups suggest using $(TeamIdentifierPrefix)com.example.mygroup.

Questions

  1. What’s the relationship between suiteName and string provided within the App Group field?

  2. Give the product outline (macOS app + plugin), what’s the correct implementation:

    a) I should use the same string as App Group value and suiteName.

    b) I should programmatically derive value of $(TeamIdentifierPrefix) and use that as value for suiteName

    c) Value of suiteName should be different from string typed across App Group values.

2

Answers


  1. Shared Settings for macOS App and Plugin Using App Groups

    Background

    You’re developing a macOS application that consists of a main application and a plugin. You want both targets to share the same settings, manipulated using a Defaults class, which extends UserDefaults.

    Implementation

    Defaults

    You’ve extended UserDefaults as follows:

    extension UserDefaults {
        static let group = UserDefaults(suiteName: "the same as app group????")
    }
    

    And created a Defaults class:

    import SwiftUI
    
    class Defaults: ObservableObject {
        // Initial set of user settings
        @AppStorage("some_value", store: .group) var someValue: Bool = false
    }
    

    You then reference values and bindings using:

    @StateObject var defaults = Defaults()
    

    App Groups

    You’ve added App Group capability to each of your targets, as shown in the image.

    Questions and Answers

    1. What’s the relationship between suiteName and string provided within the App Group field?

      The suiteName in UserDefaults(suiteName:) should match the App Group identifier you’ve set up in your target capabilities. This allows different parts of your app (or different apps in the same group) to access the same set of preferences.

    2. Given the product outline (macOS app + plugin), what’s the correct implementation?

      The correct implementation is:

      a) You should use the same string as the App Group value and suiteName.

      Here’s why:

      • The App Group identifier you set in your target capabilities (e.g., group.com.yourcompany.yourappgroup) defines a shared container that both your main app and plugin can access.
      • By using this same identifier as the suiteName when initializing UserDefaults, you’re telling your app to use the shared container for storing and retrieving preferences.

      Correct implementation would look like this:

      extension UserDefaults {
          static let group = UserDefaults(suiteName: "group.com.yourcompany.yourappgroup")
      }
      

      Where "group.com.yourcompany.yourappgroup" is the exact string you’ve entered in the App Groups capability for both your main app and plugin targets.

    Additional Notes

    1. The $(TeamIdentifierPrefix) is typically used in the App Group identifier when you’re setting it up in Xcode. However, when you’re actually using it in code, you should use the full, expanded string.

    2. You can find your full App Group identifier in your Apple Developer account or in Xcode after you’ve set up the App Groups capability.

    3. Make sure both your main app and plugin have the App Groups entitlement and are part of the same group.

    4. When distributing your app, ensure that the App Group capability is properly set up in your provisioning profiles and that both the main app and plugin are signed with the correct team and provisioning profile.

    5. Remember to handle cases where the shared UserDefaults might not be available (e.g., if the App Group isn’t properly set up). You might want to fall back to standard UserDefaults in such cases.

    References

    Login or Signup to reply.
  2. In order for the UserDefaults to use the AppGroup the suite name has to be the app group identifier. The “standard” suite name is the bundle identifier the group’s suite name is the group identifier.

    TeamIdentifierPrefix is too board IMO, I think it should be appropriate per scope. If it is used by 1 app with multiple extensions use the app’s name. If it’s used by multiple apps in the same category use something like BusinessNameSocialMedia. It is just an identifier you can name it whatever you want. I think TeamIdentifierPrefix should be used for something where all of the team’s apps need access.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search