MKStoreKit Implementation - iphone

I have spent the last 2 days fighting trying to get in app purchases working! The app has not been approved by Apple (its not ready yet), so I just did the Developer Pulled Binary method. I added a non-consumable (and I am pretty sure my contracts are cleared) and called it com.MYAPP.MYAPPNAME.levelone
I am using the MKStoreKit 3.1 relevant
I just want to see that the item will appear in the NSLog for the app, so I have this in my App Delagate
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
[MKStoreManager sharedManager];
[[MKStoreManager sharedManager] purchasableObjectsDescription];
...
When I run this it just tells me
Problem in iTunes connect configuration for product: com.mycompany.myapp.005
Problem in iTunes connect configuration for product: com.mycompany.myapp.featureA
This is a Cocos2d based game if it makes any difference.

There are reasons why I didn't implement MKStoreManager to accept a set of products as parameters.
1) You should not litter your code with hard coded product ids. This is because you initiate a purchase request with a product id. The former happens on AppDelegate and the latter happens on one of your view controllers. So there should be some file where you put in all those product constants. Why not use MKStoreManager.h itself for that?

MKStoreKit 3.1 requires some configuration before you use it; it doesn't just work out of the box.
Specifically, you need to tell MKStoreKit the list of features/product identifiers that you have configured in iTunes Connect. Oddly, you do that by modifying the source code, instead of passing in an array of arguments.
Examine MKStoreManager.h lines 26-34:
// CONFIGURATION STARTS -- Change this in your app
define kConsumableBaseFeatureId #"com.mycompany.myapp."
#define kFeatureAId #"com.mycompany.myapp.featureA"
#define kConsumableFeatureBId #"com.mycompany.myapp.005"
// consumable features should have only number as the last part of the product name
// MKStoreKit automatically keeps track of the count of your consumable product
#define SERVER_PRODUCT_MODEL 0
// CONFIGURATION ENDS -- Change this in your app
You have to change that stuff. If you don't, you'll get errors like the one you posted.
But that's not the only place. You also have to update the requestProductData implementation function in MKStoreManager.m, where kFeatureAId and kConsumableFeatureBId are used.
-(void) requestProductData
{
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:
kFeatureAId,
kConsumableFeatureBId,
nil]];
request.delegate = self;
[request start];
}
You have to specify the product identifier list yourself; MKStoreKit can't guess it for you.
Still, it's weird. It makes you wish MKStoreKit would just accept an array of product identifiers in its initializer!

Remove the unused products inside MKStoreManager.m as follows
-(void) requestProductData
{
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:
kFeatureAId,
//kConsumableFeatureBId,
nil]];
request.delegate = self;
[request start];
}

Related

MPMediaPickerController.showsCloudItems seems to do nothing

Posted this on Apple with no luck, but now that the iOS 6 NDA is up, hoping more eyes will see it here.
I am attempting to modify an app to only allow a user to select music that has been downloaded locally. I have the following code under iOS 6 GM:
MPMediaPickerController* mpc = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeAnyAudio];
mpc.allowsPickingMultipleItems = YES;
mpc.modalPresentationStyle = UIModalPresentationCurrentContext;
mpc.showsCloudItems = NO;
[self presentViewController:mpc animated:YES completion:nil];
From the documentation:
The default behavior for a media item picker is YES, which means the
the picker shows available iCloud items. A media item is considered an
iCloud item if it is available via iTunes Match and is not already
stored on the device.
I take this to mean that if iTunes Match is enabled, only items that have been downloaded to the device will show in the picker, however I always see the entire iTunes Match library. I filed a radar for this, because it seems like a serious bug. If anyone can tell me otherwise, I'd love to know what I'm missing here.
This seems to be an OS problem.
Using picker.showsCloudItems = NO; correctly shows fewer songs, instead of the whole list... The songs listed there are songs that either were manually downloaded in the Music app or songs that were streamed and therefore cached.
The problem, at least in my case, is dealing with the cached ones.
If I select a song that was manually downloaded the value of MPMediaItemPropertyIsCloudItem is NO, which is correct. I can also access the asset's URL through the MPMediaItemPropertyAssetURL property.
On the other hand, selecting a song that was cached returns YES on MPMediaItemPropertyIsCloudItem and nil on MPMediaItemPropertyAssetURL, making the song virtually useless to me.
Sorry I don't have an actual answer but I don't have enough reputation to simply comment.
Hope my 2 cents help somehow, but it truly seems to me that this issue can only be resolved by Apple in a future update.
A better solution to test if an item comes from iCloud in the didPickMediaItems delegate:
MPMediaItem *selectedItem = [selectedItems objectAtIndex:0];
if (![[selectedItem valueForProperty:MPMediaItemPropertyIsCloudItem] boolValue])
You don't really need to play it, it is more efficient to use the embedded property in the MPMediaItem.
I had this same problem. Although I was unable to hide the items, here's a good workaround that I used to prevent people from being able to select them. Inside didPickMediaItems, you should temporarily load it into an AVPlayerItem and then just check the validity of that item like so:
- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
{
MPMediaItem *selectedItem = [[mediaItemCollection items]objectAtIndex:0];
NSURL *tempURL = [selectedItem valueForProperty:MPMediaItemPropertyAssetURL];
AVPlayerItem *playerItem = [[AVPlayerItem alloc]initWithURL:tempURL];
if(playerItem.loadedTimeRanges==NULL)
{
UIAlertView *alert=[[[UIAlertView alloc]initWithTitle:NSLocalizedString(#"Invalid Song Choice",NULL) message:NSLocalizedString(#"Please choose a song that is local to your phone.",NULL) delegate:self cancelButtonTitle:NSLocalizedString(#"Okay",NULL) otherButtonTitles:nil]autorelease];
[alert show];
[playerItem release];
}
else
{
NSLog(#"Your good to go...do whatever you want with the local song");
}
}
It appears to be fixed in iOS 7.
The following code works; iCloud items are not showing:
MPMediaPickerController *picker = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeMusic];
picker.delegate = self;
picker.allowsPickingMultipleItems = NO;
picker.showsCloudItems = NO;

sandbox leaderboard empty

I'm trying to make a Game Center leaderboard for my app. I've been following the steps from Apple and following the sample code from GKTapper, but I can't get any scores to show in Game Center. I've set up the leaderboard in iTunes Connect. Here's the code that reports the score:
- (void) reportScore: (int64_t) score forCategory: (NSString *) category {
GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
scoreReporter.value = score;
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil)
{
UIAlertView* alert= [[[UIAlertView alloc] initWithTitle: #"Score Report Failed!" message: [NSString stringWithFormat: #"Reason: %#", [error localizedDescription]] delegate: self cancelButtonTitle: #"Try Again..." otherButtonTitles: NULL] autorelease];
[alert show];
}
}];
}
The code seems to run fine. The alert is never shown. But, when I go into Game Center, the leaderboard is blank. I'm running Xcode 4.2 and iOS 5. Any ideas?
Whatever's been told is completely true :
you need an int_64t score;
you need all things set up on iTunesConnect;
you need to use a sandbox account.
What I have just found out is that there's no such thing in iTunesConnect as the Category. On the other hand, you're supposed to init your GKScore with the leaderboard category.
From what i've seen over the forums, about 2/3 of the people get it right.
In iTunesConnect, when you configure a leaderboard, you set :
its reference (which i long thought was the category);
its ID (which turns out to be the actual category).
I was trying to post score using the reference instead of the ID.
Two things :
first, i had no error from the program (which, in some way, is acceptable);
second, once i got it right, i notice that, whereas many people claim the opposite, there's no need for more than one sandbox account to display the score.
Setting the category explicitly again after the init fixed it for me.
Scoreobject.category = category
Also to show the right leaderboard I set the category there aswell.
leaderboardobject.category = #"mycategory";
1) Please check if you have spelled the category correctly. Surprisingly, I was not getting an error even when I had my category misspelled. Correcting the typo fixed the issue for me.
2) Please check if you are setting the right Leaderboard before presenting the GKLeaderboardViewController? Set it correctly as below:
GKLeaderboardViewController *leaderboardViewController = [[[GKLeaderboardViewController alloc] init] autorelease];
leaderboardViewController.category = #"yourcategoryname";
[youviewcontroller presentModalViewController:leaderboardViewController animated: YES];
Two verified GameCenter users must have reported scores to a leaderboard before any scores show up in the leaderboard.
If you've only got one user in your Sandbox, create another and report a score.
If it's still not working, make sure that you verified the email address of both users.
The documentation for reportScoreWithCompletionHandler says :
"Your application should keep a strong reference to the score object until the reporting task is complete."
You are autoreleasing. Since the task will complete later, the object is probably deleted before the operation is executed.

getting operator details in iphone

How to get the currently using operator details (like Airtel or Idea or etc..)of iPhone.
Is it possible to get those details or is there any way to identify which operator currently we are using.I am developing an application which is based on the operator, if user changes his SIM(Operator) then the app shouldn't work, it has to work for that particular operator.
CTCarrier should have the info you need in it.
Edit: CTTelephonyNetworkInfo responds to a user switching SIMs mid-session, and provides an instance of CTCarrier for you.
Sample code (in your app delegate):
#import <CoreTelephony/CoreTelephony.h>
static NSString *requiredCarrier = #"Verizon"; // example carrier
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
CTTelephonyNetworkInfo *myNetworkInfo = [[CTTelephonyNetworkInfo alloc] init];
CTCarrier *myCarrier = [myNetworkInfo subscriberCellularProvider];
if(![[myCarrier carrierName] isEqualToString:requiredCarrier])
{
// lock the app, possibly terminate the app after displaying a UIAlertView
// informing the user of the network-lock.
}
// ...
return YES;
}
Note the following advisory on the properties of CTCarrier (I would recommend not doing a permanent one-way lock if a nil carrier is read):
"The value for this property is nil if any of the following apply:
The device is in Airplane mode.
There is no SIM card in the device.
The device is outside of cellular service range."
Of the properties of CTCarrier to validate on, I would recommend carrierName specifically as it doesn't change when the user is roaming so the app will still work as long as the SIM is tied to your desired operator.
Just a quick note in case someone is looking for this.
I have noticed from playing with the CTCarrier API that "nil" is returned to any of its properties only on the emulator. On the device it returns #"" (blank string) for some reason! Checking agains nil failed ont eh device but checking equality with #"" worked!
You can use the Core Telephony framework to achieve this. In particular CTCarrier and the carrierName property. View the documentation here: http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Reference/CTCarrier/Reference/Reference.html%23//apple_ref/doc/uid/TP40009596

iPhone Gigya integration sharing Facebook, twitter inconsistency

I am currently integrating facebook and twitter for iphone with gigya.
For Twitter sometimes its sharing and sometimes don't. Facebook also happening same as well.
lately facebook not even opening its login in screen. On device unlike simulator delegate methods like LoginDidFail, DidLogin called more than once.not sure why.
I am not storing any object to store provider info when login happens.
Can you please let me know why this inconsis
This seems like a multi part question.I would need more information to get a clearer understanding. Please provide code snippets if possible. Meanwhile, please see see my responses below:
Inconsistent Sharing
This might be something to do with how your userAction is being defined.
(http://wiki.gigya.com/030_API_reference/010_Client_API/010_Objects/UserAction_object)
Login Screen not loading
Typically this is down to social Network Applications not set up correctly.
(http://wiki.gigya.com/035_Socialize_Setup/005_Opening_External_Applications)
Event Delegate methods called repeatedly
This may be down do multiple instances of the GSAPI class.
Hope that helps.
I am using following code snippet
GSAPI *gsAPI // declared this in header file
gsAPI = [[GSAPI alloc] initWithAPIKey:XX viewController:self]; // i kept this in viewDidload
// add this code to have facebook and twitter on provider list. this was put in in one method which will be called when user tries to share
GSDictionary *pParams5 = [[GSDictionary new] autorelease]; [pParams5 putStringValue:#"facebook,twitter" forKey:#"enabledProviders"];
[gsAPI showAddConnectionsUI:pParams5 delegate:self context:nil];
//this method called when login fails -(void)gsLoginUIDidFail:(int)errorCode errorMessage:(NSString*)errorMessage context:(id)context {
}
// this method called on successful login
- (void) gsLoginUIDidLogin:(NSString*)provider user:(GSDictionary*)user context:(id)context {
GSDictionary *userAction = [[GSDictionary new] autorelease];
[userAction putStringValue:#"title" forKey:#"title"];
[userAction putStringValue:#"userMessage" forKey:#"userMessage"];
[userAction putStringValue:#"desc" forKey:#"description"];
[userAction putStringValue:#"imageurl" forKey:#"linkBack"];
GSDictionary *pParams5 = [[GSDictionary new] autorelease];
[pParams5 putGSDictionaryValue:userAction forKey:#"userAction"];
[gsAPI sendRequest:#"socialize.publishUserAction" params:pParams5 delegate:self context:nil];
}
-(void) gsDidReceiveResponse:(NSString*)method response:(GSResponse*)response context:(id)context {
//showing alert messages on successful sharing
//this method getting called more than twice on device
}

Invoking [SKProductsRequest start] hangs on iOS 4.0

Encountering an issue with SKProductsRequest that is specific to iOS 4.0. The problematic code:
- (void)requestProductData
{
NSSet *productIdentifiers = [NSSet setWithObjects:kLimitedDaysUpgradeProductId, kUnlimitedUpgradeProductId, nil];
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
self.productsRequest.delegate = self;
[self.productsRequest start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(#"didReceiveResponse");
}
When [SKProductsRequest start] is invoked, the productsRequest:didReceiveResponse: delegate method is never invoked; further, the entire app hangs and is completely unresponsive to input. Obviously, this is a huge issue for our iOS 4.0 users as it not only breaks payments but makes the app completely unusable.
Some other things to note: this only happens on iOS 4.0; iOS 4.2, 3.x are fine. Also: if the delegate is not set on the SKProductsRequest (i.e. comment out the line "self.productsRequest.delegate = self;"), the app doesn't hang (but of course in that case we have no way of getting the product info). Also, the problem still reproduces with everything stripped out of the productsRequest:didReceiveResponse: callback (that method never actually gets called). Finally, if the productIdentifiers NSSet object is initialized to an empty set, the hang doesn't occur.
Has anybody else experienced this? Any ideas/thoughts on what could be going on here, and how we might be able to work around this?
have you tried implementing –request:didFailWithError: in your delegate, and seeing if that's getting called?
I had a similar problem to this today. No response to any of the delegate methods after I made a SKProductRequest.
Everything was working fine, I didn't make any changes to the IAP code yet it broke.
Finally found the problem. If you self reject the app, then the product ID's you made become invalid. We resolved it by resubmitting the app and creating new ID's. Everything started to work again after that.