Can't share data between app and today extension - ios

I am developing to-do list app. In this app, i add the today extension. It is used to show the to-do list for today.
This is the code for share data between app and today extension. For testing purpose i add the only one item in the NSUserDefaults.
App code for saving the data to NSUserDefaults.
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.compname.appname"];
[shared setValue:#"Test" forKey:#"test"];
[shared synchronize];
Today extension code for fetch the data from NSUserDefaults
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.compname.appname"];
NSString *str = [ shared valueForKey:#"test"] ;
NSLog(#" Text = %#", str);
I am always getting the 'null' value.

Sounds like you haven't added the group to the entitlements/capabilities.
From this site: http://www.shinobicontrols.com/blog/posts/2014/07/21/ios8-day-by-day-day-2-sharing-extension
Go to the capabilities tab of the app's target
Enable App Groups
Create a new app group, entitled something appropriate. It must start with group.. In the demo the group is called group.ShareAlike
Let Xcode go through the process of creating this group for you.

Related

Value stored in shared NSUserDefaults or shared keychain is not updated in time

I try to share some data between my app and it's notification extension. I setup an App Group and use NSUserDefaults to share the data. It works fine at the beginning. But then i found when i update the value from A to B, the extension will not get the updated value, from the extension's perspective the value remains to be A. The value is not updated until I relaunch my app, this is not how i expected the data to be shared.
I tried 'synchronize' on NSUserDefaults.(i know this api is deprecated). Not working.
I tried to use keychain access group and store data with keychain. But it seems like the item in keychain is also not updated in time.
// save value in my app
- (void)onButtonClicked:(UIButton *)sender {
NSUserDefaults *groupUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"myAppGroup"];
[groupUserDefaults setObject:#"A" forKey:#"key"];
}
...
// read value from notification extension
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
NSUserDefaults *groupUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"myAppGroup"];
NSString *value = [groupUserDefaults stringForKey:#"key"];
// modify notification content
self.contentHandler(modifiedContent)
}
I need to share data between my app and notification extension in real time other than synchronized once per launch (as I observed). Really need some advice.

iOS: App Groups missing user default key

I have an App with a today extension. I created already an app group in the developer portal and created the target in my xcode project, linking the group in the capabilities for my app and today target.
So at the app side I'm saving my values like this:
NSUserDefaults *prefs = [[NSUserDefaults alloc] initWithSuiteName:suite];
[prefs setObject:value forKey:key];
[prefs synchronize];
The suite property is the name of my group created in the developer portal. Value is a NSDictionary.
NSDictionary* savedDict = [prefs objectForKey:key];
Calling this gives me the correct values
At the Extension Side I'm using swift and trying to get my UserDefaults like this
let userDefaults = UserDefaults.init(suiteName: "group.cryptochange.favorites")
let savedDict = userDefaults?.dictionary(forKey: "Favorites");
The problem is, that savedDict is nil.
When I print out all keys in my user defaults I see the "Favorites" key at the app side but if I'm printing out the keys in the extension, this key is missing.
Does anybody know where or what the problem could be?
Thanks in advance
EDIT 1:
I just recognize that it works with a debug build but not when I change the scheme to release
EDIT 2:
I just checked the documents directory of my app and see my app groups file which includes the values I saved.
When I look up at the documents dir of the extension there is no such a file. Is this works as intended?
After I set an "test" value inside my extension code the file appears with the test value
You have to make sure:
suite = "group.cryptochange.favorites"
key = "Favorites"
You have to check Extension is a member of group app
You should review that "Cast type" is correct
I hope my answers are useful

Using NSUserDefaults to share data between iOS and watchOS?

I'm having an issue with storing NSUserDefault strings in my iOS application and retrieving them on WatchOS.
I used the following tutorial for creating App Groups & using NSUserDefaults for App groups: http://www.atomicbird.com/blog/sharing-with-app-extensions
In the end, after creating app groups that didn't seem to have any provisioning errors, and then trying to retrieve my stored string, the value remained null. (Even though the value I was storing was definitely not null)
Here's my code for storing (in HomeViewController.m):
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]
initWithSuiteName:#"APP GROUP ID"];
[myDefaults setObject:totalDonatedString forKey:#"donatedForWatch"];
And retrieving (in InterfaceController.m in willActivate):
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]
initWithSuiteName:#"APP GROUP ID"];
NSString *donatedWatchString = [myDefaults objectForKey:#"donatedForWatch"];
NSLog(#"%#", donatedWatchString);
[_totalDonatedLabelWatch setText:donatedWatchString];
I'm pretty new to iOS dev/Obj c so any help please!
To share data your approach is quiet right by using 'App Group'. Create a header file which is included in main app target. Define a macro which identifying your app group. For example declare a Constant.h which included as following
#ifndef CONSTANT_H
#define CONSTANT_H
#define SHARED_APP_GROUP #"name_of_your_app_group"
#endif
import this file wherever you want to access (in watchos app related files and main app files) the app group.
For WatchOS 2 and greater: https://telliott.io/2015/08/11/how-to-communicate-between-ios-and-watchos2.html
The guide has instructions for Swift and Obj-C
Thanks to #dan!

NSUserDefault can't save & load in Extension in iOS8

I need to save data to NSUserDefault in my iOS Custom Keyboard.
I have successfully created App Groups and entitlement in developer portal and XCode.
Here is how i save my value with UISwitch
- (IBAction)switchAction:(id)sender
{
[self.defaults setBool:self.myKey.on forKey:#"myValue"];
[self.defaults synchronize];
}
and here is how i load value in KeyboardView.
self.defaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.mycompany.customkeyboard"];
if([self.defaults boolForKey:#"myValue"])
{
self.backgroundColor = [UIColor redColor];
}
else
{
self.backgroundColor = [UIColor blackColor];
}
It's doesn't work and doesn't load value.
How can i save and load data?
Initialize your NSUserDefaults object like this in all applications in the app group and they will share the database:
[[NSUserDefaults alloc] initWithSuiteName:#"group identifier"];
Keep in mind everything from the [NSUserDefaults standardUserDefaults] database for each application will not carry over into this database.
The documentation indicates that [NSUserDefaults standardUserDefaults] should return the shared database like the above code does, however it does not. I filed this as a bug (rdar://17164758).
And don't forget to synchronize the database:
[yourDefaults synchronize];
Ok, So I had a look around becuase I had the exact problem. What I did that worked was to add the main app and the extension to a group, Go to main project->Target->Capabilities and create a group (if you don't have one, or make one anyway) like this:
Then, go to the Extension below the target (E), again to Capabilities and add the extension to the group (exactly the same app group as you did for the main target), like this:
Then, once you have done both, in your main app, whenever you want to add something, create a new instance of NSUserDefaults, but for the Suitename equal to the groupname you made earlier. Like this:
NSArray *testing = #[#"first",#"Second",#"Third"];
NSUserDefaults *userd = [[NSUserDefaults alloc]initWithSuiteName:#"The gouprname I made earlier"];//This is exactly the same as the groupname
[userd setObject:testing forKey:#"ExtensionArray"];//set the object you want to share
[userd synchronize]; //It's a good idea to sync, just to be on the safe side.
In your extension's ViewController, use the same group name but to read the user defaults:
NSUserDefaults *sharedD=[[NSUserDefaults alloc]initWithSuiteName:#"Exactly the same groupname that I gave both in the Capabilities and when initialising the userdefault"];
self.testing = [[NSArray alloc]initWithArray:[sharedD arrayForKey:#"ExtensionArray"]];
And Voila! the array is there! I read somewhere that you can even add notification functionality for when the object changes, using a Wormhole class, but I can't find the link to it. I'm sure if you google for Wormhole class, you'll come across it.
I hope I could help, and if you found any more info, please share it with me.
You could load the right data from the containing app, so maybe set a new value in extension app will help.
[self.defaults setObject:newValue forKey:#"thisKeyIsJustUsedForSyn"]
And then load the right data.

is that possible to know my apps is first time run or not in xcode?

i create an apps that i want to prompt an message for the user.. maybe using UIAlertview. After that, if the user run the apps for the second time, the alert won't prompt up anymore.
is that possible? honestly i don't have any idea about how to doing this.
Any idea? I search on STO, actually this link, still confused.
what is NSUserDefaults? How can NSUserDefaults store this information? i mean this is my first time or second time.
thanks.
To know what's NSUserDefaults, I suggest to take a look the official doc.
And of course you can use it to fulfill your goal.
You use a user default to store information about the current amount of runs in the app.
More or less like:
BOOL isRunMoreThanOnce = [[NSUserDefaults standardUserDefaults] boolForKey:#"isRunMoreThanOnce"];
if(!isRunMoreThanOnce){
// Show the alert view
// Then set the first run flag
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"isRunMoreThanOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Yes, U can save a value in NSUserDefault for the first time in your app & set it some other value once you open the app.
like
if(![[NSUserDefault standardUserDefault] objectforKey:#"AppOpenFirstTime"])
{
// App Open First time
// Show Alert
[[NSUserDefault standardUserDefault] setObject:#"1" forKey:#"AppOpenFirstTime"]
}
You can check if you stored some value in NSUserDefaults
NSString *flag = [[NSUserDefaults standardUserDefaults] stringForKey:#"not_first_run"];
if (!flag) {
//first run, do somethig
}
and then set it to some value
[[NSUserDefaults standardUserDefaults] setObject:#"just any string" forKey:#"not_first_run"];
NSUserDefaults is a key-value store saved between your application launches.
You can do it exactly as cortez said in your link. NSUserDefaults is written to disc, and will be created and accessed from your app.
See this link
First Time when your application launch at that time boolForKey:#"AlreadyRan" is FALSE. after that set it TRUE.
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"AlreadyRan"] )
{
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"AlreadyRan"];
}
With the NSUserDefaults class, you can save settings and properties
related to application or user data.
The objects will be saved in what is known as the iOS “defaults system”.
The iOS defaults system is available throughout all of the code in your app, and any data saved to the defaults system will persist through application sessions.This means that even if the user closes your application or reboots their phone, the saved data will still be available the next time they open the app!

Resources