Hello,
my indie app has somewhat significant traction in China (both downloads and subscription purchases), but I also have high refund rate there, like multiples of other countries... Perhaps even as 80 % or more of my refunds are in China although the share of downloads and purchases is way lower.
I am curious if someone else also has this issue?
My app has the "Blinkist trial" onboarding which shows the timeline and has notification on day 5 (for weekly trial), that paid subscription starts soon. However even after stopping showing this onboarding in China for new users I still have most of my refunds from China.
I am trying to understand whether this may be broader "phenomenon" or maybe something super specific to my app. As far as I know Apple doesn't share the refund request reasons with developers and I did not get any support emails that would hint at why people are asking for refund.
Thanks!
Since Apple can terminate your developer account if you have "high" refund rate, I would like to get to the bottom of this.
Post
Replies
Boosts
Views
Activity
Hello,
we have weird crash in our app that mostly seems to happen right after launch. It is quite rare and so far I haven’t been able to reproduce it (the info below comes from Crashlytics).
The main error message I have is this:
failed to demangle witness for associated type 'Property' in conformance 'SwiftUI.StateObject<AppBlock.QuickBlockActivityViewModel>.(unknown context at $18f34e5b8).Box: DynamicPropertyBox' from mangled name ' � ��yxG' - subject type x does not conform to protocol ObservableObject
And here is the stack trace:
Crashed: com.apple.main-thread
0 libsystem_kernel.dylib 0x7200 __pthread_kill + 8
1 libsystem_pthread.dylib 0x71ac pthread_kill + 268
2 libsystem_c.dylib 0x20ca0 abort + 180
3 libswiftCore.dylib 0x3d7304 swift::fatalError(unsigned int, char const*, ...) + 134
4 libswiftCore.dylib 0x3d7324 swift::warningv(unsigned int, char const*, char*) + 30
5 libswiftCore.dylib 0x3ee678 swift_getAssociatedConformanceWitnessSlowImpl(swift::TargetWitnessTable<swift::InProcess>*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::InProcess> const*) + 2078
6 libswiftCore.dylib 0x3ecb9c swift_getAssociatedTypeWitness + 236
7 SwiftUI 0x5b838 OUTLINED_FUNCTION_49 + 640
8 SwiftUI 0xa8d68 OUTLINED_FUNCTION_513 + 16260
9 SwiftUI 0x58244 OUTLINED_FUNCTION_177 + 10892
10 SwiftUI 0x95524 OUTLINED_FUNCTION_1160 + 6632
We are using the view model (QuickBlockActivityViewModel) in a SwiftUI view that is part of collection view using the new UIHostingConfiguration from iOS 16.
Our view model is a subclass of view model for older iOS versions that conforms to ObservableObject and is marked as @MainActor.
And the view model is used like this:
@StateObject private var viewModel = QuickBlockActivityViewModel()
Internally the view model uses Combine to monitor a couple of states from other parts of the app to modify its properties.
Hello,
I have collection view with context menu using contextMenuConfigurationForItemAt and I wanted to customize the preview, when user long presses and context menu is shown. Something maybe like in the Music app when you long press on an album it shows the album in bigger size...
I found some snippets online for highlightPreviewForItemAt and dismissalPreviewForItemAt but it just doesn't work. As soon as a implemented these delegate methods, nothing happens when I long press, not even the standard preview with context menu.
These two methods aren't being called at all. Do I need to do something else? Do I need the previewProvider when creating the context menu? It is my understanding that that is needed only when the item should also open further detail on tap - which is something I don't need and want.
Below is my relevant implementation:
private func shareMenuConfiguration(for itemAt: URL, indexPath: IndexPath) -> UIContextMenuConfiguration {
let share = UIAction(title: "Share".localized(), image: UIImage(systemName: "square.and.arrow.up")) { [unowned self] _ in
let shareVC = UIActivityViewController(activityItems: [itemAt], applicationActivities: nil)
if let cell = collectionView.cellForItem(at: indexPath) {
shareVC.popoverPresentationController?.sourceView = cell.contentView
shareVC.popoverPresentationController?.sourceRect = cell.contentView.bounds
}
self.present(shareVC, animated: true)
}
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
UIMenu(title: "", children: [share])
}
}
func collectionView(_ collectionView: UICollectionView, contextMenuConfiguration configuration: UIContextMenuConfiguration, highlightPreviewForItemAt indexPath: IndexPath) -> UITargetedPreview? {
guard let item = datasource.itemIdentifier(for: indexPath), let cell = collectionView.cellForItem(at: indexPath) as? GalleryImageCell else {
return nil
}
let parameters = UIPreviewParameters()
let visibleRect = cell.contentView.bounds.insetBy(dx: 1/3, dy: 1/3)
let visiblePath = UIBezierPath(roundedRect: visibleRect, cornerRadius: 4)
parameters.visiblePath = visiblePath
return UITargetedPreview(
view: cell.contentView,
parameters: parameters,
target: .init(container: collectionView, center: collectionView.convert(cell.contentView.center, from: cell.contentView))
)
}
func collectionView(_ collectionView: UICollectionView, contextMenuConfiguration configuration: UIContextMenuConfiguration, dismissalPreviewForItemAt indexPath: IndexPath) -> UITargetedPreview? {
guard let item = datasource.itemIdentifier(for: indexPath), let cell = collectionView.cellForItem(at: indexPath) as? GalleryImageCell else {
return nil
}
let parameters = UIPreviewParameters()
let visibleRect = cell.contentView.bounds.insetBy(dx: 1/3, dy: 1/3)
let visiblePath = UIBezierPath(roundedRect: visibleRect, cornerRadius: 4)
parameters.visiblePath = visiblePath
return UITargetedPreview(
view: cell.contentView,
parameters: parameters,
target: .init(container: collectionView, center: collectionView.convert(cell.contentView.center, from: cell.contentView))
)
}
Thanks!
Hello,
my app sometimes has this super weird issue with scroll in a horizontal section (see the GIF below). The thing is, I have ever spotted it only in this third section and not the two sections above it.
All have the same compositional collection view layout and are powered by the diffable data source. I reexamined the item definition and I don't think this could be a case of hash values being same and hence confusing the collection view.
It also seems to happen only to these first items. It is not frequent but on my own device I have seen it many times so far. The problem always seems to manifest in similar manner.
Anyone seen this? I am hoping that maybe someone will recognize the problem from the GIF.
Hello,
I submitted my trader information in March 2024 for the Digital Services Act. Last Friday I got App Store Connect email saying that my info couldn't be verified and that I need to resubmit otherwise my apps won't be available in the EU in 14 days.
This is quite scary, I don't want to have my apps removed but I cannot resubmit either. In ASC Business section I see "In Review" as the status for my Digital Services Act compliance so it seems there is nothing I can do.
Contacted developer support on Monday but haven't heard back.
Anyone with the similar situation who can offer any advice?
Hello,
I am looking into the newly announced Accessory Setup Kit and I'd like to replace my manual WiFi connection setup with it, but I cannot find a way how to specify WiFi password when configuring ASDiscoveryDescriptor, only ssid or ssidPrefix can be specified?
Is it really not possible to connect to WiFi with password with this new framework? That kind of makes it unusable for my use case :( Since the accessory has password.
Hello,
I have the following subclass of UICompositionalCollectionViewLayout to get the stretchy header effect as shown below.
It works quite well, but I don't really have an experience with creating custom layouts so I thought I'd ask if maybe my implementation doesn't have some important flaws.
I once ran into persistent layout loop crash with this and I am not sure what exactly I changed but it stopped happening. However since I am using this layout on important screen, I would like to make sure there isn't obvious potential for the layout loop crash happening in App Store version.
I am particularly unsure about the shouldInvalidateLayout implementation. Originally I was returning true all the time, but decided to change it and only force invalidation for negative content offset which is when my header is supposed to stretch.
Here is the full code:
final class StretchyCompositionalLayout: UICollectionViewCompositionalLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attrs = super.layoutAttributesForElements(in: rect) ?? []
guard let collectionView = collectionView else {
return attrs
}
let contentOffset = collectionView.contentOffset.y
guard contentOffset < 0 else {
return attrs
}
var newAttributes: UICollectionViewLayoutAttributes?
attrs.forEach({ attribute in
if attribute.indexPath.section == 0 && attribute.indexPath.item == 0 {
let startFrame = attribute.frame
newAttributes = attribute.copy() as? UICollectionViewLayoutAttributes
let newFrame: CGRect = .init(x: 0, y: contentOffset, width: startFrame.width, height: startFrame.height - contentOffset)
newAttributes?.frame = newFrame
}
})
if let new = newAttributes {
attrs.removeAll { attr in
return attr.indexPath.section == 0 && attr.indexPath.item == 0
}
attrs.insert(new, at: 0)
}
return attrs
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = super.layoutAttributesForItem(at: indexPath) else {
return nil
}
let contentOffset = collectionView?.contentOffset.y ?? 1
guard contentOffset < 0 else {
return attributes
}
if indexPath.section == 0 && indexPath.item == 0 {
let attributes = attributes.copy() as? UICollectionViewLayoutAttributes ?? attributes
let startFrame = attributes.frame
let newFrame: CGRect = .init(x: 0, y: contentOffset, width: startFrame.width, height: startFrame.height - contentOffset)
attributes.frame = newFrame
return attributes
} else {
return super.layoutAttributesForItem(at: indexPath)
}
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
let contentOffset = collectionView?.contentOffset.y ?? 1
// There is visual glitch when 0 is used in this condition
if contentOffset < 1 {
return true
} else {
return super.shouldInvalidateLayout(forBoundsChange: newBounds)
}
}
}
Any feedback welcome!
Hello,
we have rare case of AuthorizationCenter.shared.requestAuthorization(for: .individual) failing to autorize user on real device - iPhone XR (iOS 16.1.2).
It does not throw the standard FamilyControlsError which we are handling, but NSCocoaErrorDomain.
This is the entire po description:
Error Domain=NSCocoaErrorDomain Code=4864 "The given data was not a valid property list." UserInfo={NSCodingPath=(), NSDebugDescription=The given data was not a valid property list., NSUnderlyingError=0x283af4d80 {Error Domain=NSCocoaErrorDomain Code=3840 "Cannot parse a NULL or zero-length data" UserInfo={NSDebugDescription=Cannot parse a NULL or zero-length data}}}
The localized one says:
"The data couldn’t be read because it isn’t in the correct format."
This sounds like some error deep in iOS. The testing device has Apple ID logged in and uses passcode.
Anything we can do on our end to solve this issue?
Hello,
I have this widget:
And as you can see down at the bottom, next item is very barely visible. This is because on different devices (combined with varied text sizes + number of lines) the vertical space differs quite a lot.
In the past I had the limit set to 4 items in the bottom part but that often left empty space at the bottom or even overflowed still on iPhone SE.
What is the proper way to tell ForEach (or any other component) to "layout as many items as can fully fit, but no more".
The only solution I could think of is to use ViewThatFits and try first rendering 6 items, then 5 and so on to find the count that fully fits. But that seems maybe too complicated?
Thanks.
Please delete this, I made wrong conclussions. The issue wasn't with UISearchController as it is happening on other screens also where I dont even use the seach.
Hello,
we had working DeviceActivityReport in our app for months now. However when building with Xcode 15 (previously betas, now the GM), the activity reports no longer displays anything on iOS 16 devices.
If we run it with Xcode 14, it works. But with Xcode 15 builds, the device activity report only works on iOS 17 devices :(
I am able to see some somewhat generic errors in the Console.app when opening screen that contains the report.
-[_EXServiceClient launchWithConfiguration:error:]_block_invoke failed with error: Error Domain=com.apple.extensionKit.errorDomain Code=2 UserInfo={NSUnderlyingError=0x280b9b600 {Error Domain=RBSRequestErrorDomain Code=5 UserInfo={NSLocalizedFailureReason=<private>}}}
Failed to create extensionProcess for extension '<private>' error: Error Domain=com.apple.extensionKit.errorDomain Code=2 UserInfo={NSUnderlyingError=0x280b9b600 {Error Domain=RBSRequestErrorDomain Code=5 UserInfo={NSLocalizedFailureReason=<private>}}}.
Failed to make extensionProcess with error: Error Domain=com.apple.extensionKit.errorDomain Code=2 UserInfo={NSUnderlyingError=0x280b9b600 {Error Domain=RBSRequestErrorDomain Code=5 UserInfo={NSLocalizedFailureReason=<private>}}}
Failed to get extension process and XPC endpoints with error: Error Domain=com.apple.extensionKit.errorDomain Code=2 UserInfo={NSUnderlyingError=0x280b9b600 {Error Domain=RBSRequestErrorDomain Code=5 UserInfo={NSLocalizedFailureReason=<private>}}}
And I managed to find one error that is specific to our activity extension which says just: Cannot track instance that is already dead!
Hello,
I am curious if someone else also noticed this. We have started getting reports about our app not working correctly (mostly related to the Device Activity monitor that "runs" in the background, https://developer.apple.com/documentation/deviceactivity/deviceactivitymonitor).
Upon checking the Xcode Organizer I can see somewhat significant amount of crashes that mostly appear to happen on iOS 16.6 - it is possible that our users don't wait with updating iOS but still looks suspicious.
The crashes are related to ManagedSettings calls outside our own code.
We haven't changes this code in a while so this coupled with the fact that these crashes happen "deep" in the ManagedSettings framework leads me to believe there is some other issue.
Hello!
I am playing around with the PHPickerViewController and so far I was able to get the selected images by loading them into UIImage instances but I don't know how to get the selected video.
Below is the relevant implementation of the method: func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]):
let provider = result.itemProvider
guard provider.hasItemConformingToTypeIdentifier(AVFileType.mov.rawValue) else { return }
						provider.loadItem(forTypeIdentifier: AVFileType.mov.rawValue, options: nil) { (fileURL, error) in
								if let error = error {
										print(error)
										return
								}
								guard let videoURL = fileURL as? URL else { return }
								DispatchQueue.main.async {
										let fm = FileManager.default
										let destination = fm.temporaryDirectory.appendingPathComponent("video123.mov")
										try! fm.copyItem(at: videoURL, to: destination)
										let playerVC = AVPlayerViewController()
										playerVC.player = AVPlayer(url: destination)
										self.present(playerVC, animated: true, completion: nil)
								}
						}
I get crash trying to copy the item. It says the source file does not exists but the path looks real to me.
"The file “3C2BCCBC-4474-491B-90C2-93DF848AADF5.mov” couldn’t be opened because there is no such file." I tried it without copying first and just passing the URL to AVPlayer but nothing would play.
I am testing this on a simulator.
Thanks for help!
Hello,
I am building contact form that allows to attach screenshots and screen recordings. The PhotosPicker part is relatively straightforward but I am not sure how to properly import the selected items.
The binding is of type [PhotosPickerItem] which requires (at least for my current implementation) to first know if the item is image or video.
I have this not so pretty code to detect if the item is video:
let isVideo = item.supportedContentTypes.first(where: { $0.conforms(to: .video) }) != nil || item.supportedContentTypes.contains(.mpeg4Movie)
Which for screen recordings seems to work only because I ask about .mpeg4Movie and then I have this struct:
struct ScreenRecording: Transferable {
let url: URL
static var transferRepresentation: some TransferRepresentation {
FileRepresentation(contentType: .mpeg4Movie) { video in
SentTransferredFile(video.url)
} importing: { received in
let copy = URL.temporaryDirectory.appending(path: "\(UUID().uuidString).mp4")
try FileManager.default.copyItem(at: received.file, to: copy)
return Self.init(url: copy)
}
}
}
Notice here I have just the .mpeg4Movie content type, I couldn't get it to work with more generic ones like movie and I am afraid this implementation could soon break if the screen recordings change video format/codec.
And finally my logic to load the item:
if isVideo {
if let movie = try? await item.loadTransferable(type: ScreenRecording.self) {
viewModel.addVideoAttachment(movie)
}
} else {
if let data = try? await item.loadTransferable(type: Data.self) {
if let uiImage = UIImage(data: data) {
viewModel.addScreenshotAttachment(uiImage)
}
}
}
I would like to make this more "future proof" and less error prone - particularly the screen recordings part.
I don't even need the UIImage since I am saving the attachments as files, I just need to know if the attachment is screenshot or video and get its URL.
Thanks!
Hello,
I initially started the discussion over at Swift Forums - https://forums.swift.org/t/issue-with-connect-proxy-some-connections-dont-work-probably-sockets/45575 because I am using SwiftNIO but it appears that it makes more sense here.
I have an app with NetworkExtension of the packet tunnel provider type. So I am using the NEPacketTunnelProvider. As part of the extension, I have SwiftNIO server with connect proxy which is used to route the traffic.
This works great in almost all cases, but apps like Signal or WhatsApp don't work. They don't display any kind of "no connection" indicator but the messages aren't send or received.
Over at Swift Forums I got an answer from Quinn “The Eskimo!” that I think points to the actual problem:
My experience is that a lot of these ‘chat’ apps explicitly bind their
connections to the WWAN interface, which means they don’t use the
default route and thus aren’t seen by the packet tunnel provider.
My packet tunnel provider is configured to use the default routes for IP4 and IP6.
So my concern is how to configure it, that it works also for the chat apps? There are couple of apps from the App Store that I tried which use this same approach and while they are active, Signal works fine.
Yes, I know this solution is not ideal and not the main intended usecase for packet tunnel, but it is the only option available on iOS..
Thanks for help! Happy to clarify further.