iOS Today Extension NSUserDefaults Sharing Data with Containing App using Callbacks - ios

I've got the following problem:
I created a Today Extension, which contains an UISwitch. The IBAction of this switch in Today Extension should store the on-state using the NSUserDefaults with the initWithSuite like this:
- (IBAction)switchStateChanged:(id)sender {
BOOL isOn = self.preferenceSwitch.isOn;
NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.x.TodayExtensionSharingDefaults"];
[sharedDefaults setBool: isOn forKey: #"SwitchState"];
[sharedDefaults synchronize];
}
Now in my Containing App, I know that i can access the switch state using this:
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.x.TodayExtensionSharingDefaults"];
BOOL value = [defaults boolForKey:#"SwitchState"];
I'm looking for a solution that gives me a callback in my main containing app, when the value of the switch is changed.
In this solution, i have to set a NSTimer that refresh the user-defaults every 200ms for example.
Is there any solution by adding an Observer to the sharedDefaults?

I think this will work for your use case:
When you leave your app and open up Notification Center,
- (void)applicationWillResignActive:(UIApplication *)application
is called in your AppDelegate. When you come back from the widget,
- (void)applicationDidBecomeActive:(UIApplication *)application
is called in your AppDelegate. So just check your value then and fire off a internal notification to your controller. You shouldn't have any need for a timer.

Observing the change in your app is not a good solution, even if you could make it work, because you can't be certain that your app is even running when the switch value changes. It's also not how today extensions are intended to work.
If your app needs to know the state of this switch the next time it runs (recognizing that it might not be running when the switch is tapped), you're already doing the right thing.
If you need to immediately notify your app that the switch value has changed (again, recognizing that your app might not be running and that doing this might launch your app), you should create a custom URL scheme for your app and then open the URL from the extension. This would be something like:
In the app, declare a custom URL scheme in the "URL types" section of the app's "Info" settings.
Also in the app, add code to the app delegate to receive requests to open URLs.
In the app extension, use [NSExtensionContext openURL:completionHandler:] to open the URL. This will launch your app and pass the provided URL.
If the URL scheme is something like mygreatapp, the app extension would open a URL like mygreatapp:. You can add detail to the URL if needed, or the app can just use user defaults to look up the saved value.

Related

iOS SDK Detect if app was updated or a new install

After looking at a bunch of SO posts about detecting if this is a fresh install or not, I'm assuming what I want to do is impossible, but I'm going to ask just in case there's a trick I'm unsure of.
I am building an SDK to be integrated into apps, and I want to be able to tell when the SDK gets initialized for the very first time if it's from a brand new install, or from an app update which included our SDK.
I could have the integrator to call something like [MySDK initializeIsNewInstall:YES/NO] and force them to figure out which it is (using NSDefaults or whatever), but I'd rather be able to figure it out automatically somehow.
If anyone has any ideas, that would be great.
I would like to suggest pretty good trick by using [NSUserDefaults standardUserDefaults]
do it like this,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if([[NSUserDefaults standardUserDefaults] boolForKey:#"isApplicationUpdated"]){
// application was updated//
// make another userDefaults to store version number and confirm if it is updated here.
}
else{
[[NSUserDefaults standardUserDefaults] setBookForKey:#"isApplicationUpdated"]
// as for the first time application would not find this key and you can use it after you have updated the app do stuff here
}
Afaik the only way to detect whether your app was updated or freshly installed in your case is to check your persistence for something that should be there from a previous version. For future checks you can add your own flag to your persistence.

get notification when new iOS application installed iphone

I wondered if there are a way to be notified when a new application is installed in my device and trigger some treatment in my applications. Like PACKAGE_ADDED BroadcastReceiver in android
Thank's
Apple does not provide such information. Instead, you could add something like:
if([[NSUserDefaults standardUserDefaults] objectForKey:#"firstRun"] == nil)
{
//This is a first run
[[NSUserDefaults standardUserDefaults] setObject:#"NotFirstRun" forKey:#"firstRun"];
}
to applicationDidFinishLaunchingWithOptions:
update
If you instead want to detect the installation of another app the approach is different:
You can't detect when an app is installed, but for SOME apps you can detect if they are installed.
Doing your own app launch (or perhaps using a backgroundfetch process) you can see if an app is installed IF the app responds to a URL Scheme AND you know that scheme.
Take a look at
([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:customURL]])
If this methode returns YES for a given URL Scheme you know that app is installed. Here is a partial list of URL Schemes for some common apps or search http://handleopenurl.com/. You can of course also make your own URL Scheme if you want to detect your own app.
No. Apple doesn't give you this data.
What you can do, however, is maintain an user defaults data and manipulate in applicationDidFinishLaunchingWithOptions: delegate.
I've used a library called 'GBVersionTracking' for detect when is his first launch.
Importing this library you can send messages to the class 'GBVersionTracking' like:
[GBVersionTracking isFirstLaunchEver];
[GBVersionTracking isFirstLaunchForVersion];
[GBVersionTracking isFirstLaunchForBuild];
https://github.com/lmirosevic/GBVersionTracking

Settings.bundle: how should application recognize the fact that a value got changed outside of app? [duplicate]

This question already has answers here:
How to determine when Settings change on iOS
(7 answers)
How to receive NSUserDefaultsDidChangeNotification iphone
(1 answer)
Closed 9 years ago.
I am using Settings bundle to configure my app. As a side effect, the same set of settings is available outside the app in iOS Settings. This is great. However there is a little problem - I do need to react to the changes. For example, I have a name that a user is using to be recognized by others and if it changes, a server call must happen. How to handle that?
EDIT: take it easy, fellas. I've never done that before and it's hard to read thru all guidelines available. Settings.bundle is not an obvious thing to deal with. Anyways, feel free to vote the question down but at least take a minute and read thru all commends before you do so.
Tried a couple suggested ways, i.e. using notifications and in more direct manipulation of defaults when app becomes active. The second approach worked better because it only executed at times I expect instead of every time any config setting is changed/added/deleted within the app.
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSString *nameOld = [[NSUserDefaults standardUserDefaults] stringForKey:kNameKey];
[[NSUserDefaults standardUserDefaults] synchronize];
NSString *nameNew = [[NSUserDefaults standardUserDefaults] stringForKey:kNameKey];
You should check for changes to settings in this appDelegate method.
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Check for any changes to settings
[[NSUserDefaults standardUserDefaults] synchronize];
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
bool userICloudChoice = [userDefaults boolForKey:_cloudPreferenceKey];
}

issue with NSUserDefaults (becomes null)

We are developing an iPhone application. The app is available in the app store. We are using NSUserDefaults to store our usertoken value. But some users reports that the usertoken is became null when the app idle (in background) for long time. But normally the value is getting.
The following is the code for storing usertoken in the NSUserDefaults. We are setting the value to the userToken from the login page and signup pages.
[[NSUserDefaults standardUserDefaults] setObject:userToken forKey:USER_TOEKN];
I have not called synchronize after setting value to NSUserDefaults. Could you please help
You need to call [[NSUserDefaults standardUserDefaults] synchronize]; if your app is going to be backgrounded - my guess is the app idles before the defaults automatically synchronizes. From the documentation:
Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.
As for where to do this, take a look at applicationWillResignActive: and applicationDidEnterBackground: in your Application Delegate.
Try something like this:
NSUserDefaults *udf = [NSUserDefaults standardUserDefaults];
[udf setObject:userToken forKey:USER_TOEKN];
[udf synchronize];
It will store your value permanently.

Temporary Disclaimer

I'm making an app as a part of my project and I've been asked to add a disclaimer.
At first I made a separate view with a textview that holds the disclaimer, when the user presses the Disclaimer button they will see this.
But I've been asked to change this so that the disclaimer is shown if the app is being used for the first time. If the user accepts it, they won't see it again and if they don't they'll see it every time they open the app.
I don't know how to go about this. I tried changing it so that the first thing the app shows when launched is the disclaimer, but that got annoying because every time I launch the app it goes to the disclaimer.
Anyone have any suggestions or examples ?
You can use NSUserDefaults to achieve this. Once the user has accepted the disclaimer, write a BOOL called disclaimerAccepted (or similar) to your defaults. Use the following code in the AppDelegate method application:didFinishLaunchingWithOptions: to check this:
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"disclaimerAccepted"]) {
// Show the disclaimer.
}
And use this code when the user accepts the disclaimer:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:YES forKey:#"disclaimerAccepted"];
[defaults synchronize];
Hope this is helpful.
Why not use NSUserDefaults to store info whether user dismissed or accepted the disclaimer & show the dialog accordingly. NSUserDefaults are persisted even if app is closed.
edit:
Here is an example Using User Defaults
The best solution I found is given here: iPhone: How do I detect when an app is launched for the first time?
If you like it add your upvote there - I only just used it a couple of days ago and I think it is really good!

Resources