In App Purchase How to check if item purchased - xcode

hi there i have followed a tutorial online for in app purchase and have gotten it to work perfect but the only problem is when i reopen the app i have to restore the purchase to make is display again
how would i check when that app loads that the item was purchased and can display the purchased content
here is the link for the online tutorial - http://www.techotopia.com/index.php/An_iPhone_iOS_6_In-App_Purchase_Tutorial
if anybody could give me some pointers that would fantastic

You can store those data in NSUserDefaults or in the keychain and check in those whether the user has already purchased the item or not
To Store in the NSUserDefaults:
when user made your in App then set value in NSUserDefaults like this
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:YES forKey:#"isPurchase"];
[userDefaults synchronize];
and when you starts the app you can check whether the user has already purchased the in-app like this:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if(![userDefaults boolForKey:#"isPurchase"])
{
// Unlock your features code comes here
}
And I strongly recommend you to go through this tutorial

Related

How to save downloaded files(audio, doc) automatically to user's Downloads folder in mac os x sandboxed application?

In my Mac OS X application I tried to save downloaded files to application's directory(i.e. HomeDirectory()/Documents) but App Store rejected my application saying that your downloaded file is not accessible to the user easily( i.e. without opening the app). Then I tried to write the downloaded files to ~/Downloads folder by adding Read/Write permission in entitlements, but App Store again reject the application saying
Your application accesses the following location(s):
~/Download
The majority of developers encountering this issue are opening files
in Read/Write mode instead of Read-Only mode, in which case it should
be changed to Read-Only.
Other common reasons for this issue include:
creating or writing files in the above location(s), which are not valid locations for files to be written as stated in documentation.
writing to the above location(s) without using a valid app-id as a container for the written files.
Now the issue is App Store is neither allow me to save the files in App's Directory nor in System's folder(i.e. Downloads). Also I Don't want to use NSSavePanel every time. I want to download the files silently. Where should I save my files?
With the help of Security-Scoped Bookmark, user-selected read-write entitlement and NSOpenPanel I was abled to read/write to user selected folder.
Below are the steps I followed,
Added
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
in Entitlements file.
Asked the user to select(or create and select) the desired folder to which my application want to access(read/write) using NSOpenPanel.
When user selects the folder, I created the bookmark of selected folder path as bookmarked path in NSUserDefaults using NSURLBookmarkCreationWithSecurityScope.
NSOpenPanel *openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseDirectories:YES];
[openDlg setCanCreateDirectories:YES];
[openDlg setAllowsMultipleSelection:FALSE];
[openDlg setPrompt:#"Select"];
if ( [openDlg runModal] == NSModalResponseOK )
{
NSURL *url = openDlg.URL;
NSError *error = nil;
NSData *bookmark = [url
bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:bookmark forKey:#"DOWNLOAD_FOLDER_BOOKMARK_PATH"];
[userDefaults synchronize];
}
Once you saved the bookmarked path in NSUserDefaults you can access the saved path later using NSURLBookmarkResolutionWithSecurityScope.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSData * bookmarkedPathData = [userDefaults objectForKey:#"DOWNLOAD_FOLDER_BOOKMARK_PATH"];
NSURL* urlFromBookmark = [NSURL URLByResolvingBookmarkData:bookmarkedPathData
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:nil
bookmarkDataIsStale:nil
error:&error];
Once you got the saved Bookmarked URL you can use that URL to perform read, write operation. Before reading/writing from/to the URL, please start the scope using [urlFromBookmark startAccessingSecurityScopedResource]; . And after finishing read/write operation stop the scope using [saveFolder stopAccessingSecurityScopedResource];
Note: I did tried to write to directly to Documents, Downloads, Desktop without creating folder inside these directories but Apple rejected the app, saying
Your application access the following locations 'Downloads'.
Then instead of writing directly to these directories( Documents, Downloads, Desktop), I asked the user to select(create & select) a folder, then performed the read/write operations on user selected folder using Security-Scope-Bookmark.
Hope this helps someone.

iOS8: Sharing common files between apps

Two iOS: AppA and AppB
Both Apps are created by me and I would like to share one single file between both of the apps.
i.e. AppA launches on deviceA and the User saves data on fileA. Later the User launches AppB on the same (deviceA) and also saves data on fileA. Both apps are saving data on the same file.
I'm aware that I can use NSUserDefaults and share Keychain between apps, but that's not what I'm looking for.
I read up on document extensions provider and app groups, but I'm confused if I can use these for this scenario? Or is there any other way to accomplish this?
You can do it using Application Group Container Directory:
NSFileManager *fm = [NSFileManager defaultManager];
NSString *appGroupName = #"Z123456789.com.example.app-group"; /* For example */
NSURL *groupContainerURL = [fm containerURLForSecurityApplicationGroupIdentifier:appGroupName];
NSError* theError = nil;
if (![fm createDirectoryAtURL: groupContainerURL withIntermediateDirectories:YES attributes:nil error:&theError]) {
// Handle the error.
}
You could just upload the files after saving to your server and make both apps request updates for the file whenever they are launched.
Hope that helps :)

NSUserDefaults of different application

I am currently developing System Pane and my app have some configuration settings saved to User Defaults:
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:listOfStuff];
[userDefault setObject:encodedObject forKey:#"myStuff"];
[userDefault synchronize];
Can anyone tell me if and how a different application can read settings that have been saved in above System Pane?
Thank you.
The way to read someones preferences is very simple and straight forward:
NSUserDefaults *defaults = [[NSUserDefaults alloc] init];
[defaults addSuiteNamed:#"com.apple.systempreferences.plist"];
NSLog(#"DefaultExposeTab is: %#", [defaults stringForKey:#"DefaultExposeTab"]);
Make sure to initialize NSUserDefaults following way:
[[NSUserDefaults alloc] init];
then you can add desired preference list, in our case I would like to read System Preferences:
[defaults addSuiteNamed:#"com.apple.systempreferences.plist"];
and finally get value for whichever key you want, in this example:
"DefaultExposeTab"
Above example works like a charm. Please remember it will only work for current user.
Thanks.
P.S: Please note - above example will NOT work for sandboxed application.
As Melr explained, you need to use the suite name. But it's actually possible to read the preferences of another application from a sandboxed app. It requires a temporary exception entitlement.
For example, to read the Finder preferences, you need to add this to your
entitlements file:
<key>com.apple.security.temporary-exception.shared-preference.read-only</key>
<array>
<string>com.apple.finder</string>
</array>
Then you can access the Finder preferences like this:
NSUserDefaults *finderDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"com.apple.finder"];
NSDictionary *standardViewOptions = [finderDefaults dictionaryForKey:#"StandardViewOptions"];
NSNumber *fontSize = [standardViewOptions valueForKeyPath:#"ColumnViewOptions.FontSize"];
If you need to read the preferences of another app, just replace com.apple.finder with the appropriate bundle identifier.
My app Prefs Editor uses the CFPreferences functions for this (e.g. CFPreferencesSetAppValue). That gives you direct control over whose app's settings you'll access.
You can even access the prefs of sandboxed applications with this method, if you know their plist file's full path and pass that to the applicationID parameter.
For more info, read through the answers of this question: How does OS X's defaults command get access to prefs of sandboxed apps?
Yes another application can read the settings if you save by using NSUserDefaults because it saves the settings as an unencrypted plist file on disk.
Reading another application's settings from a plist file is easy. Search for the file path and open it. NSDictionary can be initialized with a string of the file path to a plist file.
If the defaults you want to store are secret (like password, security tokens, etc), then add an encrypted item to the keychain instead of storing them in a plist.
https://developer.apple.com/library/mac/documentation/security/Conceptual/keychainServConcepts/01introduction/introduction.html

How to force NSArrayController to reload MOC contents to reflect latest fresh data

I am working on a Mac & iOS App, with iCloud CoreData in between to synchronize the data.
When I update some thing from iOS App, and the updates are already migrated to the PersistentStore in Mac App while the Mac App is running. The problem is I cannot find an effective way to force the NSArrayController to reload all data from the store.
tried -(void) fetch:(id)sender; only can see the delete or added entity, but the updated model property not refreshed...
Please help. Thanks
If you see the latest data in the managed object context, but not in the array controller, you want:
[_yourManagedObjectContext processPendingChanges];
[_yourArrayController fetchWithRequest:nil merge:YES error:&error];
[_yourArrayController rearrangeObjects];
I use this in a Mac/iOS iCloud app to update the Mac app's data when the iCloud store changes.
Following is the reply from Apple's Developer Technical support. It worked for me. Thanks all for providing solutions.
For the OS X app, when reloadFetchResults is called, you can ask the NSManagedObjectContext to reset itself and perform the fetch again.
- (void)reloadFetchedResults:(NSNotification *)note
{
NSDictionary *userInfoDict = [note userInfo];
NSManagedObjectContext *moc = self.coreDataController.mainThreadContext;
// this only works if you used NSMainQueueConcurrencyType
// otherwise use a dispatch_async back to the main thread yourself
//
[moc performBlock:^{
[self mergeiCloudChanges:userInfoDict forContext:moc];
[moc reset];
[self.tableArrayController fetch:self];
}];
}
I've found that
[self.managedObjectContext reset];
[myArrayController fetch:self];
forces my NSTableView (with NSArrayController) to re-populate and display newly processed NSManagedObjects.
in case someone else finds this...
in my case, I was building the array from user interaction (not Core Data), and then trying to show the tableView when they were done (on the same window)... and of course... seeing nothing!
[arrayController rearrangeObjects];
just before I wanted to show the tableView fixed it for me.

Cocoa equivalent of .NET's Environment.SpecialFolder for saving preferences/settings?

How do I get the reference to a folder for storing per-user-per-application settings when writing an Objective-C Cocoa app in Xcode?
In .NET I would use the Environment.SpecialFolder enumeration:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
What's the Cocoa equivalent?
In Mac OSX application preferences are stored automatically through NSUserDefaults, which saves them to a .plist file ~/Library/Preferences/. You shouldn't need to do anything with this file, NSUserDefaults will handle everything for you.
If you have a data file in a non-document based application (such as AddressBook.app), you should store it in ~/Library/Application Support/Your App Name/. There's no built-in method to find or create this folder, you'll need to do it yourself. Here's an example from one of my own applications, if you look at some of the Xcode project templates, you'll see a similar method.
+ (NSString *)applicationSupportFolder;
{
// Find this application's Application Support Folder, creating it if
// needed.
NSString *appName, *supportPath = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES );
if ( [paths count] > 0)
{
appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleExecutable"];
supportPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:appName];
if ( ![[NSFileManager defaultManager] fileExistsAtPath:supportPath] )
if ( ![[NSFileManager defaultManager] createDirectoryAtPath:supportPath attributes:nil] )
supportPath = nil;
}
return supportPath;
}
Keep in mind that if your app is popular you'll probably get requests to be able to have multiple library files for different users sharing the same account. If you want to support this, the convention is to prompt for a path to use when the application is started holding down the alt/option key.
For most stuff, you should just use the NSUserDefaults API which takes care of persisting settings on disk for you.

Resources