I tried to create a new version to update an app to fix something for iOS 14. When I clicked on the + to add a version I got a pop up that was missing its content. It was just a pop up with the title "Agreement Update", an empty body, and then a blue "OK" button.
I figured there was an ajax error loading the message, but ok, I'll head over to Agreements and accept whatever new agreements there are...
... but that page just shows a spinner and never loads.
And the browser Console shows a bunch of 404s as it tries to dynamically load content.
[Error] Failed to load resource: the server responded with a status of 404 () (tidbits-popover.angular.min.js.map, line 0) https://appstoreconnect.apple.com/agreements/scripts/npm/tidbits-popover.angular.min.js.map
[Error] Failed to load resource: the server responded with a status of 404 () (detail, line 0) https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/ra/user/detail
[Error] Failed to load resource: the server responded with a status of 404 () (ref, line 0) https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ref
It's really important for us to be able to submit app updates now that iOS 14 is available and users are starting to uncover issues that we weren't able to catch in our testing.
Post
Replies
Boosts
Views
Activity
Since the release of iOS 14, I keep getting reports of this crash via Crashlytics and I have no idea how to figure out what is going wrong, because the stack trace doesn't touch my code anywhere. What can I do? How do I find the source of the problem?
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000004
Crashed: com.apple.root.user-initiated-qos
0	CoreData											 0x1b85a87ac _PFObjectIDFastHash64 + 40
1	CoreFoundation								 0x1b254e4f8 __CFBasicHashRehash + 992
2	CoreFoundation								 0x1b2552414 CFBasicHashRemoveValue + 2384
3	CoreFoundation								 0x1b2469ec0 CFDictionaryRemoveValue + 236
4	CoreData											 0x1b84f51c0 -[NSManagedObjectContext(_NSInternalAdditions) _forgetObject:propagateToObjectStore:removeFromRegistry:] + 124
5	CoreData											 0x1b84d46ec -[_PFManagedObjectReferenceQueue _processReferenceQueue:] + 860
6	CoreData											 0x1b85a0734 -[_PFAutoreleasePoolThunk dealloc] + 48
7	libobjc.A.dylib								0x1c65bb81c AutoreleasePoolPage::releaseUntil(objc_object**) + 204
8	libobjc.A.dylib								0x1c65bb6e8 objc_autoreleasePoolPop + 212
9	libdispatch.dylib							0x1b2120aa4 _dispatch_last_resort_autorelease_pool_pop + 44
10 libdispatch.dylib							0x1b21313c8 _dispatch_root_queue_drain + 1064
11 libdispatch.dylib							0x1b21318e8 _dispatch_worker_thread2 + 116
12 libsystem_pthread.dylib				0x1f9a748cc _pthread_wqthread + 216
13 libsystem_pthread.dylib				0x1f9a7b77c start_wqthread + 8
I'm using the App Store Server API to fetch information about in-app purchases/subscriptions. I'm able to fetch data successfully, but I can't seem to verify/decode the signed transactions that come back. (I know that I can split and base64 decode to get the payload, but I need to verify the the JWT to ensure the security.)
$signedTransactionJWT = $response['signedTransactions'][0];
$privateKeyText = file_get_contents('/private/key/from/appstoreconnect.p8');
$decodedTransactionPayload = JWT::decode($signedTransactionJWT, new Key($privateKeyText, 'ES256'));
but that gave me:
openssl_verify(): supplied key param cannot be coerced into a public key
I'm trying to figure out how to do this verification. The WWDC videos about it say that since Apple is using an x5c JWT header, that the token should be self-contained and verifiable without need for external resources. I've seen some other pages say that I need to fetch certificates or JWKS from Apple and use those, but a) that didn't work for me either, and b) again, I thought the x5c was supposed to make it internally verifiable.
Any help?
It's maddening. I just opened a file and now it's gone because I had the audacity to open another file. I've learned that I can double click the tab of the first file to make it a permanent tab... but, of course, I'll need to do that every time I ever open any file ever, and if I close that file and come back to it later I'm going to be constantly having to double click tabs just to make Xcode stop replacing my tabs for me.
It's nuts. It's driving me insane.
Please. Is there any way to just DISABLE the temporary tabs behavior? I don't find it helpful in any way and I find it to be destructive to my development workflows.
My app is a hybrid of ObjC and Swift as I have been converting it from ObjC to Swift a bit at a time. I need to integrate In-App Purchases now and I'd like to use StoreKit 2. However, when I have one of my Swift classes return a Product object, my ObjC classes don't seem to have access to the Product type and referring to it as an SKProduct type doesn't work either.
Is it possible to interact with the Store Kit 2 APIs from ObjC code? Or am I going to need to isolate all of the StoreKit2 stuff in my Swift code and communicate differently when it's time to communicate with my old ObjC code?
Thanks,
Kenny
I've been reading through the documents and I feel like each particular doc jumps over the piece of info that I need. It explains how to create a Sandbox Test User and I've done that. I did plenty of IAP work many years ago, but things have changed enough that it's not working as I expect. When I read the docs, I feel like I can't find the missing piece.
When I test in a simulator with Xcode, it does my IAP transactions in the Xcode environment. That makes sense.
https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox
This page says:
To run your app using your Sandbox Apple ID, build and run your app from Xcode.
But when I test on a physical device installing directly from Xcode, it also does my IAP transactions in the Xcode environment. I thought this would put me in the Sandbox environment, but it didn't. The initial purchase view controller didn't reference the Sandbox at all and the "You're All Set" alert shows Environment: Xcode.
When I put a test build into TestFlight and test using that version, my IAP transactions are happening in production using my real Apple Id (but I'm not actually charged for any transactions).
I assumed that testing in TestFlight would give me the Sandbox environment, but it happens in the Production environment. (The purchase view controller doesn't show Sandbox and the "You're All Set" alert doesn't show Sandbox.)
So, how do I test in the Sandbox? Every way I try to test either puts me in the Xcode environment or the Production Environment.
What am I missing?
I've logged out of my real Apple id on my phone and then logged in with the Sandbox User credentials I created in AppStore Connect. But when I tried to test the app, by installing from Xcode it still says I'm in the Xcode test environment. When I create transactions, those transactions show up in the Xcode Transaction Manager.
How do I test in the Sandbox environment?
I'm working on implementing the new StoreKit 2 api in my iOS app. I offer auto-renewing subscriptions to my users. I have lots of different product levels each that come with yearly or monthly charging options.
Let's say a user has a yearly auto-renewing subscription that is paid through April 2024. In Sept 2023, they decide to downgrade to a monthly product. Their yearly product stays in place until it expires and then when the subscription auto-renews in April 2024, it will renew as monthly instead.
How do I look up what product id they downgraded to? When I look in the renewalInfo struct, it will give me info on if they will renew, when they will renew, and it'll give me their currentProductId... but I need the next product id. The one that they downgraded to, the monthly one. When their subscription to the yearly product expires, they'll renew as a different (monthly) product.
if let status = try? await self.subscriptionProducts.first?.subscription?.status.first {
if let renewalInfo = try? self.checkVerified(status.renewalInfo) {
// ...
}
}
I can't figure out how to access that info so that I can properly present the info in their Account screen. If my users were on a yearly product and last week they chose to downgrade to a monthly product, I need to show them that they are finishing their yearly sub and will auto-renew as monthly. I can't just show them that they are on the yearly sub, because they'll get confused because they know they downgraded to monthly.
I'm trying to test my IAP subscriptions. Testing in the Sandbox environment has been kind of a nightmare, because it sometimes returns out of date information on the phone and the server events are either never delivered or delivered very late, etc. It makes testing nigh impossible.
So I'm trying to test via TestFlight, because that is, at least, working in the production environment and delivers events more quickly and seems to return the correct data when I query the StoreKit2 APIs.
However, it's using my REAL Apple Id for the purchases (no charges though), and after it has auto-renewed my subscription 12 times... then it NEVER will auto-renew ever again (as far as I can tell). Even if I resubscribe, the subscription immediately dies at the end of that period.
It's making testing impossible again... and I can't find a way to clear TestFlight purchases similar to the way I can clear purchases for Sandbox users.
At this point, I have -no- confidence that my Apple IAP Subscriptions are going to work correctly and I don't seem to have a way that I can test them properly in order to gain that confidence.
Is there any way to clear purchases in TestFlight or any way to allow more than 12 renewals in TestFlight?
A handful of my customers have reported a consistent freeze in my app (smells like either a thread deadlock or an infinite recursion to me). It's working properly for most people, but if 3 people are reporting it to me that says to me that probably 300 are experiencing it but staying quiet.
It happens every time they take a certain kind of action. But it never happens to me so I can't figure out what is breaking.
No crash is happening, so I'm not getting any reports via Firebase.
It doesn't appear to be related to their data, because they can have someone else use a different device, login to their account, download all of their data, and then successfully do the thing that freezes 100% of the time on their original device.
I've got one of these customers set up on TestFlight so I can send them test versions of the app with some debug collection code. I created my own version of a tracelog and write a line to a file whenever I start/end a function. I've added those tracelog calls to a bunch of methods and classes (but not all).
The action that causes the freeze is when they tap Edit on a record. What's supposed to happen is that I modally present a nav controller containing an EditBlahViewController.
The trace logs show that the EditBlahViewController gets through viewDidLoad, viewWillAppear, two rounds of viewWillLayoutSubviews/viewDidLayoutSubviews... but then never gets to viewDidAppear.
I've tried updating more and more functions/classes with the tracelog calls, but I can't find any infinite recursions. I've added tracelogs to all calls involving dispatching to other threads (especially synchronous dispatches to the main thread) but I don't see any deadlocks. Every dispatch to main starts and ends properly and then goes on to the next thing.
User is on iOS 16.6.1 with an iPhone 12.
I don't know what else to try. How can I debug this at a distance and figure out where the problem is?
I have a SwiftData object called Asset. Asset has an optional relationship to another SwiftData object called Income. Income has an Int? called cashflow.
AssetsListView shows a list of assets and has a + button to create an asset object and show the AddEditAssetView where the user can fill in the values on the asset.
The newly added asset is a @State variable in AssetsListView.
That asset is a @Binding in AddEditAssetView.
In AddEditAssetView, I use a custom view called MoneyTextField which is just a simple wrapper around a standard TextField but it does some customized formatting and such.
One of these MoneyTextFields that I'm showing is so the user can edit the cashflow amount which is found in $asset.income.cashflow.
MoneyTextField("placeholder text", value: $asset.income.cashflow)
// inside MoneyTextField, value is: @Binding var value: Int?
But since all relationships in SwiftData need to be optional, $asset.income is a Income? and so I get the understandable error:
Value of optional type 'Income?' must be unwrapped to refer to member 'cashflow' of wrapped base type 'Income'
But if I change it to:
MoneyTextField("placeholder text", value: $asset.income?.cashflow)
I get the error:
Cannot use optional chaining on non-optional value of type 'Binding<Income?>'
When $asset is my @Binding, how do I pass $mybinding.property.otherproperty as a binding to a subview?
I'm a long time ObjC app dev, new-ish to swift and brand new to swiftui, so I'm kind of lost. Is there a simple way to do what I'm doing or is my entire approach wrong because I'm not thinking in a proper swiftui mind yet?
More code for context:
struct AssetsView: View {
@State var addedasset: Asset?
// more stuff
var body: some View {
NavigationStack {
List {
MoreStuff()
}
.toolbar {
ToolbarItem {
Button {
let asset = Asset(name: "", assetType: .realestate)
self.addedasset = asset
self.modelContext.insert(asset)
} label: {
Image(systemName: "plus")
}
.fullScreenCover(isPresented: $showingaddscreen) {
AddEditAssetView(player: $player, asset: $addedasset)
}
}
}
}
}
}
struct AddEditAssetView: View {
@Binding var asset: Asset
var body: some View {
NavigationStack {
Form {
OtherStuff()
// here's where the compile error is
MoneyTextField(localizedstringkey: "realestate_cashflow_eg", value: $asset.income?.cashflow)
}
}
}
}
struct MoneyTextField: View {
var localizedstringkey: LocalizedStringKey
@Binding var value: Int?
@State var valuestring = ""
var body: some View {
TextField(localizedstringkey, text: $valuestring)
.textFieldStyle(.roundedBorder)
.keyboardType(.numberPad)
.onReceive(Just(valuestring), perform: { foo in
print("onReceive: foo | \(String(describing: foo))")
updatevalueint(valstring: foo)
})
.onAppear {
if let intval = self.value {
updatevaluestring(val: intval)
}
}
}
}