Since XCode 15, we can't get our app in the app store no more. While uploading, we get the message: "Entitlement com.apple.developer.playable-content is missing".
The entitlement is for CarPlay and it worked for years -we did not change anything.Now with XCode 15, we had to remove CarPlay completely, otherwise we wouldn't get the app in the App Store no more.
General
RSS for tagDelve into the world of built-in app and system services available to developers. Discuss leveraging these services to enhance your app's functionality and user experience.
Post
Replies
Boosts
Views
Activity
I have experienced a strange issue on my iphone test device. (iPhone Xr running iOS 17.0.3)
In my app I ask a user for calendar full access. Once I gave the access permission, the app works as expected. Then somehow the status changed from .fullAccess to .denied. This happens without my interaction in iPhone's Settings. I have doubled checked in Settings app and the permission is still granted. But somehow the status is denied when calling EKEventStore.authorizationStatus(for: .reminder)
Regardless of how bad my code is, the app should not be able to change status from .fullAccess to .denied. Correct?
I have never had this problem until lately. But it happens to both my iOS app and my mac Catalyst app. Which is really strange. (iOS 17.0.3 and Sonoma 14.0)
This problem doesn't happen all the time though. Most of the time my app works fine. But it can happen few times per day. And even more strange, it tends to happen at the same time for iOS and macOS.
I don't know if this problem happens to me because of the fact that I install/uninstall the app many times but currently it just causes me a headache.
I have attached 2 images. These 2 images happen at the same time. The only fix is that I have to turn off then turn on the Full Access again in Settings app. Something for Reminder.
Any advice is much appreciated. Thank you.
This is a tricky one. I have a shipping product which, when compiled under Xcode 14.3.1 works as expected on Sonoma.
If the same project is recompiled with Xcode 15, the subclass of NSTextView will not display correctly (text is same color as background).
I am also using a custom NSLayoutManager (to draw invisibles).
Unfortunately, there is an intermittent aspect to this. I use this subclass in several places and it works on my setup on the main editor, but not with some customers.
Then I found a different use of the same subclass that does not work for me.
When it does not work, it is consistent for that user.
I have manually marked the textViews as using TextKit 1, with no change.
I also tried the Clips Bounds to yes, again no change.
If I change the class to NSTextView, the text displays properly, but I lose existing functionality.
There appears to be some undocumented behavior change in Xcode 15 (or when linking against Sonoma SDK) that for subclasses of NSTextView (stored in XIB files). I know that there is a push to move toward TextKit 2, but it seems TextKit 1 support was possibly changed as well.
The text is there and I can edit it, double click, copy and paste it, it is just invisible, when compiled with Xcode 15 (also 15.1).
It has to be something very subtle that the subclassed TextView from one XIB will work, but from another XIB will not.
Does anyone have any insight into the potential change with TextKit 1 implementation?
Thanks.
Ok, weird one here. I have a widgetkit watch extension that I'm transitioning to. All code compiles clean, but when I go to install I get an error that it can't be installed on the watch because the extension does not define either a NSExtensionMainStoryboard or an NSExtensionPrincipalClass key. I don't have a storyboard for the extension as it's for the complications, so I added a principal class key.
Now it won't install with the error that it defines a principal class which is not allowed for the extension point com.apple.widgetkit-extension.
Huh. Well, ok, um... I guess I'll rip it out and stay with the deprecated clock kit complications, since they at least install. But this is very frustrating, and makes me think Apple wants us to go insane!
According to upcoming privacy manifest document, NSUserDefaults is only allowed for a use for the app itself.
It is serious for developers who makes App Extensions.
https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
CA92.1
Declare this reason to access user defaults to read and write information that is only accessible to the app itself.
This reason does not permit reading information that was written by other apps or the system, or writing information that can be accessed by other apps.
Developers, please submit a request to add the permission of App Group.
https://developer.apple.com/contact/request/privacy-manifest-reason/
let formatter = DateIntervalFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .none
formatter.dateTemplate = "EEEjm"
Produces, in my locale and on my device with 24 hour time on:
"Tue, 6:39 – 7:10 pm"
I was expecting:
"Tue, 18:39 – 19:10"
Other date formatters are showing 24 hour time using the j symbol. For example:
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .none
formatter.setLocalizedDateFormatFromTemplate("EEEjm")
Produces, for the start and end dates:
Tue 18:39
Tue 19:10
Further, NSDateIntervalFormatter.h suggests I should be able to use symbols like j.
So why can't I create strings in 24 hour time with DateIntervalFormatter?
Thanks for your time.
iOS 16.7.1 / Xcode 15
Hi,
I was using NFCNDEFReaderSessionDelegate at first to read and write the cards, but didDetect tags method did not detect any tag because my nfc tag is not pre-formatted, it was calling other delegate methods so I have my NFCNDEFReaderSessionDelegate setup correctly. Hence, I used NFCTagReaderSessionDelegate, didDetect tags method of NFCTagReaderSessionDelegate detected tag and the tag was not pre-formatted. The issue I have been facing is I am not able to write for the first time and getting an error
Error Domain=NFCError Code=102 "Tag Not NDEF formatted" UserInfo={NSLocalizedDescription=Tag Not NDEF formatted}.
When I used another app from apple store to write data on the same tag which is not pre-formatted. Using that app, I am able to write the data on that tag. That app was using CoreNFC framework I believe, as it has NFC session alert which seems it was from apple library CoreNFC, so I assume that there must be a way to write the data on unformatted nfc tags. Do I have to use any low level of commands? I am not sure how can I fix this issue. Please provide some sample code, suggestions, right path to make the tag ready to have NDEF format and able to write the data on it.
Here is my NFC tag details:
My app sends screen time awareness notifications based on DeviceActivityMonitor thresholds.
Often, users receive two notifications in a row for the same screen time threshold. This means that the app extension is triggering the same eventDidReachThreshold callback function twice for the same threshold. I've made sure that there is only one activity schedule being monitored. This happens often, but not every time (over 50% of the time).
Anybody else experience this issue, and any way to mitigate it?
I'd like to implement a fully immersive space that's experienced by multiple Vision Pro users simultaneously via SharePlay. To do this, the multiple Vision Pro users will join a SharePlay-enabled visionOS window that has a button to enter a fully immersive space, which is also SharePlay-enabled. I tried following the WWDC sessions and docs, but they don't provide enough detail about integrating SharePlay into an existing window and immersive space. How can I adjust my SharePlay code so it makes my visionOS window + fully immersive space SharePlay-able? Please see existing code below for a SharePlay visionOS widow, thank you.
P.S. WWDC ref. https://developer.apple.com/videos/play/wwdc2023/10087
import SwiftUI
import RealityKit
import RealityKitContent
import GroupActivities
import LinkPresentation
struct SharePlayWorld: View, GroupActivity {
@Environment(ViewModel.self) private var model
@Environment(\.openWindow) private var openWindow
@Environment(\.dismissWindow) private var dismissWindow
@Environment(\.openImmersiveSpace) private var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace
var body: some View {
@Bindable var model = model
Toggle(
model.isShowingPracticeSpace ? "Leave Space" : "Enter Space",
isOn: $model.isShowingPracticeSpace
)
.onChange(of: model.isShowingPracticeSpace) { _, isShowing in
Task {
if isShowing
{
await openImmersiveSpace(id: "SharePlayWorld")
}
else
{
await dismissImmersiveSpace()
}
}
}
.toggleStyle(.button)
}
// SHAREPLAY CODE
private func startSharePlaySession() async {
for await session in SharePlayWorld.sessions() {
guard let systemCoordinator = await session.systemCoordinator else { continue }
let isLocalParticipantSpatial = systemCoordinator.localParticipantState.isSpatial
Task.detached {
for await localParticipantState in systemCoordinator.localParticipantStates {
if localParticipantState.isSpatial {
// Start syncing scroll position
} else {
// Stop syncing scroll position
}
}
}
var configuration = SystemCoordinator.Configuration()
configuration.spatialTemplatePreference = .sideBySide
systemCoordinator.configuration = configuration
session.join()
}
// Create the activity
let activity = SharePlayWorld()
// Register the activity on the item provider
let itemProvider = NSItemProvider()
itemProvider.registerGroupActivity(activity)
// Create the activity items configuration
let configuration = await UIActivityItemsConfiguration(itemProviders: [itemProvider])
// Provide the metadata for the group activity
configuration.metadataProvider = { key in
guard key == .linkPresentationMetadata else { return nil }
let metadata = LPLinkMetadata()
metadata.title = "Explore Together"
metadata.imageProvider = NSItemProvider(object: UIImage(named: "explore-activity")!)
return metadata
}
self.activityItemsConfiguration = configuration
}
}
#Preview {
SharePlayWorld()
.environment(ViewModel())
}
I have edited the default widget with Intent, but am being hit with the following errors… it runs perfectly fine if I don’t use an Intent in a static widget
Could not find an intent with identifier ConfigurationAppIntent, mangledTypeName: Optional("27trainWidgetsConfigExtension22ConfigurationAppIntentV")
associateAppIntent(forUserActivity:) Error converting INIntent to App Intent: AppIntents.PerformIntentError.intentNotFound
I think it may be something to do with Info.plist?
Hello
After updating my/our devices to iOS 17 (or XCode 15, not entirely sure), the custom fonts in our application have started randomly not working. Usually it will happen after the app has been in the background for a while.
What happens is that:
The fonts either don't load at all. For icon fonts, this means a lot of question marks.
The fonts get swapped around, meaning regular text (Roboto, custom font) starts rendering using the icon font (Font Awesome). I can tell because I recognize the font from development.
I have no idea how to reproduce it. I tried simulating the memory warning on the simulator, but that doesn't trigger it. It did not happen when building for iOS 16 and I did not change any font logic since then. It still does not happen on devices running iOS 17 but on versions of the app built with XCode 14.
Some debug info:
XCode: 15.0.1 (15A507)
iOS: 17.1.1 (real device, I have not observed it on Simulator)
We load the custom fonts from a proprietary SPM package:
fileprivate static func registerFont(fontName: String, ext: String = "otf") {
guard let fontURL = Bundle.module.url(forResource: fontName, withExtension: ext),
let fontDataProvider = CGDataProvider(url: fontURL as CFURL),
let font = CGFont(fontDataProvider) else {
fatalError("Couldn't create font from filename: \(fontName).\(ext)")
}
var error: Unmanaged<CFError>?
CTFontManagerRegisterGraphicsFont(font, &error)
}
public static func registerFonts() {
registerFont(fontName: "Font Awesome 6 Brands-Regular-400")
registerFont(fontName: "Font Awesome 6 Duotone-Solid-900")
registerFont(fontName: "Font Awesome 6 Pro-Light-300")
registerFont(fontName: "Font Awesome 6 Pro-Regular-400")
registerFont(fontName: "Font Awesome 6 Pro-Solid-900")
registerFont(fontName: "Font Awesome 6 Pro-Thin-100")
registerFont(fontName: "Font Awesome 6 Sharp-Light-300")
registerFont(fontName: "Font Awesome 6 Sharp-Regular-400")
registerFont(fontName: "Font Awesome 6 Sharp-Solid-900")
registerFont(fontName: "Roboto-Medium", ext: "ttf")
registerFont(fontName: "Roboto-Regular", ext: "ttf")
registerFont(fontName: "RobotoMono-Regular", ext: "ttf")
}
// Similar methods for all font types and icons:
@objc public static func getDefaultFont(size: CGFloat) -> UIFont {
return UIFont.init(name: "Roboto-Regular", size: size) ?? UIFont.systemFont(ofSize: size);
}
This code is the called in didFinishLaunching, and it would crash the app if it failed:
FontHandler.registerFonts()
To reiterate, all the fonts work when launching the app. Restarting the app always fixes it, which, combined with the fact that they get swapped around, leads me to believe that it's some kind of font caching issue.
We use the fonts in code-only (no storyboards or xibs ever). A font would be loaded like this:
let label = UILabel()
label.font = FontHandler.getDefaultFont(size: 15)
The font files ship with the SPM package itself, which contains the FontHandler class used above.
import PackageDescription
let package = Package(
name: "MyPackageName",
defaultLocalization: "en",
platforms: [
.iOS(.v11)
],
products: [
.library(
name: "MyPackageName",
targets: ["MyPackageName"]),
],
targets: [
.target(
name: "MyPackageName",
resources: [
.process("Fonts")
]),
.testTarget(
name: "MyPackageNameTests",
dependencies: ["MyPackageName"]),
]
)
Hello,
I'm currently experiencing an issue with the DeviceActivityMonitor extension in my code, specifically with the eventDidReachThreshold callback. I'm hoping to get some insights into why this problem occurs and how to resolve it.
Problem:
Issue 1: The eventDidReachThreshold callback is not triggering as expected. It appears that the callback is not being invoked when the threshold is reached.
Issue 2: After a few seconds, the eventDidReachThreshold callback starts to trigger multiple times. This unexpected behavior is causing problems in my code, as it results in incorrect actions being taken.
Issue 3: There are instances where the eventDidReachThreshold callback provides an incorrect event name.
iOS version: iOS16.7.2 and iOS17.1.1
Here is my code to start the monitoring:
func startMonitoring() {
var startTime : DateComponents = DateComponents(hour: 0, minute: 0)
let endTime : DateComponents = DateComponents(hour: 23, minute: 59)
/// Creates the schedule for the activity, specifying the start and end times, and setting it to repeat.
let schedule = DeviceActivitySchedule(intervalStart: startTime, intervalEnd: endTime, repeats: true, warningTime: nil)
/// Defines the event that should trigger the encouragement.
let event = DeviceActivityEvent(applications: socialActivitySelection.applicationTokens, categories: socialActivitySelection.categoryTokens, webDomains: socialActivitySelection.webDomainTokens, threshold: DateComponents(minute: 2))
let events: [DeviceActivityEvent.Name: DeviceActivityEvent] = [.socialScreenTimeEvent : event]
do {
activityCenter.stopMonitoring([.socialScreenTime])
/// Tries to start monitoring the activity using the specified schedule and events.
try activityCenter.startMonitoring(.socialScreenTime, during: schedule, events: events)
} catch {
/// Prints an error message if the activity could not be started.
print("Could not start monitoring: \(error)")
}
}
In addition, I should mention that, with each iteration through the eventDidReachThreshold callback, I increment the threshold by 2 minutes and restart the monitoring.
If there are any known workarounds or potential solutions, please share them.
Thank you.
Hello all,
My team makes a third-party SDK in the form of an xcframework, and we're working on creating our privacy manifest. However, I've noticed that the privacy manifest we include in the xcframework does not seem to get aggregated in with the base app's manifest when generating the privacy report.
Is that even the expected behavior? That when generating a privacy report, it will aggregate the manifests from the app and all frameworks? We've always recommended to our clients to select "Do not embed" when adding our SDK, as embedding it seems to introduce problems when submitting to the app store. Are the problems in the aggregation due to the fact that it's not embedded?
If it turns out that our manifest won't get aggregated with the client's app's manifest, what should we do? Should we recommend that they manually include any items from our manifest into theirs?
I'd appreciate any information, I haven't been able to find any solid details on any of this.
AASA File was applied to apply UniversalLink to the App. I deleted AASA to remove UniversalLink while using it normally. However, even though I deleted the file, I'm still opening the app. I've tried reinstalling the app several times, and I've also disabled the server cache, but it's no use. What should I do? Anyone knows?
Hello,
I created a lock screen widget for my app last year, as a widget app extension. It has worked fine, but I am working on a new release and it has stopped updating:
It is not called anymore when I call WidgetCenter.shared.reloadTimelines(ofKind: "MyWidget"), and the preview screen is now blank when I add it on the lockscreen.
I haven't touched anything related to the widget from what I know. The only things I can think of is that Xcode has updated my project files automagically, and I have updated cocoapods.
I looked at the device logs, and found this:
[...MyWidget] Failed to launch extension with error: Error Domain=com.apple.extensionKit.errorDomain Code=2 UserInfo={NSUnderlyingError=0x84b4d4410 {Error Domain=RBSRequestErrorDomain Code=5 UserInfo={NSLocalizedFailureReason=, NSUnderlyingError=0x84b45ea30 {Error Domain=NSPOSIXErrorDomain Code=111 UserInfo={NSLocalizedDescription=}}}}}.
I have no idea what this is, hoping someone can come up with suggestions on where to look. I have looked at my git history but I can't find anything changed.
Hello,
I wasn't able to figure out how to handle multiple days with DeviceActivitySchedule.
For instance, let's say the user wants to block certain apps from 9:00 AM to 12:00 AM, every day except Saturday and Sunday, how my schedule should look like?
I've tried different things...
This schedule works for each day of the week, but that's not my goal:
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(hour: 9, minute: 00),
intervalEnd: DateComponents(hour: 12, minute: 00),
repeats: true)
And if I specify the weekDay inside the DateComponents, like this:
// Gregorian calendar
// 2 -> Monday
// 6 -> Friday
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(..., weekday: 2),
intervalEnd: DateComponents(..., weekday: 6),
repeats: true)
the schedule will block the apps from Monday at 9:00 AM to Friday at 12:00 AM, which is also not my goal.
The only workaround that came to my mind was to create a different schedule for each day of the week:
enum WeekDays: String, CaseIterable {
case sun, mon, tue, wed, thu, fri, sat
var sortOrder: Int {
switch self {
case .sun: return 1
case .mon: return 2
case .tue: return 3
case .wed: return 4
case .thu: return 5
case .fri: return 6
case .sat: return 7
}
}
}
func startMonitoring(weekDays: [WeekDays]) {
for weekDay in weekDays {
let day = weekDay.sortOrder
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(
hour: 9,
minute: 00,
weekday: day),
intervalEnd: DateComponents(
hour: 12,
minute: 00,
weekday: day),
repeats: true)
let activityName = DeviceActivityName(weekDay.rawValue)
do {
try center.startMonitoring(activityName,
during: schedule)
} catch {
print("DEBUG: Error: \(error.localizedDescription)")
}
}
}
This way I kinda get what I want, for example:
I can specify 3 days of the week, let's say Monday, Tuesday and Wednesday, the time interval, let's keep 9:00 AM - 12:00 AM, and this function will block apps on Monday, Tuesday and Wednesday at that time interval, fine.
However...
What if I also want another schedule that blocks at a different time interval but same day?
For example, I want to block certain apps Monday and Tuesday from 2:00 PM - 6:00 PM.
Following the example above the activityName would be overwritten, so the user ( for Monday and Tuesday ) would now have only the schedules that starts from 2:00 PM.
Basically, I want the user to be able to select multiple days for a schedule and to let them create as many schedules as they want.
Does anybody know the correct way to handle multiple days schedules?
It seems that whenever I scan the contents of ~/Library/Containers with my app, I get the warning [App] would like to access data from other apps, regardless of how often I have already allowed it. When the warning appears, the last scanned file is ~/Library/Containers/com.apple.CloudPhotosConfiguration/Data.
My sample code:
let openPanel = NSOpenPanel()
openPanel.canChooseDirectories = true
openPanel.runModal()
let url = openPanel.urls[0]
let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: nil)
while let url = enumerator?.nextObject() as? URL {
print(url.path)
}
Is it expected that one has to allow this warning every time the app is run?
Hello, I'm attempting to learn the basics of AppIntents.
My test Hello World intent takes a number and doubles it.
This page (https://developer.apple.com/documentation/appintents/providing-your-app-s-capabilities-to-system-services) seems to imply that you can return types from the perform() function.
My code compiles, but crashes at runtime with the error
perform() returned types not declared in method signature - Did not declare ReturnsValue but provided one
Code:
struct DoubleANumber: AppIntent {
static var title: LocalizedStringResource = "Double a number"
static var description =
IntentDescription("Given a number, gives back twice that number.")
@Parameter(title: "Start Number")
var inputNumber: Double
static var parameterSummary: some ParameterSummary {
Summary("The number to double")
}
func perform() async throws -> some IntentResult & ReturnsValue {
let outputNumber = inputNumber * 2
return .result(value: outputNumber)
}
}
The value returned in the value property of the IntentResult is a Double. I would have assumed that this would be a valid primitive type (as mentioned in the earlier section of that docs page, covering parameters) and that the actual type returned is the wrapper .result type would be covered in the type in the method signature some IntentResult & ReturnsValue
What am I missing?
Thanks.
We have an app with CarPlay support. There you can preview a trip and start it.
However, if we start a trip (see eta and manoeuvres), then turn off the car (or tap disconnect in CarPlay Simulator), then turn it again - CarPlay launched, but there's no eta panel and manoeuvres in it. Even if cancel this trip and start new.
Only after relaunch the app eta and manoeuvres appear again.
Is someone experienced something similar? Maybe this is because some misunderstunding in CarPlay workflow?
When I display the PKToolPicker in my app it looks similar to the image below
If you use one of the apps from Apple like Pages or Freeform you see a picker similar to this one.
Notice that the PKToolPicker from the Apple app has 6 tools not including the ruler. With the tool all the way to the left being the writing tool.
How do you get the picker to display with the writing tool? I have looked over the API and I can see where you can set if the ruler is displayed or not but I can't find anything for the writing tool