Reading NSUserDefaults from helper app in the sandbox - objective-c

I found some resources on reading the NSUserDefaults of another application.
Objective-C NSUserDefaults caching prevents another app from accurately reading changes
NSUserDefaults: Is it possible to get userDefaults from another app?
Apparently, it's not possible.
However the questions firstly relate to iOS, and secondly the two apps are completely different.
I have a LaunchAtLogin helper app. But it does some other tasks too.
Therefore, the helper app should run always, but only start the main app if the BOOL in the NSUserDefaults is set.
Is there a way I can achieve that?

Since 10.7.4 you can use Application Groups within the sandbox. All applications within the group share the same sandbox. See Application Groups on how to set these up.

It's possible to share preferences between a main app and helper app using Security Application Groups and -[NSUserDefaults initWithSuiteName:]:
Security Application Groups
In order for multiple apps to share a common container, you'll want to set the com.apple.security.application-groups entitlement (in your main and helper app) to a common identifier, such as #"com.company.my-app-suite". See Adding an App to a Group for more information.
User Defaults Suites
As per the Foundation Release Notes for OS X 10.9:
For applications that are part of a Security Application Group, the NSUserDefaults "suite" APIs (-initWithSuiteName:, -addSuiteNamed: and -removeSuiteNamed:) will operate on a suite shared by applications in the group and stored in the group container, if the suite identifier is the identifier of the group.
So you'll want to do something like this in your application delegate (or similar):
- (NSUserDefaults *)sharedUserDefaults {
static NSUserDefaults *shared = nil;
if (!shared) {
shared = [[NSUserDefaults alloc] initWithSuiteName:#"com.company.my-app-suite"];
}
return shared;
}
And use that instead of [NSUserDefaults standardUserDefaults] throughout both your apps.

Apps can share a container directory on iCloud.
From Apple's doc on configuring your iCloud entitlements:
The iCloud Containers field identifies the list of container directories that your app can access in the user’s iCloud storage. (This field corresponds to the com.apple.developer.ubiquity-container-identifiers entitlement.) The strings you add to this list must correspond to bundle identifiers for apps created by your team. Xcode uses the current app’s bundle identifier to specify the first string; you can change this to a different bundle identifier if you want multiple apps to share a main container directory. You can also add additional bundle identifiers for your team’s other apps.

Related

Disable popup when work with Shared Web Credentials (work directly)

Is there any way to work with data in shared web credentials directly, like with keychain, without showing popups on SecAddSharedWebCredential and SecRequestSharedWebCredential?
Or are there any other methods to work with it?
I want to share some data (string) between apps with different development teams.
I will recommend you to use the KeychainAccess which is a simple swift wrapper. And using Keychain is the best way to store small pieces of data that are critical to your app, like secrets and passwords.
Also the tutorial from raywenderlich would help you use the Keychain Services API.
App groups can be an option for your use case. Read below the apple API documentation and medium post
App Groups
Use a shared app group to share data/files between two/more apps or containing apps. An app group creates a secure container that multiple processes can access. Normally, each process runs in its own sandbox environment, but an app group lets both processes share a common directory.
Apple API docs - https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups
https://medium.com/#dinesh.kachhot/different-ways-to-share-data-between-apps-de75a0a46d4a
Also here is another stackoverflow post answering similar question - Communicating and persisting data between apps with App Groups

Sharing files Between Apps on iOS Devices

Is it possible on iOS to access another app's file data? On Android, that seems possible according to following URL.
Sharing files/ installation directory between two apps
No, that is not possible.
All iOS apps are sandboxed (at least on non-jailbroken devices), and while keychain data can be shared (between Apps that share their Bundle Seed ID), doing the same for file-based data is currently not possible.
What you CAN do is pass data to other apps by exchanging them via a server or call a URL scheme that another app has registered. Apple says:
Using a URL-based syntax, you can access data from the Web, as well as
pass information to other installed applications, such as Mail,
iTunes, and YouTube. Your own application can declare a unique URL
scheme, allowing any application to collaborate and share data with
your app.
It depends on what kind of data. In fact, iOS apps may only share keychain data. From Apple's doc :
An app ID has two parts: the team ID followed by the bundle ID search
string. The team ID is a 10-character string generated by Apple. Each
development team is assigned a unique team ID used to identify all
your apps. The team ID allows you to share keychain data between apps.
Apps with the same team ID can share data, such as usernames and
passwords. A bundle ID search string is traditionally a
reverse-domain-name style string. It’s the string you use in Xcode as
the bundle ID.
I've never done this, but there must be many tutorials on how to do this.
It is not possible to access other app's data installed on any Apple device. It is restricted by apple.
Anyways you can try it on JailBreaked devices. These operations are handled by Apple Private API's. Which you cant access in regular devices.
If you get access to them/used in your application, apple will reject your application.

iOS SDK: Working with NSUserDefaults

With the NSUserDefaults class, you can save settings and properties related to application or user data.
now i have tow question :
( settings and properties ) Where are stored ?
if =>The objects will be saved in what is known as the iOS “defaults system"
then : What is iOS “defaults system"
How long will remain stored ?
Where? It depends on what kind of app you're developing. For AppStore applications, in the sandbox folder of your installed app folder, more precisely in the Library/Preferences folder. The actual file that contains the settings is a PLIST (property list) file whose name matches the bundle identifier of your app.
All in all:
(/var/mobile/Applications/XXXX-XXXX-XXXXXX-XXXXXXXX/MyApp.app/Library/Preferences/com.mycompany.bundleid.plist
(where XXXX etc. is an UUID).
If you're making an app for jailbroken devices (i. e. a Cydia app), it will be a plist file again, whose name matches the bundle ID, but it will be installed in
/var/mobile/Library/Preferences/com.mycompany.bundleid.plist
The iOS defaults system is the part of the Foundation framework, iOS itself and the files and directories altogether which manage, store and modify your preferences/settings/defaults.
How long? Again, it depends on what kind of app you are writing. For a normal AppStore app, the defaults are persited to the file - but only as long as the user doesn't delete your app. When your app is deleted, the whole sandbox, app bundle and od course the user defaults will also be gone. Forever, irreversibly.
If you develop a jailbroken application which resides in the system apps' directory (/Applications), then the user defaults file will be available in /var/mobile/Library/Preferences even if the user deletes your package/application, as APT (the backing package manager of Cydia) only makes note of the files your package originally contained, and that's not the case with the defaults property list file (which is only created when your app first accesses the NSUserDefaults class.) If the user manually deletes the file or restores to a stock firmware, it'll be gone.
Answers:
In the application's sandbox. Where exactly is unimportant as you aren't going to be accessing the defaults directly anyway.
As long as your app is on the device. If you delete the app, the sandbox is deleted as well, so that's when they get deleted. If you update your app, the same sandbox is used, so they don't get deleted.
As for what it is, I'm just going to quote you a bit of the documentation:
The NSUserDefaults class provides a programmatic interface for interacting with the defaults system. The defaults system allows an application to customize its behavior to match a user’s preferences. For example, you can allow users to determine what units of measurement your application displays or how often documents are automatically saved. Applications record such preferences by assigning values to a set of parameters in a user’s defaults database. The parameters are referred to as defaults since they’re commonly used to determine an application’s default state at startup or the way it acts by default.
At runtime, you use an NSUserDefaults object to read the defaults that your application uses from a user’s defaults database. NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. The synchronize method, which is automatically invoked at periodic intervals, keeps the in-memory cache in sync with a user’s defaults database.

Can I programmatically wipe the application data in applicationDidFinishLaunching:withOptions:?

For testing purposes, I'd like to be able to just reset the application to a clean state. (Similar to what deleting the app from the Simulator / iPhone does).
Assume we have a WIPE_DATA define, if that is set, the app should start as if it has been just installed. Obviously if you know the app, you know where it stores data in NSUserDefaults etc. I was wondering if there was a more generic approach that requires no insight into the specific app and thus would be applicable to any app.
In your app you have two kinds of data - NSUserDefaults settings and files in Documents directory. If you want to wipe all the data to make your application to initial state and settings, you should create e.g. an app delegate method which set initial NSUserDefaults settings and clean application generated files in Documents directory.
As far as I know there is no standart system way to do that.

iCloud Support in an application for Mac OS X Lion

Within a Mac OS X (10.7 Lion) Non-Document Based application, I want to include iCloud support so I can share data across other instances of the same application on other macs (not to iOS devices). After surfing around the Apple documentation a bit, I've discovered I should use a key value list storage in iCloud, as the document I want to upload contains only an array of custom objects (that have simple properties such as a name (string), date (date object), ...). This file is the only thing I want to upload to iCloud. Within the application, I have already implemented saving the file to the disk using NSFileManager's - (void)writeData:(NSData*)data toPath:(NSString *)path (or whatever it was, I've forgotten). It is loaded from the file using NSFileManager again (using - (NSData *)dataInFileAtPath:(NSString*)path, or whatever it was). The file is stored in a subdirectory, in the user's Application Support directory. It is saved whenever a new item is added to the array, or an item in the array is modified.
I was wondering if anyone could provide a link to a tutorial, or point me in the right direction, to writing that file to iCloud, then downloading it again on other instances of the same application? All the tutorials and documentation I have found have only been for iOS. Any help will be greatly appreciated!
Thanks in Advance!
Ben
Just use NSUbiquitousKeyValueStore, which is a lot like NSUserDefaults except that it's written to iCloud. You should read the iCloud Storage section of the Mac App Programming guide, but what you need to do may be as simple as enabling entitlements in the Summary tab of your App Target in Xcode, and then doing something like:
NSData *dataToStore = [NSKeyedArchiver dataWithRootObject:yourArray];
[[NSUbiquitousKeyValueStore defaultStore] setData:dataToStore forKey:#"yourKey"];
Then, to retrieve your data, just do
NSData *retrievedData = [[NSUbiquitousKeyValueStore defaultStore] dataForKey:#"yourKey"];
NSArray *retrievedArray = [NSKeyedUnarchiver unarchiveObjectWithData:retrievedData];
The one caveat here is that for this to work with an array of custom objects, these objects must all implement the NSCoding protocol. This is just a matter of implementing two methods; here's a good tutorial.
P.S. You use the same APIs whether you're developing for OS X or iOS, so there's no reason why you couldn't just follow an iOS tutorial for iCloud storage.