I'm in the process of planning out the infrastructure for a Mac App, and we have a startup screen with many user files listed. We want the App to be iCloud-compatible (thus the need for Document-based (key-value won't cut it since they aren't nested - correct me if I'm wrong here)). Essentially, we don't want to have the user keep track of each individual file themselves as that would be irritating, but rather store it in the App's folder until the user needs it (i.e. Email, Export, etc). It would eliminate a lot of the friction in the app, we think. I guess my question is:
Is it possible to store files automatically in the App's installation folder (or somewhere locally?) without bothering the user - in a Document-based app - and still be App Store compatible? Seems like the ideal solution - user opens app, App knows it's save location and automatically saves documents there when a user creates one, and pulls them to share if needed. Any help?
Yes, it's possible. You won't want to store document's in the application's installation folder. For one thing that'll violate the App Store rules, but it's bad behavior anyway, since Applications are normally installed in /Applications, which shouldn't be cluttered up with other files. So storing things in ~/Library/Application Support/YourAppName is the way to go.
To actually implement this, take a look at NSDocumentController and NSDocument itself. You'll basically want to override/modify any UI that allows users to choose a location to save/open documents. Instead, just let them name the documents, and then automatically save them with the given name in the app support folder. Then create a UI that allows them to browse and open those files within the app.
Related
I'm working on an OS X app that most users choose to "launch at login", the kind you'd find at the menu bar.
In order to launch it at login I'm using SMLoginItemSetEnabled to launch a LoginHelper app that will open the main app, as described in this tutorial.
The app is failing to start up at login for just a handful of our users.
I was unable to reproduce this or to track the cause but I found (on a user's machine) that:
Deleting /Root/_com.apple.SMLoginItemBookmarks/[myapp] and /Root/[myapp] on /var/db/launchd.db/com.apple.launchd.peruser.$UID/overrides.plist and then resetting the Launch at login on the app fixed the issue. Also, we diff'd the files and the Data on the bookmark had changed.
For reference, I found about the overrides.plist here.
Since the app has both a Mac App Store and a Direct download version, I'm suspecting multiple copies of the app setting themselves as Launch at login may be the reason for this to fail, maybe these "bookmarks" are trying to open another instance of the app, that may or may not be deleted.
Now the questions, provided that this app needs to remain sandboxed:
Is there a way of updating that Data on the overrides.plist bookmarks?
Is there any way of deleting one self's app from the overrides.plist to start clean?
Is this maybe a known issue?
Any other suggestions on why the bookmark seems to point nowhere or how to fix it will be appreciated.
Note: This is my first question on StackOverflow, please excuse me if I failed to follow some of the suggested etiquette.
I don't know a definitive solution to this, I wasn't even aware of the overrides.plist. It could be related to multiple copies. As far as I understand, adding login through SMLoginItemSetEnabled sets a metadata flag that this Bundle ID should be launched on start. Then Spotlight, on start, will go do a metadata search on the file system and see which Bundle IDs need to be launched. Then, I guess, it will initiate the launch using the bundle ID. In my own application, Trickster, which uses the same technique for launching, I see that if I enable launch-on-login through the app itself, it might pop-up this strange message which refers to a debug build. I'm not even sure why it says about the first time. Very strange.
So, to have them launched, you have to make sure that the relevant bundles are in locations where Spotlight indexes (that the user hasn't disable Spotlight for these locations). Usually users don't disable Spotlight, especially for /Applications/ but I'm just saying.
What I usually suggest when support comes my way (and how I have it set up for me because I have multiple copies), is I to disable launch from within the app and instead add the correct one (from /Applications) manually in Login Items in System Preferences.
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.
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.
I have a fairly straightforward question about using droplets for my mac application. My app is not a document based app.
Is there any way to get the path of the item that was dropped? How would I go about implementing this if that was the case? I have looked into this, and it doesn't look like I can do droplets at all without making my app document based, which I really don't want to do.
Thanks ahead of time!
You don't have to use NSDocument at all to make a droplet. Just include CFBundleDocumentTypes in your Info.plist (see Storing Document Types Information in the Application's Property List for details) and implement application:openFile: in your app delegate (there are variants of this method for multiple files etc.).
I would like to be able to change the OSX services that my application provides based on the current user's preferences (like adding more, changing the name,...). This basically means modifying the Info.plist (NSService key), but I don't think it is a good practice when an application modifies its own Info.plist while running, right? (At least based on few searches here). Is there any other option how to get this functionality?
I guess it should always be an external entity who does modify the Info.plist? So far I can only think about providing a system preference bundle which will do the modification in the actual app? Do you have any ideas?
Thank you
One way would be to install a service in ~/Library/Services that provides the services, and edit that application's Info.plist from your main application.
Of course, that should be an explicit action, so the user (hopefully) knows to delete the service if they delete your application. And you should document that procedure on your product's support web page, just in case they don't.
Here's a small twist to the previous recommendations, create a separate app that handles the service and bundle it within your Resources. When you want to enable the service, instead of copying the file over to ~/Library/Services, create a symbolic link within the ~/Library/Services folder that points to the app you bundled in your Resources.
This way if the user deletes your application, all that will be left behind is a symbolic link pointing to an invalid location. Does less arm than actually leaving the app behind and will have the added benefit that the service will no longer be available (since the info.plist will have been removed when the user deleted your app).