Using NSUserDefaults to share data between iOS and watchOS? - ios

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!

Related

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

Can't share data between app and today extension

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.

NSUserDefault with App Group is not working in iOS 8 Beta3

I have to save Boolean Value to NSUserDefault in my App with custom keyboard extension and share with App Group.
My Code is worked in iOS 8 Beta1.
self.defaults = [NSUserDefaults standardUserDefaults];
if([self.defaults boolForKey:#"BlackKey"])
{
NSLog(#"Black");
}
else
{
NSLog(#"White");
}
But Not in iOS 8 Beta3. When i retrieve Boolean value from NSUserDefault , it's return nothing and i can't load from custom keyboard extension.
I have also tried with initWithSuiteName in NSUserDefault. Am i only one for that problem or bugs of iOS 8 Beta3?
A few probable solutions are:
Your app group is not setup correctly, or you are not using the correct group identifier with initWithSuiteName:
You have not enabled network access for your keyboard. This document states the following when you have network access disabled for your keyboard (default behavior):
No shared container with containing app
It's a bug.
Try using
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"BlackKey"];
when you save and read it by using this code:
if([[NSUserDefaults standardUserDefaults] boolForKey:#"BlackKey"]) {
NSLog(#"Black");
}
else
{
NSLog(#"White");
}
or if you already done so, then it can be bug, and Xcode 6 beta versions also have other bugs so it's safer to try in Xcode 5 or older.

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.

Rate this app funtionlity

i am trying to provide the rate this app functionality into my application hence i added the below code
- (void)gotoReviews
//------------------
{
NSString *str = #"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa";
str = [NSString stringWithFormat:#"%#/wa/viewContentsUserReviews?", str];
str = [NSString stringWithFormat:#"%#type=Purple+Software&id=", str];
str = [NSString stringWithFormat:#"%#APPid", str];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
}
str = [NSString stringWithFormat:#"%#APPid", str]; here i have to mention my app id.i see the appid into the provisioning portal as following 546F5QMTE4.com.XXXX.XXXX into the APp id section.
Is that the "546F5QMTE4" string need to placed? am i right is that correct id?
please let me know
You can do this in many ways:
Direct approach:
#define APP_ID XXXXX //id from iTunesConnect
NSString *reviewURL = [NSString stringWithFormat:#"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%d",APP_ID];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]];
Try with Appirator in app delegate:
[Appirater setAppId:#"552035781"];
[Appirater setDaysUntilPrompt:1];
[Appirater setUsesUntilPrompt:10];
[Appirater setSignificantEventsUntilPrompt:-1];
[Appirater setTimeBeforeReminding:2];
[Appirater setDebug:YES];
You can get source: Here.
Add Appirater.h and Appirater.m to your project.
For more information about integration: Here
:)
No, it is not that number. You have to go to the iTunesConnect -> Manage Your Apps, choose your app, then look under "App Information" for Apple ID (digits only).
Of course be sure that you have actually a record for your app. If not, just make it (Add New App button).
iRate is best https://github.com/nicklockwood/iRate
The one that I use and works wonders on iOS 5+ (also available for Mac OS X, but this answer is focused on the iOS portion) and up on all devices (iPad, iPhone, iPod Touch) is iRate.
It uses a uialertview and storekit to ask the user for a rating (or to remind them later). Everything is customizable, from the name of the Cancel Button Title to the Interval at which it reminds the user.
By default, iRate automatically opens when certain requirements are met (ex. app launched X number of times, user passed X number of levels), but you can also use a variety of methods and your own logic (with the help of iRate methods) to manually display an iRate popup.
Setup
To install,
just drag the header (.H) file the implementation (.M) file, and the iRate Bundle (for localization) into your project.
Import the header in your AppDelegate: #import "iRate.h"
Add the StoreKit Framework to your project - More on StoreKit from Apple Documentation
Add the following method to your app delegate: + (void)initialize
The properties can be set in the initialize method, however none of them are required (iRate can automatically find all of this information).
No, it isn't. It's rather a numeric ID with a few digits, something like this:
http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=389801252&pageNumber=0&sortOrdering=1&type=Purple+Software
This will only be live when your application has been approved by Apple and it's already on the AppStore (in case of an intentionally delayed launch).
Furthermore, the way you're composing that poor URL string is simply horrible. Don't abuse format strings! You have a constant string here, so you don't even need any call to + [NSString stringWithFormat:]. Even if you wanted to alter the app ID, you could do that using one single formatting statement:
NSString *str = [NSString stringWithFormat:#"http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=%#&pageNumber=0&sortOrdering=1&type=Purple+Software", appID];

Resources