Communicating and persisting data between apps with App Groups
Solution 1
Another benefit to App Groups is the ability to share a NSUserDefaults
database. This also works for App Extensions (notification center widgets, custom keyboards, etc).
Initialize your NSUserDefaults
object like this in all applications in the app group and they will share the database:
Objective-C:
[[NSUserDefaults alloc] initWithSuiteName:@"<group identifier>"];
Swift:
NSUserDefaults(suiteName: "<group identifier>")
Keep in mind everything from the [NSUserDefaults standardUserDefaults]
database for each application will not carry over into this database.
The documentation gives a correct example as well (As of Beta 3).
And don't forget to synchronize the database:
[yourDefaults synchronize];
Solution 2
Sharing NSUserDefaults data between multiple apps
In order to have shared defaults between an app and an extension or between 2 apps you have to add an App Group in your settings using the following steps:
- In the Project Navigator click on the *.xcodeproj file (should be at the top).
- To the right of the Project Navigator look for Project and Targets. Under targets click on your primary target (should be the first thing under Targets).
- Towards the top, click on the Capabilities tab.
- In the App Groups section click the switch to the right to turn App Groups ON.
- Click on the + button and add an App Group named group.com.company.myApp.
- Go to the same place in your other apps and this group should now be available to select. Turn this group on for each app that will be using this shared data.
Note: If you go to the Apple Developer Portal (the Apple website that shows all of your Certificates, Identifiers, Devices and Provisioning Profiles) and go to Identifiers > App Groups you should see this new App Group.
To store data:
var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")!
userDefaults.setObject("user12345", forKey: "userId")
userDefaults.synchronize()
To retrieve data:
var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
if let testUserId = userDefaults?.objectForKey("userId") as? String {
print("User Id: \(testUserId)")
}
Solution 3
Application groups, according to my interpretation of the existing documentation, are primarily targeted for extensions, more specifically, for widgets. Widgets are their own application bundle that coexist with your app. Since they are a separate application and therefore have their own sandbox, you will need to use App Groups to share files.
After some header grep'ing, I think I found the API needed, but was actually put in as part of iOS 7.
NSFileManager
has a method on it containerURLForSecurityApplicationGroupIdentifier:
where you can pass in the identifier you created when turning on App Groups for your apps:
NSURL *containerURL = [[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:@"group.com.company.app"];
Solution 4
One important trap I tapped into today is the following:
In many projects I saw a single app target and with different bundle identifiers set for each configuration of that target. Here things get messy. What the developers intended was to create a debug app for the debug config and a production app for the release target.
If you do so both apps will share the same NSUserDefaults when they are set up like so
var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
userDefaults!.setObject("user12345", forKey: "userId")
userDefaults!.synchronize()
This causes problems in many places:
- Imagine you set YES for a key when a special app-intro-screen has been shown to the user. The other app will now also read YES and don't show the intro.
- Yes some apps also store oAuth tokens in their user defaults. Anyways... Depending on the implementation, the app will recognize that there's a token and start retrieving data using the wrong token. The chance is high that this will fail with strange errors.
The solution to this problem in general is to prefix the defaults keys with the current configuration built. You can detect the configuration easily at runtime by setting different bundle identifiers for your configurations. Then just read the bundle identifier from NSBundle.mainBundle()
. If you have the same bundle identifiers you need to set different preprocessor macros like
#ifdef DEBUG
NSString* configuration = @"debug";
#elif RELEASE
NSString* configuration = @"release";
#endif
In Swift it will look almost the same:
#if DEBUG
let configuration = "debug"
#elseif RELEASE
let configuration = "release"
#endif
Solution 5
App Group
allows you to share data(UserDefaults, Files, CoreData(manage model graph), POSIX locks) between different processes(applications, extensions...) from the same development team(account). It creates a shared container
whit id
which shoyld start from group.
for saving/caching data which you are allowed to access thought url and IPC
To use App Group
with UserDefaults
- Add
App Group
capability with the same id for ALL targets(app, extension...) which you will get an access from
After creation you are able to check it on Apple Developer. Certificates, IDs & Profiles -> Identifiers -> ALL Groups
- Write from Application1
let defaults = UserDefaults(suiteName: "group.goforit")
defaults?.setValue("Hello World!", forKey: "key1")
- Read from Application2
let defaults = UserDefaults(suiteName: "group.goforit")
let result = defaults?.value(forKey: "key1") //Hello World!
shared container
root location single URL.
let rootURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.goforit")
//file:///Users/alex/Library/Developer/CoreSimulator/Devices/1AF41817-FE2E-485A-A592-12C39C0B0141/data/Containers/Shared/AppGroup/DC14D43F-2C2C-4771-83BE-64A9F54BD2E1/
streem
Hey, My name is Emilien Stremsdoerfer, I'm currently a Software Engineer and lead iOS at HER, the social network for LGBTQ+ women. Feel free to check my profile on Linkedin for more information https://www.linkedin.com/in/estremsdoerfer
Updated on July 08, 2022Comments
-
streem almost 2 years
iOS 8 revealed a new API yesterday concerning App Groups. It was kind of messy before to share data and communicate between apps and I believe that's precisely what App Groups is intended to correct.
In my app I have enabled App Groups and added a new group but I just can't find any documentation on how to use it. Documentation and API references only state how to add a group.
So what is App Groups really intended to do? Is there any documentation somewhere on how to use it?
-
streem about 10 yearsThanks, I believe you're right about extensibility. I'm a little bit more dubious about this iOS 7 method, it seems pretty static to me, iOS 8 introduced real interactions and communication between apps.
-
Wayne Hartman about 10 years@Justafinger This iOS 7 method is only for creating a URL to write to and read from data between the shared applications. This particular method is only really useful (from what I see so far) for widgets, but not other extensions.
-
streem about 10 yearsWell, i believe Apple wanted to make this easier in iOS 8 without having to create a container programmatically and share custom files. Documentation states that you should be able to share data by using NSUserDefault. I guess i'm missing something, because that's not working for me.
-
Wayne Hartman about 10 years@Justafinger I have not been able to get
NSUserDefaults
to work, either. I chalk to up to Beta 1 bug. -
Andrew about 10 years@WayneHartman There is a workaround for the
NSUserDefaults
database. See my answer. -
iOS Dev almost 10 yearsWorks only on simulator (XCode 6 beta 5, iOS 8 beta 5)
-
Kiran Panesar almost 10 yearsNOTE: If you're using this with an iOS 8 Extension (e.g. keyboard), you'll need to ensure your extension has RequestsOpenAccess=YES in its Info.plist file.
-
MAC over 9 yearsI did RequestsOpenAccess=YES and follow instruction still it wan't works for me on Device and works fine on Emulator, anything specific for device ?
-
Ravi Ojha about 9 yearsSame issue with me, i have integrated share extension in my app, it work on simulator, but not working on real device ,,i have added the RequestOpenAccess =YES but its not work, my question is stackoverflow.com/questions/30489894/…
-
Andrew about 9 years@Tejinder You have not provided any information as to how I might diagnose your problem. What version of iOS are you using? More than likely you are running into a provisioning problem and you should check your provisioning profiles to make sure they are correctly configured for app groups.
-
Mike Richards over 8 yearsDo you know if it possible to use the same app group between two different organizations? Would we be able to utilize an app group in a library that we distribute to other organizations?
-
Andrew over 8 years@MikeRichards not sure, but if I remember correctly the app groups are prefixed with a team id
-
TenaciousJay over 8 yearsThanks! It took a bit of searching through documentation to figure out how to do this and I thought others might appreciate the steps I took.
-
Daniel over 8 yearsYour problems exist because you mix all your data in a shared UserDefaults. You should use
NSUserDefaults.standardUserDefaults()
for data that should not be shared. -
Arbaz Shaikh over 8 yearsThanks for the detailed description...! do we need to created any certificate from Apple Developer Portal (the Apple website that shows all of your Certificates, Identifiers, Devices and Provisioning Profiles) to enable this group? same like Push notification.?
-
TenaciousJay over 8 yearsWhen you do step 5 it should add the App Group to the Apple Developer Portal, you should not have to go directly to the Developer Portal to add it. After you do step 5 you can go to the portal and see that it should have created it for you.
-
Bernard about 8 years@SantaClaus Yes you must have same team development id as explain here: developer.apple.com/library/ios/documentation/Miscellaneous/…
-
Taimur Ajmal over 7 years@TenaciousJay Superb answer. Just want to add If you want to launch the app from the func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool
-
Sunil Targe over 7 years@SantaClaus Can we allow app groups container for iTunes File Sharing
Application supports iTunes file sharing
? -
LizG over 7 yearsgreat answer. thanks @TenaciousJay. I am trying to retrieve a variable and its value from AppB into AppA, how would I do this? For instance if "riderCancelledRequest = true" in AppB, how would I retrieve this in AppA?
-
TenaciousJay over 7 yearsIn Swift 3.0, since you're not storing an object you'd probably use "set" instead of "setObject". So in AppB it would include the line: userDefaults!.set(true, forKey: "riderCancelledRequest"). And in AppA include the line: userDefaults?.bool(forKey: "riderCancelledRequest").
-
Krunal Nagvadia almost 5 yearsIs there any other process to follow for uploads the apps? I'm Parsing the data between Native iOS and Unity App.
-
eharo2 about 4 yearsBy far the best solution around. This should be the accepted answer
-
Raja Saad almost 3 yearsShort, but very very useful explanation of how to use App Groups along with User Defaults @yoAlex5