I am implementing a couple custom intents in my app. Having completed the implementation of the custom intent definitions and the intent handlers which presumably should be called on voice command based on the suggestedInovocationPhrase, I am getting stumped with just getting IOS to recognize my shortcut donation. While the shortcut donation is executed multiple times from the view that I am trying to create the shortcut for, it is never being displayed in the shortcut app or on my lock screen as having been donated. In my settings App, I have turned on (under Developer) "Display Recent Shortcuts" and "Display Donations on Lock Screen". Here is the code that is executing each time I think I am making a donation:
- (NSUserActivity *) CreateMyShortcut {
NSUserActivity *newActivity = [[NSUserActivity alloc] initWithActivityType: kMyShortCutActivityType];
if (@available(iOS 12.0, *)) {
newActivity.persistentIdentifier = kMyShortCutActivityType;
newActivity.eligibleForSearch = TRUE;
newActivity.eligibleForPrediction = TRUE;
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithContentType: UTTypeImage];
newActivity.title = @"My Shortcut";
attributeSet.contentDescription = @"description";
newActivity.suggestedInvocationPhrase = @"Create Widget";
UIImage *image = [UIImage imageNamed:@"MyApp_Icon.jpg"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
attributeSet.thumbnailData = imageData;
newActivity.contentAttributeSet = attributeSet;
}
return newActivity;
}
This is called from the view that I want to create the shortcut for with the following code:
// Donate a shortcut to allow Siri to assist with creating a parts list
NSUserActivity *activity = [[MyDonationManager sharedInstance] CreateMyShortcut];
NSLog(@"Donating Siri Shortcut");
[activity becomeCurrent];
Is there something else I need to do?
Delve 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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
It seems that subscription status gives different results with XCode testing and Sandbox testing.
I am using StoreKit2 to implement an IAP of an autorenewable subscription. I want to determine whether the subscription has been cancelled, so that the UI reflects that the subscription will stop after the expiry date and not be renewed.
the 'willAutoRenew' property of the subscription status renewalInfo seems to do exactly what is required, and works fine in XCode testing. My setup is very similar to the StoreKit demo associated with the WWDC21 session available here:
https://developer.apple.com/documentation/storekit/in-app_purchase/implementing_a_store_in_your_app_using_the_storekit_api/
To demonstrate its use, add:
print(renewalInfo.willAutoRenew)
after line 79 of the SubscriptionsView in the demo project. When you run the app, and purchase a Standard Navigation assistance subscription, the console shows 'true'. If you then cancel the subscription in XCode (Debug:StoreKit:Manage Transactions), the console will show 'false' as expected
So far so good. My problem is that when I move to Sandbox testing, and cancel the subscription in another way (eg using the .manageSubscriptionsSheet view modifier, or in Settings:App Store:Sandbox Account), the willAutoRenew property remains true, even though the subscription is in fact cancelled (ie it disappears after the expiry date)
Does anyone know a workaround to determine cancellation status?
When testing In-App Purchases in Xcode with a .storekit file, I can delete past purchase transactions, so I can re-test the purchase experience.
I've switched to using a Sandbox tester and made purchases. However, I cannot find how to delete previous purchase transactions made in the sandbox so I can re-run the tests.
Is this possible?
I'm using TestFlight to test an app with payment/subscription functionality. I created sandbox accounts in AppStore Connect accordingly to be able to test the subscriptions. I'm logged in with the sandbox account.
When I try to subscribe in the App the wrong account (this is my actual real AppleID) is used for the subscription although it is recognized that this is just a sandbox subscription.
I tried:
logging off/on into the sandbox account
creating a totally new sandbox account
trying to trigger the payment with no logged in sandbox account
The result is always: in the payment popup it is stated that the purchase account will be my original AppleID and not a sandbox account.
How can I switch the accounts? Is this a bug at Apple's side somehow?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
TestFlight
In-App Purchase
StoreKit
I have an existing iOS app with shortcuts support, and I am trying to bring the same shortcuts to my Mac app in macOS Monterey. In my case, I have added the same intents definition file to my Mac target app, added "Intents eligible for in-app handling" to my Info.plust file and added the intent names, and made sure all the intent handling code is part of both iOS and Mac targets. Still, when I build and run the app on macOS Monterey, the new shortcuts don't show in the shortcut editor at all. I've tried closing and restarting the Shortcuts app, but no luck. The build logs do show the intents being built, but they're just not showing up in the Shortcuts app.
I tried 'donating' one of the intents in my Mac app code, but got an error:
Cannot donate interaction with intent that has no valid shortcut types
Not sure what to try to make it work.
Thanks.
Topic:
App & System Services
SubTopic:
Automation & Scripting
Tags:
wwdc21-10232
App Intents
Shortcuts
On an app that was using the old API for In-App Purchases (StoreKit 1). The app is already published on the App Store. The purchase is non-consumable.
While trying to migrate to StoreKit 2, I'm unable to restore purchases.
Specifically displaying and purchasing products works as expected, but when deleting and reinstalling the app, and then trying to restore purchases I can't do it.
I'm trying to restore them using the new APIs but it doesn't seem to be working.
What I have tried so far:
I'm listening for transaction updates during the whole lifetime of the app, with:
Task.detached {
for await result in Transaction.updates {
if case let .verified(safe) = result {
}
}
}
I have a button that calls this method, but other than prompting to log in again with the Apple ID it doesn't seem to have any effect at all:
try? await AppStore.sync()
This doesn't return any item
for await result in Transaction.currentEntitlements {
if case let .verified(transaction) = result {
}
}
This doesn't return any item
for await result in Transaction.all {
if case let .verified(transaction) = result {
}
}
As mentioned before I'm trying this after purchasing the item and deleting the app. So I'm sure it should be able to restore the purchase.
Am trying this both with a Configuration.storekit file on the simulator, and without it on a real device, in the Sandbox Environment.
Has anyone being able to restore purchases using StoreKit 2?
PD: I already filed a feedback report on Feedback Assistant, but so far the only thing that they have replied is:
Because StoreKit Testing in Xcode is a local environment, and the data is tied to the app, when you delete the app you're also deleting all the transaction data for that app in the Xcode environment. The code snippets provided are correct usage of the API.
So yes, using a Configuration.storekit file won't work on restoring purchases, but if I can't restore them on the Sandbox Environment I'm afraid that this won't work once released, leaving my users totally unable to restore what they have already purchased.
Can i use apple pay integration into my web iframe?In my situation, canMakePayment() returns null when i check browser support apple pay or not in Iframe
In our Mac application, we are creating a web-socket connection using NWConnection and we are able to successfully establish the connection and read/write data from both sides. We have auth tokens which are sent in headers of NWProtocolWebSocket.Options to the server. If token is good, server accepts the web-socket connection. As per RFC 6455, if server does not want to accept the connection for any reason during web-socket handshake, it returns 403 status code. In our case, if cookies are not valid, server returns 403 during web-socket handshake.
However, we could not find a way to read this status code in Network.framework. We are only getting failed state with NWErrorwhich is .posix(53) but there is no indication of the status code 403. We tried looking into protocol metadata on NWConnection object and they are nil.
We tested the same using URLSessionWebSocketTask where in failure callback method, we could see 403 status code on task.response which means client is getting the code correctly from server.
So, is there a way to read the HTTP status code returned by server during web-socket handshake using Network.framework?
I have received two strange crash reports from an iPad11,7 running iPadOS 15.1 and an iPad11,2 running iPadOS 15.2.
On both occasions, the crashed thread calls CFURLRequestSetMainDocumentURL, which in turn calls _dispatch_source_set_runloop_timer_4CF in libdispatch, after which the application crashes with SIGSEGV and SEGV_MAPERR.
The crashed thread's call stack is displayed below. Full crash logs are attached as well. What could this be?
Exception Type: SIGSEGV
Exception Codes: SEGV_MAPERR at 0x21d
Crashed Thread: 20
Thread 20 Crashed:
0 libdispatch.dylib 0x00000001829e1784 _dispatch_source_set_runloop_timer_4CF + 36
1 CFNetwork 0x00000001834fc824 CFURLRequestSetMainDocumentURL + 2240
2 CFNetwork 0x00000001836b89a8 _CFNetworkErrorGetLocalizedDescription + 693652
3 CFNetwork 0x00000001834fdb1c CFURLRequestSetMainDocumentURL + 7096
4 CFNetwork 0x00000001834f3c34 CFURLRequestSetURL + 9668
5 libdispatch.dylib 0x00000001829ca914 _dispatch_call_block_and_release + 28
6 libdispatch.dylib 0x00000001829cc660 _dispatch_client_callout + 16
7 libdispatch.dylib 0x00000001829d3de4 _dispatch_lane_serial_drain + 668
8 libdispatch.dylib 0x00000001829d498c _dispatch_lane_invoke + 440
9 libdispatch.dylib 0x00000001829d5c74 _dispatch_workloop_invoke + 1792
10 libdispatch.dylib 0x00000001829df1a8 _dispatch_workloop_worker_thread + 652
11 libsystem_pthread.dylib 0x00000001f1eea0f4 _pthread_wqthread + 284
12 libsystem_pthread.dylib 0x00000001f1ee9e94 start_wqthread + 4
second_crashlog.txt
report-2517628380750009999-e4d7ea06-6f22-4b7e-b129-045599e1dee5.txt
I'm using NSPersistentCloudKitContainer with Core Data and I receive errors because my iCloud space is full. The errors printed are the following: <CKError 0x280df8e40: "Quota Exceeded" (25/2035); server message = "Quota exceeded"; op = 61846C533467A5DF; uuid = 6A144513-033F-42C2-9E27-693548EF2150; Retry after 342.0 seconds>.
I want to inform the user about this issue, but I can't find a way to access the details of the error. I'm listening to NSPersistentCloudKitContainer.eventChangedNotification, I receive a error of type .partialFailure. But when I want to access the underlying errors, the partialErrorsByItemID property on the error is nil.
How can I access this Quota Exceeded error?
import Foundation
import CloudKit
import Combine
import CoreData
class SyncMonitor {
fileprivate var subscriptions = Set<AnyCancellable>()
init() {
NotificationCenter.default.publisher(for: NSPersistentCloudKitContainer.eventChangedNotification)
.sink { notification in
if let cloudEvent = notification.userInfo?[NSPersistentCloudKitContainer.eventNotificationUserInfoKey] as? NSPersistentCloudKitContainer.Event {
guard let ckerror = cloudEvent.error as? CKError else {
return
}
print("Error: \(ckerror.localizedDescription)")
if ckerror.code == .partialFailure {
guard let errors = ckerror.partialErrorsByItemID else {
return
}
for (_, error) in errors {
if let currentError = error as? CKError {
print(currentError.localizedDescription)
}
}
}
}
} // end of sink
.store(in: &subscriptions)
}
}
I've got an iOS app with lots of extensions, some of them complex and doing a lot of stuff.
After a bug I'd like to be able to use OSLogStore to get a holistic picture of logging for the app and its extensions and send that to a debugging server to retrospectively view logs for the app and its extensions.
The constructor is OSLogStore.init(scope: OSLogStore.Scope), however scope only has one value .currentProcessIdentifier.
Implying if that is called from within the app it can only get access to logging for its process only. I tried it out to confirm this is the case - if I log something in an extension (using Logger), then run the app with code like this:
let logStore = try! OSLogStore(scope: .currentProcessIdentifier)
let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600))
let allEntries = try! logStore.getEntries(at: oneHourAgo)
for entry in allEntries {
look at the content of the entry
Then none of the entries are from the extension.
Is there anyway from within the app I can access logging made within an extension?
I was playing around a bit with the new AttributedString and a few questions came up.
I saw this other forum question "JSON encoding of AttributedString with custom attributes", but I did not completely understand the answer and how I would need to use it.
I created my custom attribute where I just want to store additional text like this:
enum AdditionalTextAttribute: CodableAttributedStringKey, MarkdownDecodableAttributedStringKey {
typealias Value = AttributedString
static let name = "additionalText"
}
I then extended the AttributeScopes like this:
extension AttributeScopes {
struct MyAppAttributes: AttributeScope {
let additionalText: AdditionalTextAttribute
let swiftUI: SwiftUIAttributes
}
var myApp: MyAppAttributes.Type { MyAppAttributes.self }
}
and I also implemented the AttributeDynamicLookup like this:
extension AttributeDynamicLookup {
subscript<T: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeScopes.MyAppAttributes, T>) -> T { self[T.self] }
}
So next I created my AttributedString and added some attributes to it:
var attStr = AttributedString("Hello, here is some text.")
let range1 = attStr.range(of: "Hello")!
let range2 = attStr.range(of: "text")!
attStr[range1].additionalText = AttributedString("Hi")
attStr[range2].foregroundColor = .blue
attStr[range2].font = .caption2
Next I tried to create some JSON from my string and took a look at it like this:
let jsonData = try JSONEncoder().encode(attStr)
print(String(data: jsonData, encoding: .utf8) ?? "no data")
//print result: ["Hello",{},", here is some ",{},"text",{"SwiftUI.ForegroundColor":{},"SwiftUI.Font":{}},".",{}]
I guess it makes sense, that both SwiftUI.ForegroundColor and SwiftUI.Font are empty, because they both do not conform to Codable protocol.
My first question would be: Why does my additionalText attribute not show up here?
I next tried to extend Color to make it codable like this:
extension Color: Codable {
enum CodingKeys: CodingKey {
case red, green, blue, alpha
case desc
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
guard let cgColor = self.cgColor,
let components = cgColor.components else {
if description.isEmpty { throw CodingErrors.encoding }
try container.encode(description, forKey: .desc)
return
}
try container.encode(components[0], forKey: .red)
try container.encode(components[1], forKey: .green)
try container.encode(components[2], forKey: .blue)
try container.encode(components[3], forKey: .alpha)
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let description = try container.decodeIfPresent(String.self, forKey: .desc) {
if description == "blue" {
self = Color.blue
return
}
throw CodingErrors.decoding
}
let red = try container.decode(CGFloat.self, forKey: .red)
let green = try container.decode(CGFloat.self, forKey: .green)
let blue = try container.decode(CGFloat.self, forKey: .blue)
let alpha = try container.decode(CGFloat.self, forKey: .alpha)
self.init(CGColor(red: red, green: green, blue: blue, alpha: alpha))
}
}
But it looks like even though Color is now codable, the encoding function does not get called when I try to put my attributed string into the JSONEncoder.
So my next question is: Does it just not work? Or do I also miss something here?
Coming to my last question: If JSONEncoder does not work, how would I store an AttributedString to disk?
I'm developing a per-app VPN iOS app with Wireguard. For that, I created a configuration file with payload type "com.apple.vpn.managed.applayer". Using the MDM server I installed some apps which need to use the VPN connection. But when I open these apps, I could see the VPN getting enabled in the device. The VPN icon appears on the notification bar but no internet connection. The VPN and internet is working correctly if I change the payload type to "com.apple.vpn.managed" in configuration file.
I am testing App Clip on Testflight to show App Clip Card but it only shows a white Card with the message: “This app clip is not currently available in your country or region” (if using Local Expreriences, it shows normally)
I have fully installed apple-app-site-association, App Clip Experience, Domain URL Status also validated ... don't understand why, is the app "Redy For Sale" new to show the Card?. I want to let customers test show App Clip Card without using Local Expreriences on Testflight
If anyone knows, please help, thank you.
What does APS stand for in APS Environment Entitlement?
When my app starts it loads data (of vehicle models, manufacturers, ...) from JSON files into CoreData. This content is static.
Some CoreData entities have fields that can be set by the user, for example an isFavorite boolean field.
How do I tell CloudKit that my CoreData objects are 'static' and must not be duplicated on other devices (that will also load it from JSON files).
In other words, how can I make sure that the CloudKit knows that the record created from JSON for vehicle model XYZ on one device is the same record that was created from JSON on any other device?
I'm using NSPersistentCloudKitContainer.
I have two call directory extensions, each with InfoPlist.strings in en.lproj and nb.lproj directories. In these files I've defined CFBundleDisplayName for both locales.
These names are displayed under Settings -> Phone -> Call Blocking & Identification. On iOS 12.2 the names are displayed correctly in both Norwegian and English.
Testing on iOS 15.3 the English names are displayed even when device language is set to Norwegian.
Worth noting: When updating the English versions of CFBundleDisplayName this is immediately reflected in Call Blocking & Identification page with Norwegian device language.
As this feature requires a real device, I'm unable to test on iOS 13 and 14.
Hello!
I make use of the new iOS 15.4 SKAdNetwork.updatePostbackConversionValue feature:
SKAdNetwork.updatePostbackConversionValue(0) { error in
if let error = error {
print(error.localizedDescription)
}
}
I am not sure why, but I always see this error message in the console:
SKAdNetwork: Error while updating conversion value: Error Domain=SKANErrorDomain Code=10 "(null)"
The operation couldn’t be completed. (SKANErrorDomain error 10.)
Any idea what’s going on there? What does Error Code 10 mean? Couldn't find anything in the documentation about that so far.
I have the NSAdvertisingAttributionReportEndpoint key with domain (https://api2.branch.io/v1/skadnetwork/advertiser_app) in my .plist.
@Quinn,
The application which is not made with Xcode, has a provision profile, but App Store Connect says "Not Available for Testing".
My Googlefu appears weak as I can't seem to figure out why this is, except that it mentions you need to be using Xcode 13 or newer.
Am guessing Xcode is adding some meta data to the Info.plist file which TestFlight requires.
Is it possible to know which keys and values are required to satisfy TestFlight?
If it's not plist keys, is there something else that's needed, that can be shared? We can do this privately if desired.
I'm trying to use task_for_pid in a project but I keep getting error code 5 signaling some kind of signing error. Even with this script I cant seem to get it to work.
#include <mach/mach_types.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/mach_traps.h>
#include <stdio.h>
int main(int argc, const char * argv[]) {
task_t task;
pid_t pid = argc >= 2 ? atoi(argv[1]) : 1;
kern_return_t error = task_for_pid(mach_task_self(), pid, &task);
printf("%d -> %x [%d - %s]\n", pid, task, error, mach_error_string(error));
return error;
}
I've tried signing my executables using codesign and also tried building with Xcode with the "Debugging Tool" box checked under hardened runtime. My Info.plist file includes the SecTaskAccess key with the values "allowed" and "debug." Hoping someone can point me towards what I'm missing here. Thanks!