App name: WF Favorites Watch (hidden on App Store)
Environment:
Independent, autonomous Watch only app
No VPN
Solid WiFi and connection from iPhone to Watch
Installed version:
Released version with approved subscription
App previously installed on watch as Free app or one-time-purchase
App Store on iPhone shows grayed out "Purchased" button
Situation created with latest release:
Business model change from free or purchased to IAP subscription
In-app subscription works correctly
Attempting to redeem offer code on iPhone App Store
An offer code is available but does not work
Issue:
The code entry page appears
Correct offer code does not install app
Screenshot shows constant spinner
Spinner eventually returns to download icon
To reproduce
App must be installed as a "purchased" app shown on iPhone App Store
Navigate to: https://apps.apple.com/redeem?ctx=offercodes&id=6451388967&code=CODE
Enter the Offer Code
App is never installed on watch
I wonder if the "Purchased" state of the app on the iPhone App Store page is somehow preventing the iPhone App Store from installing the new version as a subscription using the offer code.
I have tried with the app on the watch. I tried to uninstall the app from watch and then redeem the code. I tried deleting and reinstalling the app on the watch. No configuration allows the redeem code to ever install the app.
I attempted to remove the app from the iPhone App Store. I am unable to, I presume, because it is not an iPhone app.(?)
What can I do to resolve this?
Post
Replies
Boosts
Views
Activity
This is the first subscription submission for this existing/distributed app.
This is the rejection message:
Specifically, your app did not load any subscription offers at launch and no further content could be accessed.
The app works correctly in simulator, on device and TestFlight. I am using a sync'd StoreKit configuration file.
The app has no functionality at all without the subscription being available to the app. It seems the app is being tested independently of the subscription upon first launch. Or said differently, the app is being tested without a subscription being available because the subscription has not been approved and available at the time the app is first launched for testing.
It seems the reviewers aren't making the subscription available at the time of launching the app for testing as is the case in XCode, on device and within TestFlight - the subscription is always available in those environs.
Is my analysis correct, close, a mile off or ...?
Thanks for your help and insight.
Plenty of info on test IAPs in xCode. I need to test whether the user has previously purchased the product in order to adjust my business model from a paid app to an in-app-purchased subscription.
I have implemented the code from "What's New in StoreKit" found at https://developer.apple.com/wwdc22/10007?time=527 and this works. but I don't know how to create a mock purchase that I can use to validate a previous purchase. This means I have no way of testing if the code actually works with a previous purchase in place.
My question is specifically: How do I create a mock/test "purchased product" that I can use in testing this functionality?
For clarity, I have successfully test IAP IAW: https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode/
Thanks
Target: WatchOS 10.5
NOTE: This is a watchOS only app
Given:
A single view containing NavigationSplitview, with the List in the "sidebar", a TabView in the "detail" and a TabView in a sheet attached to each tab in the "detail" view.
When:
Navigating between top-level list and "detail" TabView, or navigating through "detail" to "sheet" TabView
Then:
Memory leaks occur.
If the TabView() views are replaced with List() views there are no longer memory leaks.
There are no reference types involved. Everything is in Structs
Code below causes the issue which can be observed in Instruments.
So my question is what have I coded incorrectly to cause this issue? Or, How can I fix this?
Thanks in advance.
@main
struct VerticalTabView_MemLeak: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
struct ParentItem: Identifiable, Hashable {
var id = UUID()
var name: String
var children: [Item]
init(_ name: String, _ children: [Item]){
self.name = name
self.children = children
}
}
struct Item: Identifiable, Hashable {
var id: UUID = UUID()
var name: String
init(_ name: String){ self.name = name }
}
@State var selectedParentItem: ParentItem?
@State var selectedItem: Item?
var parentItems = [
ParentItem("A", [Item("one"),Item("two"),Item("three")]),
ParentItem("B", [Item("four"),Item("five"),Item("six")]),
ParentItem("C", [Item("seven"),Item("eight"),Item("nine")])
]
var body: some View {
NavigationSplitView {
List(selection: $selectedParentItem) {
ForEach(parentItems, id: \.id) { parentItem in
NavigationLink(value: parentItem) {
HStack {
Text(parentItem.name)
}
.padding()
}
}
}
.navigationTitle("Top Level")
} detail: {
if let items = selectedParentItem?.children {
TabView(selection: $selectedItem) {
ForEach(items, id:\.id) { item in
Text(verbatim: item.name)
.tag(item)
.onTapGesture {
selectedItem = item
}
}
}
.tabViewStyle(.verticalPage)
.navigationTitle(selectedParentItem?.name ?? "")
.sheet(item: $selectedItem,
onDismiss: { selectedItem = nil },
content: { item in
TabView {
Text(item.name).foregroundStyle(.yellow)
Text(item.name).foregroundStyle(.yellow)
}
.tabViewStyle(.verticalPage)
.navigationTitle(selectedParentItem?.name ?? "")
})
}
}
}
}
#Preview {
ContentView()
}
REF: TN3135
Context:
Stand alone watch app
Target platform is cellular watch
Phone likely (90%) out of range in a different location (although this applies equally to watch+phone too)
User story:
As a water & wind sports enthusiast who is either in-shore, near-shore or off-shore
I want to receive near-real-time wind reports on my wrist
so that I can determine ...(many varieties of facts)
My Case for lifting restrictions on NWPathMonitor, NWPath, NWPath.Status
What this is about:
Proactive UX (enlightening) vs. Reactive UX (disappointing)
Reducing unnecessary code execution proactively
Exactly the same purpose the tiny red x at the top center of the Watch screen serves (notifies me that the watch is offline -- probably using NWPath.Status of .unsatisfied)
What this is NOT about
Preflighting requests
UI design (although there is a UI component associated with UX - like the tiny red x ...)
Establishing low level connections
Watch App End User Scenario
Water & Wind sports enthusiasts are frequently in and out of cellular range.
As a kiteboarding enthusiast I am relating my personal experience. The phone is in the vehicle in the parking lot > 100 yards away while I'm standing on the beach (before I get into the water).
On shore or just off shore my watch likely has a solid connection. When 100 yards off shore watch has a decently but tenuous connection. While at 200 yards off shore watch has no connection at all.
Developer's Case
Current REACTIVE solution
My current watch app is forced to be reactive by attempting a URLSession request and capturing one of the plethora of URLError error conditions.
This action, of course, is activated through a user interaction workflow:
User interaction --> create URL --> use URLSession --> capture URLError --> determine failure cause --> notify user network data cannot be retrieved
Optimal PROACTIVE solution
Provide a simple indicator to the end user that the data cannot be retrieved. The reason is not relevant to the end user, but they know their interaction with the app is unnecessary. The app's UX has been improved by proactively precluding an unnecessary interaction and precluding unecessary code execution behind the scenes.
NWPath.Status = .unsatisfied --> UI shows "no network" type indicator --> (no user interaction - no backend requests - no code execution) --> NWPath.Status = .satisfied --> UI shows nominal status --> end user interacts normally
Rationale
Using NWPath.Status allows us as developers to fulfill some basic tenets of the Human Interface Guidelines associated with Providing Feedback
Specifically, the overview states we should communicate:
The current status of something
A warning about an action that can have negative consequences
And quoting about my specific use case, the guidelines continue:
... it often works well to display status information in a passive way so that people can view it when they need it.
Consider integrating status feedback into your interface.
Show people when a command can’t be carried out and help them understand why.
And finally, the guideline specifically calls out the WatchOS experience I am attempting to avoid. By proactively providing feedback we can prevent the reactive "touch --> wait & see --> then disappoint with no connection" approach.
Final Thoughts
I realize I am naive about the behind the scenes with this API. I realize that this is likely not the intended use of this API. But as a developer, I also realize users of our stuff often use it in ways we never intended.
Please allow these API features on WatchOS
First issue - this is an autonomous WatchOS app. So I'm unsure about the error about installing on iPhone,
Second issue is the typo at the end of the statement ("v"). The message is so very generic and errored I have no idea what to correct.
What I need help with:
Following the link provided and looking under "Discussion" one finds:
For a list of the features that different devices support, see Required Device Capabilities.
When you follow that link, one only finds settings for Vision, iPhone, iPad, and IPod Touch.
What required settings am I missing? What do I need to register as UIReqiuredDeviceCapabilities specifically for an autonomous WatchOS app?
My guess is I have some build setting(s) wrong even though this is built from the WatchOS app template.
How do I troubleshoot this to track down what I've done incorrectly?
Any help is appreciated.
This is the rejection message:
Guideline 2.3 - Performance - Accurate Metadata
We were unable to install the app on iPhone. The UIRequiredDeviceCapabilities key i> n the Info.plist is set in such a way that the app will not install on v .
Next Steps
To resolve this issue, please check the UIRequiredDeviceCapabilities key to verify that it contains only the attributes required for your app features or the attributes that must not be present on the device. Attributes specified by a dictionary should be set to true if they are required and false if they must not be present on the device.
Resources
Learn more about the UIRequiredDeviceCapabilities key.