Posts

Post not yet marked as solved
1 Replies
730 Views
I am implementing IAP for an autorenewable subscription. I decode the receipt on the device. I noticed in the sandbox that the original_transaction_id is changing for each renewal. (It is always the same as the transaction_id which differs for each renewal, as it should.) Can anyone confirm that this is NOT what happens in production?A WWDC video states that the original_transaction_id for an autorenewable subscription can be used to associate different devices owned by the same user. I had always thought that the original_transaction_id would differ from device to device. Can anyone confirm that in production the original_transaction_id is the same across all devices owned by the same user for an autorenewable subscription?
Posted
by PBK.
Last updated
.
Post marked as solved
11 Replies
2.3k Views
I am trying to implement GKVoiceChat between two iPhones (an iPhone X and an iPhone 5s) in iOS11.3.1 Xcode 9.3.1. I have the GameKit connection working fine but not the voice. Has anyone got VoiceChat working? Can anyone see anything wrong in the code here? Thanks...Here is my relevant code:#import <GameKit/GameKit.h> #include <AVFoundation/AVFoundation.h> //in a method at the beginning...... AVAudioSession *audioSession = [AVAudioSession sharedInstance]; NSError *error= nil; [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; [audioSession setActive:YES error:&error]; if(error){ NSLog(@"audioSession: %@ %ld %@", [error domain], (long)[error code], [[error userInfo] description]); }else{ [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error]; if(error){ NSLog(@"audioSession1: %@ %ld %@", [error domain], (long)[error code], [[error userInfo] description]); }else{ if( [GKVoiceChat isVoIPAllowed]){ allChannel=[[GKVoiceChat alloc] init]; allChannel=[myMatch voiceChatWithName:@"allPlayers"]; if(allChannel){ allChannel.volume = 1.0; allChannel.active=YES; [self performSelector:@selector(delayedStart) withObject:nil afterDelay:6.0f];//give Game Center a chance to respond }else{ NSLog(@"no channel was oppend"); } }else{ NSLog(@"voip not allowed"); } } } -(void)delayedStart{ [allChannel start]; NSLog(@"started"); }Here are the errors I get that I don't think are relevant. They all occur before the delayed call to [allChannel start] and they are there whether or not I implement any of the GKVoiceChat code. I think they are bugs in the GKMatch system. I am ignoring them://these errors occur before the match has been found and before the code above is executed: 2018-05-17 21:05:31.006119-0400 Go[477:67899] [log] [ERROR] gckSessionCheckPendingConnections:1438 gckSessionCheckPendingConnections: iICEChecksLeft=0, iUnconnectedNodeCount=0, iDDsExpected=1 2018-05-17 21:05:31.063331-0400 Go[477:67847] [log] [ERROR] ICEStopConnectivityCheck:2688 ICEStopConnectivityCheck() found no ICE check with call id (2019854734) 2018-05-17 21:05:31.065208-0400 Go[477:67847] [log] [ERROR] gckSessionCheckPendingConnections:1438 gckSessionCheckPendingConnections: iICEChecksLeft=0, iUnconnectedNodeCount=0, iDD // the next line occurs when there is a call to matchmakerViewController:viewControllerDidFindMatch: and the code above is then executed 2018-05-17 21:05:35.251683-0400 Go[477:67566] [Error] Extension request cancelled with error: Error Domain=NSExtensionErrorDomain Code=-2 "Extension cancelled by host." UserInfo={NSLocalizedDescription=Extension cancelled by host.}Here are the errors I get after setting the GKVoiceChat object to start (i.e. after that 6 second delay):2018-05-17 21:05:40.766056-0400 Go[477:67566] started 2018-05-17 21:05:41.310557-0400 Go[477:67895] [log] [ERROR] openLogDump:65 failed to open /var/mobile/Library/Caches/com.apple.VideoConference/logs/20180517-210541-0757771790-CallSettings.calldump with error 1 2018-05-17 21:05:41.449639-0400 Go[477:68033] [] WiFi:[548298341.448992]: Missing com.apple.wifi.manager-access entitlement 2018-05-17 21:05:41.449986-0400 Go[477:68033] [] WiFi:[548298341.449970]: Missing com.apple.wifi.manager-access entitlement 2018-05-17 21:05:41.450418-0400 Go[477:68033] [] WiFi:[548298341.450400]: Missing com.apple.wifi.manager-access entitlement 2018-05-17 21:05:41.451010-0400 Go[477:68033] [] WiFi:[548298341.450924]: Missing com.apple.wifi.manager-access entitlement 2018-05-17 21:05:41.451625-0400 Go[477:68033] [] WiFi:[548298341.451608]: Missing com.apple.wifi.manager-access entitlement 2018-05-17 21:05:43.648429-0400 Go[477:67566] Bad response from apsd: Connection interrupted 2018-05-17 21:05:43.662956-0400 Go[477:67566] [Warning] Remote loader crashed for request: <NSMutableURLRequest: 0x10ba1bb60> { URL: http://init.ess.apple.com/WebObjects/VCInit.woa/wa/getBag?ix=4 } 2018-05-17 21:05:43.664051-0400 Go[477:67566] [Warning] => Retrying... (0/5) retries 2018-05-17 21:05:43.667507-0400 Go[477:67566] [Warning] Remote loader crashed for request: <NSMutableURLRequest: 0x10ba1bb60> { URL: http://init.ess.apple.com/WebObjects/VCInit.woa/wa/getBag?ix=4 } 2018-05-17 21:05:43.667646-0400 Go[477:67566] [Warning] => Retrying... (1/5) retries 2018-05-17 21:05:45.845023-0400 Go[477:67566] [Warning] Remote loader crashed for request: <NSMutableURLRequest: 0x10ba1bb60> { URL: http://init.ess.apple.com/WebObjects/VCInit.woa/wa/getBag?ix=4 } 2018-05-17 21:05:45.845205-0400 Go[477:67566] [Warning] => Retrying... (2/5) retries 2018-05-17 21:05:46.484616-0400 Go[477:67895] [log] VideoConference [ERROR] -[VideoConference inviteDataForParticipantID:callID:remoteInviteData:nonCellularCandidateTimeout:error:]:855 VideoConference: CALLID MISMATCH 0x10bb332e0 client callID 6161504380 internal callID 0 2018-05-17 21:05:46.490559-0400 Go[477:68030] [log] [ERROR] VCAudioReceiver_DiscardQueueExcess:454 AudioReceiver is NULL 2018-05-17 21:05:46.490986-0400 Go[477:68030] [log] [ERROR] VCAudioReceiver_DiscardQueueExcess:454 AudioReceiver is NULL 2018-05-17 21:05:50.246310-0400 Go[477:67566] [Warning] Remote loader crashed for request: <NSMutableURLRequest: 0x10ba1bb60> { URL: http://init.ess.apple.com/WebObjects/VCInit.woa/wa/getBag?ix=4 } 2018-05-17 21:05:50.246469-0400 Go[477:67566] [Warning] => Retrying... (3/5) retries 2018-05-17 21:05:52.019693-0400 Go[477:67895] [log] VCCallSession [ERROR] -[VCCallSession startConnectionWithParticipantID:callID:usingInviteData:isCaller:capabilities:idsSocket:destination:error:]_block_invoke:2215 - Reporting not available (no backends) 2018-05-17 21:05:56.819849-0400 Go[477:67566] [Warning] Remote loader crashed for request: <NSMutableURLRequest: 0x10ba1bb60> { URL: http://init.ess.apple.com/WebObjects/VCInit.woa/wa/getBag?ix=4 } 2018-05-17 21:05:56.820068-0400 Go[477:67566] [Warning] => Retrying... (4/5) retries
Posted
by PBK.
Last updated
.
Post not yet marked as solved
0 Replies
375 Views
FYI - There appears to be a bug in the sandbox. When you do a restoreCompletedTransactions it will call updatedTransactions for each purchase that is being restored. But it will call with a transaction.transactionState equal to SKPaymentStatePurchased not SKPaymentStateRestored. After multiple calls to updatedTransactions with the wrong transaction.transactionState it will correctly call paymentQueueRestoreCompletedTransactionsFinished:
Posted
by PBK.
Last updated
.
Post marked as solved
6 Replies
606 Views
I am looking for a way to limit the reuse of a one-time offer in an app. For example, a feature that is available for a period of time and subsequently must be purchased through an IAP. I am concerned that the 'free trial' period in a 'free' non-consumable IAP or an autorenewable subscription can be 'hacked' by creating multiple App Store accounts. (Is that concern unwarrented?) While I am concerned about multiple App Store accounts, I am not concerned about multiple Apple ID's because it is a sufficient pain to change a device's Apple ID that I can allow that 'hack'. I do not need to know who the user is - I just need a permanent identifier for the user (or the device) that records 'first use of app' by the user or by the device. (DeviceCheck requires a server and is just a bit too complicated.)1) I can't use identifierForVendor because it gets reset on app delete-and-reinstall.2) I am told I can no longer reliably use the keychain (my current solution) because in various betas and perhaps the latest iOS it gets wiped out on app deletion.3) I am told that the user's iCloud key-value can be deleted by the user through the Settings app after app deletion.A) Can I use the user's CloudKit private database as a place to store permanent information? Will it survive deletion of the app and the user removing the app from being able to access CloudKit?B) Can I use the user's userRecord in the public database in CloudKit? Will it survive deletion of the app and the user removing the app from being able to access CloudKit?C) Is there any other way to leave a permanent record on a user's device or elsewhere?
Posted
by PBK.
Last updated
.
Post not yet marked as solved
0 Replies
365 Views
Does anyone know if the following records/files are 'permanent'? That is, are they deleted when the user deletes the app, logs out of iCloud and denys the app access to CloudKit/iCloud Drive?1) The user's iCloud key-value file for the app.2) Files in the user's CloudKit private database.3) The user's userRecord in the public database in CloudKit.4) The iCloud keychain entries for the app.
Posted
by PBK.
Last updated
.
Post marked as solved
1 Replies
496 Views
My app (in production environment) stopped generating push notifications based on a CKSubscription firing. This seems to have happened within the past few hours. Has anyone else noticed a problem or can anyone confirm that CloudKit CKSubscriptions contnue to work for them?
Posted
by PBK.
Last updated
.
Post not yet marked as solved
1 Replies
691 Views
Since July 11th my CloudKit Dashboard shows no push notifications (Production, Telemetry) and the Logs show no pushes however I have been receiving them every hour. Is anyone seeing the Dashboard correctly displaying or incorrectly not displaying pushes since July 11th?
Posted
by PBK.
Last updated
.
Post not yet marked as solved
2 Replies
2.5k Views
Since IAPs were first created you were not allowed to unlock code in an app using anything other than IAPs (aka 3.1.3 first bullet). That has now changed. New guideline 3.1.3(b) (see below) allows an app to accept a purchase from another platform and use that to "access content, subscriptions, or features". "(F)eatures" here means unlocking code. This new 3.1.3(b) supercedes many of my past comments. Thank you anti-trust law.3.1.3(b) Multiplatform Services: Apps that operate across multiple platforms may allow users to access content, subscriptions, or features they have acquired elsewhere, including consumable items in multi-platform games, provided those items are also available as in-app purchases within the app. You must not directly or indirectly target iOS users to use a purchasing method other than in-app purchase, and your general communications about other purchasing methods must not discourage use of in-app purchase.
Posted
by PBK.
Last updated
.
Post not yet marked as solved
0 Replies
671 Views
When I query CloudKit using the Dashboard (Production/data) I get the first 200 records. At the bottom of the screen it states "200 Records listed". Sometimes it also includes an option button "Show more" - but not always. How do I get that option button to appear if I know there are more records to display?
Posted
by PBK.
Last updated
.
Post marked as solved
1 Replies
1.3k Views
(This question is also posted deep inside a thread on the CloudKit forum. But since it relates to Notifications perhaps this is a better place for it.)CloudKit has a feature whereby in response to a CKQuerySubscription the user will receive a push notification alert when certain CKRecords in CloudKit are changed. If they tap on that push notification alert then the app will open. CloudKit also has a limit of 40 queries per second - a number which is often quoted as large enough for almost any needs. But it's not because: 1) suppose an app has 10,000 users 2) all users subscribe to receive an alert notification when there is a change in a single important record 3) if that record changes only once every month 4) when that record changes many of the 10,000 will open their app at the exact same time after receiving the alert notification, or at most within few seconds of each other 5) If the app then tries to download that changed record the 40/second limit will be hit and it will take over 5 minutes to download the change to the 10,000. 6) This assumes the app does a masterful job of queueing the 10,000 based upon the error CKErrorRequestRateLimitedHow do you deal with this issue?One solution is to include the entire record information in the notification and not query CloudKit after the notification. You could do that using alertLocalizationArgs or desiredKeys. But the value of each key "may be truncated (to 100 characters) when added to the push notification" and desiredKeys is limited to 3 keys. Does anyone know the limit to the number of keys you can have in alertLocalizationArgs and the allowable size of a total notification? Help!
Posted
by PBK.
Last updated
.
Post not yet marked as solved
0 Replies
701 Views
Error message is: 'CKModifyBadgeOperation' is deprecated: first deprecated in iOS 11.0 - No longer supported, will cease working at some point in the futureDoes anyone know how to reset the badge number if you want the badge to indicate the number of notifications that were sent to the app since the last time the app was opened? If you just reset it to 0 on the device without using CKModifyBadgeOperation then the next time CloudKit sends a notification the number displayed is the old number plus 1.
Posted
by PBK.
Last updated
.
Post marked as solved
1 Replies
625 Views
I have a basic misunderstanding of something.I want each user to be able to switch on, or switch off, a subscription* which will notify them when new records are added to the public database. Because they can turn this on or off, each user must have their own unique subscription and they do a: CKModifySubscriptionsOperation *modifySubscriptions= [[CKModifySubscriptionsOperation alloc] initWithSubscriptionsToSave:subscriptionToAdd subscriptionIDsToDelete:subscriptionIDsToDelete];with the subscription in subscriptionsToAdd or subscriptionIDsToDelete.If I used identical subscriptions for each user then when one user deleted it it would be deleted for all users.So....1) this means that if I have 20,000 users I will have 20,000 subscriptions* - IS THAT THE CORRECT PROCEDURE????and2) I am violating this provision: IS IT OK TO IGNORE THIS?????? "Subscriptions must be created in the Development environment first and then promoted to Production. Attempting to create a subscription directly in the Production environment will result in an error." https://developer.apple.com/documentation/cloudkit/cksubscription?language=objc* actually I have 5 different recordTypes. The user gets to select, from amongst the 5, which ones they want to turn on/off. So the problem is 100,000 subscriptions and cannot be 'solved' by enabling or disabling all notifications for the device. NSString *subID=[anAlert stringByAppendingString: [[[[UIDevice currentDevice] identifierForVendor] UUIDString] substringFromIndex:4]]; CKQuerySubscription *itemSubscription=[[CKQuerySubscription alloc] initWithRecordType:recordType predicate:predicate subscriptionID:subID options:CKQuerySubscriptionOptionsFiresOnRecordCreation]; itemSubscription.notificationInfo = notification; [subscriptionToAdd addObject:itemSubscription];.
Posted
by PBK.
Last updated
.
Post not yet marked as solved
0 Replies
593 Views
I have registered a subscription in CloudKit. If it is triggered while the app is open I get two successive calls touserNotificationCenter:willPresentNotification:withCompletionHandler:separated by 0.2 seconds.If the subscription is triggered while the app is in the background and then when I open the app (either by tapping on the notification or by tapping on the app icon long after the notification has disappeared) I get one call to willPresentNotification. Is this normal behavior?
Posted
by PBK.
Last updated
.