Changing provided services based on user preferences in OSX? - objective-c

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).

Related

Is there a way to update SMLoginItemBookmarks data on launchd overrides.plist

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.

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.

Are there any update frameworks for iOS apps?

I need to be able to update my app from within the app itself. I know Sparkle works for Mac Apps but I can't seem to find any for iOS.
Edit: I am not asking how to bypass the review process. I was thinking that there might be frameworks similar to Clutch.io that allow updates to images/documents/etc from within the app. Or things like UrbanAirship that manage in app purchase data that allows an app to be extended from the app itself.
You can't replace your app with an updated one (except through the App Store) and you can't replace parts of your app with updated parts (that would make your app's code signature invalid); you can only update stuff that's outside of your app's bundle.
You can't update the app binary yourself, the system is responsible for updating all apps.
Though, if you just want to update some data in your app you can do that for sure.
Here is what I was looking for:
http://code.google.com/p/cooliris-toolkit/
It has a class called RemoteUpdater which allows me to download zip files of images/data or whatever I like to extend my content.
Depends on your needs. If you dont want to see the app you can also do an Enterprise Deploy.
Used by corporations to distribute apps to their clients or employees.
Needs a separate Apple account which costs more.
Uses same process as deploy to appstore
Archive > Distribute > create ipa/plist > copy these to webserver with html page with link to plist and user clicks on link from Safari on iOS Device and it installs.
Going back to CArpp Store review process after that is painful.

Mac App: Storing Information w/ Document-based Applications

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.

Get droplet path without making app document based

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.).