Post

Replies

Boosts

Views

Activity

Redeeming code stucks very often after pressing "Redeem offer code"
Hello, we are facing an issue, that the Code Redemption Sheet is not continuing correctly. Sometimes its just disabling the "Redeem" button and nothing happens for a while. After a while the button gets enabled again and you can press the button again. Sometimes its working then, sometimes not. Furthermore after the button action works and the payment method was chosen, the same issue can happen again. Its doing nothing for a while and you have to start again. The app has the target SDK iOS 14 and uses SwiftUI. We just display the Code Redemption Sheet by using this snippet: SKPaymentQueue.default().presentCodeRedemptionSheet() The screenshot show the "stuck" behavior. The button is disabled and nothing is happening for a while. The code itself is fine and it is working. Best regards, Sebastian
31
17
9.0k
Jun ’22
CoreMediaIO Camera Extension: custom properties?
I struggle to add custom properties to my streams as described in the WWDC22 video https://developer.apple.com/videos/play/wwdc2022/10022/ minute 28:17 The speaker describes using this technique in his CIFilterCam demo (would the source code be available please?) to let the app control which filter the extension should apply. Presumably, there's thus a way to: 1 - define a custom property in the camera extension's stream/device/provider? 2 - be able to use CoreMediaIO (from Swift?) in the app in order to set values of that custom property. This is not documented anywhere I could find. Help and sample code would be greatly appreciated. Thank you. Laurent
14
0
4k
Jun ’22
How to put app-specific logic between migration steps?
There was a section in the talk about how we can break down migration into smaller changes, and that we have an opportunity to run app-specific code in between migration steps. However the talk didn't touch on how can can achieve this, besides a single sentence, which doesn't give enough detail at least for me to figure out how to do it. Intuitively, an event loop could be built that opens the persistent store with the lightweight migration options set and iteratively steps through each unprocessed model in a serial order, and Core Data will migrate the store. Given the automatic nature of the lightweight migrations, especially in the case where we're using NSPersistentCoordinator, doesn't the automatic system just zoom through all of the migrations from model A --> A' --> A'' -> B? How to we make it stop so we can execute our own app code? Thanks!
2
2
1.2k
Jun ’22
BSD Privilege Escalation on macOS
This week I’m handling a DTS incident from a developer who wants to escalate privileges in their app. This is a tricky problem. Over the years I’ve explained aspects of this both here on DevForums and in numerous DTS incidents. Rather than do that again, I figured I’d collect my thoughts into one place and share them here. If you have questions or comments, please start a new thread with an appropriate tag (Service Management or XPC are the most likely candidates here) in the App & System Services > Core OS topic area. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" BSD Privilege Escalation on macOS macOS has multiple privilege models. Some of these were inherited from its ancestor platforms. For example, Mach messages has a capability-based privilege model. Others were introduced by Apple to address specific user scenarios. For example, macOS 10.14 and later have mandatory access control (MAC), as discussed in On File System Permissions. One of the most important privilege models is the one inherited from BSD. This is the classic users and groups model. Many subsystems within macOS, especially those with a BSD heritage, use this model. For example, a packet tracing tool must open a BPF device, /dev/bpf*, and that requires root privileges. Specifically, the process that calls open must have an effective user ID of 0, that is, the root user. That process is said to be running as root, and escalating BSD privileges is the act of getting code to run as root. IMPORTANT Escalating privileges does not bypass all privilege restrictions. For example, MAC applies to all processes, including those running as root. Indeed, running as root can make things harder because TCC will not display UI when a launchd daemon trips over a MAC restriction. Escalating privileges on macOS is not straightforward. There are many different ways to do this, each with its own pros and cons. The best approach depends on your specific circumstances. Note If you find operations where a root privilege restriction doesn’t make sense, feel free to file a bug requesting that it be lifted. This is not without precedent. For example, in macOS 10.2 (yes, back in 2002!) we made it possible to implement ICMP (ping) without root privileges. And in macOS 10.14 we removed the restriction on binding to low-number ports (r. 17427890). Nice! Decide on One-Shot vs Ongoing Privileges To start, decide whether you want one-shot or ongoing privileges. For one-shot privileges, the user authorises the operation, you perform it, and that’s that. For example, if you’re creating an un-installer for your product, one-shot privileges make sense because, once it’s done, your code is no longer present on the user’s system. In contrast, for ongoing privileges the user authorises the installation of a launchd daemon. This code always runs as root and thus can perform privileged operations at any time. Folks often ask for one-shot privileges but really need ongoing privileges. A classic example of this is a custom installer. In many cases installation isn’t a one-shot operation. Rather, the installer includes a software update mechanism that needs ongoing privileges. If that’s the case, there’s no point dealing with one-shot privileges at all. Just get ongoing privileges and treat your initial operation as a special case within that. Keep in mind that you can convert one-shot privileges to ongoing privileges by installing a launchd daemon. Just Because You Can, Doesn’t Mean You Should Ongoing privileges represent an obvious security risk. Your daemon can perform an operation, but how does it know whether it should perform that operation? There are two common ways to authorise operations: Authorise the user Authorise the client To authorise the user, use Authorization Services. For a specific example of this, look at the EvenBetterAuthorizationSample sample code. Note This sample hasn’t been updated in a while (sorry!) and it’s ironic that one of the things it demonstrates, opening a low-number port, no longer requires root privileges. However, the core concepts demonstrated by the sample are still valid. The packet trace example from above is a situation where authorising the user with Authorization Services makes perfect sense. By default you might want your privileged helper tool to allow any user to run a packet trace. However, your code might be running on a Mac in a managed environment, where the site admin wants to restrict this to just admin users, or just a specific group of users. A custom authorisation right gives the site admin the flexibility to configure authorisation exactly as they want. Authorising the client is a relatively new idea. It assumes that some process is using XPC to request that the daemon perform a privileged operation. In that case, the daemon can use XPC facilities to ensure that only certain processes can make such a request. Doing this securely is a challenge. For specific API advice, see this post. WARNING This authorisation is based on the code signature of the process’s main executable. If the process loads plug-ins [1], the daemon can’t tell the difference between a request coming from the main executable and a request coming from a plug-in. [1] I’m talking in-process plug-ins here. Plug-ins that run in their own process, such as those managed by ExtensionKit, aren’t a concern. Choose an Approach There are (at least) seven different ways to run with root privileges on macOS: A setuid-root executable The sudo command AppleScript’s do shell script command, passing true to the administrator privileges parameter The AuthorizationExecuteWithPrivileges routine, deprecated since macOS 10.7 The SMJobSubmit routine targeting the kSMDomainSystemLaunchd domain, deprecated since macOS 10.10 The SMJobBless routine, deprecated since macOS 13 An installer package (.pkg) The SMAppService class, a much-needed enhancement to the Service Management framework introduced in macOS 13 Note There’s one additional approach: The privileged file operation feature in NSWorkspace. I’ve not listed it here because it doesn’t let you run arbitrary code with root privileges. It does, however, have one critical benefit: It’s supported in sandboxed apps. See this post for a bunch of hints and tips. To choose between them: Do not use a setuid-root executable. Ever. It’s that simple! Doing that is creating a security vulnerability looking for an attacker to exploit it. If you’re working interactively on the command line, use sudo. IMPORTANT sudo is not appropriate to use as an API. While it may be possible to make this work under some circumstances, by the time you’re done you’ll have code that’s way more complicated than the alternatives. If you’re building an ad hoc solution to distribute to a limited audience, and you need one-shot privileges, use either AuthorizationExecuteWithPrivileges or AppleScript. While AuthorizationExecuteWithPrivileges still works, it’s been deprecated for many years. Do not use it in a widely distributed product. The AppleScript approach works great from AppleScript, but you can also use it from native code using NSAppleScript. See the code snippet later in this post. If you need one-shot privileges in a widely distributed product, consider using SMJobSubmit. While this is officially deprecated, it’s used by the very popular Sparkle update framework, and thus it’s unlikely to break without warning. If you only need escalated privileges to install your product, consider using an installer package. That’s by far the easiest solution to this problem. Keep in mind that an installer package can install a launchd daemon and thereby gain ongoing privileges. If you need ongoing privileges but don’t want to ship an installer package, use SMAppService. If you need to deploy to older systems, use SMJobBless. For instructions on using SMAppService, see Updating helper executables from earlier versions of macOS. For a comprehensive example of how to use SMJobBless, see the EvenBetterAuthorizationSample sample code. For the simplest possible example, see the SMJobBless sample code. That has a Python script to help you debug your setup. Unfortunately this hasn’t been updated in a while; see this thread for more. Hints and Tips I’m sure I’ll think of more of these as time goes by but, for the moment, let’s start with the big one… Do not run GUI code as root. In some cases you can make this work but it’s not supported. Moreover, it’s not safe. The GUI frameworks are huge, and thus have a huge attack surface. If you run GUI code as root, you are opening yourself up to security vulnerabilities. Appendix: Running an AppleScript from Native Code Below is an example of running a shell script with elevated privileges using NSAppleScript. WARNING This is not meant to be the final word in privilege escalation. Before using this, work through the steps above to see if it’s the right option for you. Hint It probably isn’t! let url: URL = … file URL for the script to execute … let script = NSAppleScript(source: """ on open (filePath) if class of filePath is not text then error "Expected a single file path argument." end if set shellScript to "exec " & quoted form of filePath do shell script shellScript with administrator privileges end open """)! // Create the Apple event. let event = NSAppleEventDescriptor( eventClass: AEEventClass(kCoreEventClass), eventID: AEEventID(kAEOpenDocuments), targetDescriptor: nil, returnID: AEReturnID(kAutoGenerateReturnID), transactionID: AETransactionID(kAnyTransactionID) ) // Set up the direct object parameter to be a single string holding the // path to our script. let parameters = NSAppleEventDescriptor(string: url.path) event.setDescriptor(parameters, forKeyword: AEKeyword(keyDirectObject)) // The `as NSAppleEventDescriptor?` is required due to a bug in the // nullability annotation on this method’s result (r. 38702068). var error: NSDictionary? = nil guard let result = script.executeAppleEvent(event, error: &error) as NSAppleEventDescriptor? else { let code = (error?[NSAppleScript.errorNumber] as? Int) ?? 1 let message = (error?[NSAppleScript.errorMessage] as? String) ?? "-" throw NSError(domain: "ShellScript", code: code, userInfo: nil) } let scriptResult = result.stringValue ?? "" Revision History 2024-11-15 Added info about SMJobSubmit. Made other minor editorial changes. 2024-07-29 Added a reference to the NSWorkspace privileged file operation feature. Made other minor editorial changes. 2022-06-22 First posted.
0
0
2.6k
Jun ’22
XPC Resources
XPC is the preferred inter-process communication (IPC) mechanism on Apple platforms. XPC has three APIs: The high-level NSXPCConnection API, for Objective-C and Swift The low-level Swift API, introduced with macOS 14 The low-level C API, which, while callable from all languages, works best with C-based languages General: DevForums tag: XPC Creating XPC services documentation NSXPCConnection class documentation Low-level API documentation XPC has extensive man pages — For the low-level API, start with the xpc man page; this is the original source for the XPC C API documentation and still contains titbits that you can’t find elsewhere. Also read the xpcservice.plist man page, which documents the property list format used by XPC services. Daemons and Services Programming Guide archived documentation WWDC 2012 Session 241 Cocoa Interprocess Communication with XPC — This is no longer available from the Apple Developer website )-: Technote 2083 Daemons and Agents — It hasn’t been updated in… well… decades, but it’s still remarkably relevant. TN3113 Testing and Debugging XPC Code With an Anonymous Listener XPC and App-to-App Communication DevForums post Validating Signature Of XPC Process DevForums post Related tags include: Inter-process communication, for other IPC mechanisms Service Management, for installing and uninstalling Service Management login items, launchd agents, and launchd daemons Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
2.0k
Jun ’22
Tasks shown "alive" in Instruments display even after they should have finished.
In my TestApp I run the following code, to calculate every pixel of a bitmap concurrently: private func generate() async {     for x in 0 ..< bitmap.width{         for y in 0 ..< bitmap.height{             let result = await Task.detached(priority:.userInitiated){                return iterate(x,y)             }.value             displayResult(result)         }     } } This works and does not give any warnings or runtime issues. After watching the WWDC talk "Visualize and optimize Swift concurrency" I used instruments to visualize the Tasks: The number of active tasks continuously raises until 2740 and stays constant at this value even after all 64000 pixels have been calculated and displayed. What am I doing wrong?
2
0
1.5k
Jun ’22
MusicKit Artwork url
Hi, I'm trying out the beta for music kit. In the current version of my app, my widget can show multiple albums. I preload the images of the album covers. In the beta's the url that is returned for the artwork starts with: "musickit://", which does not work with URLSession. How can I preload the data using the new url scheme? Current code:     func fetchArtworkFor (musicID: MusicItemID, url : URL?) async throws -> UIImage? {         guard let url = url else {             return nil         }         let urlRequest = URLRequest (url: url)         let data = try await URLSession.shared.data(for: urlRequest)         let image = UIImage(data: data.0)         return image     } // Some other function         for album in albumsToShow {             if let url = album.artwork?.url(width: context.family.imageHeight, height: context.family.imageHeight), let image = try? await fetchArtworkFor(musicID: album.id, url:url) {                 images[album] = image             }         }
2
1
1.4k
Jun ’22
MainActor and NSInternalInconsistencyException: 'Call must be made on main thread'
Hello, When attempting to assign the UNNotificationResponse to a Published property on the main thread inside UNUserNotificationCenterDelegate's method func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async both Task { @MainActor in } and await MainActor.run are throwing a NSInternalInconsistencyException: 'Call must be made on main thread'. I thought both of them were essentially doing the same thing, i.e. call their closure on the main thread. So why is this exception thrown? Is my understanding of the MainActor still incorrect, or is this a bug? Thank you Note: Task { await MainActor.run { ... } } and DispatchQueue.main.async don't throw any exception.
4
5
2.9k
Jul ’22
Would YOU use ClamXav on an Apple Mac?
Mac users often ask whether they should install "anti-virus" software. The answer usually given on ASC is "no." The answer is right, but it may give the wrong impression that there is no threat from what are loosely called "viruses." There is a threat, and you need to educate yourself about it. This is a comment on what you should—and should not—do to protect yourself from malicious software ("malware") that circulates on the Internet and gets onto a computer as an unintended consequence of the user's actions. It does not apply to software, such as keystroke loggers, that may be installed deliberately by an intruder who has hands-on access to the computer, or who has been able to log in to it remotely. That threat is in a different category, and there's no easy way to defend against it. The comment is long because the issue is complex. The key points are in sections 5, 6, and 10. OS X now implements three layers of built-in protection specifically against malware, not counting runtime protections such as execute disable, sandboxing, system library randomization, and address space layout randomization that may also guard against other kinds of exploits. 2. All versions of OS X since 10.6.7 have been able to detect known Mac malware in downloaded files, and to block insecure web plugins. This feature is transparent to the user. Internally Apple calls it "XProtect." The malware recognition database used by XProtect is automatically updated; however, you shouldn't rely on it, because the attackers are always at least a day ahead of the defenders. The following caveats apply to XProtect: ☞ It can be bypassed by some third-party networking software, such as BitTorrent clients and Java applets. ☞ It only applies to software downloaded from the network. Software installed from a CD or other media is not checked. As new versions of OS X are released, it's not clear whether Apple will indefinitely continue to maintain the XProtect database of older versions such as 10.6. The security of obsolete system versions may eventually be degraded. Security updates to the code of obsolete systems will stop being released at some point, and that may leave them open to other kinds of attack besides malware. 3. Starting with OS X 10.7.5, there has been a second layer of built-in malware protection, designated "Gatekeeper" by Apple. By default, applications and Installer packages downloaded from the network will only run if they're digitally signed by a developer with a certificate issued by Apple. Software certified in this way hasn't necessarily been tested by Apple, but you can be reasonably sure that it hasn't been modified by anyone other than the developer. His identity is known to Apple, so he could be held legally responsible if he distributed malware. That may not mean much if the developer lives in a country with a weak legal system (see below.) Gatekeeper doesn't depend on a database of known malware. It has, however, the same limitations as XProtect, and in addition the following: ☞ It can easily be disabled or overridden by the user. ☞ A malware attacker could get control of a code-signing certificate under false pretenses, or could simply ignore the consequences of distributing codesigned malware. ☞ An App Store developer could find a way to bypass Apple's oversight, or the oversight could fail due to human error. Apple has so far failed to revoke the codesigning certificates of some known abusers, thereby diluting the value of Gatekeeper and the Developer ID program. These failures don't involve App Store products, however. For the reasons given, App Store products, and—to a lesser extent—other applications recognized by Gatekeeper as signed, are safer than others, but they can't be considered absolutely safe. "Sandboxed" applications may prompt for access to private data, such as your contacts, or for access to the network. Think before granting that access. Sandbox security is based on user input. Never click through any request for authorization without thinking. 4. Starting with OS X 10.8.3, a third layer of protection has been added: a "Malware Removal Tool" (MRT). MRT runs automatically in the background when you update the OS. It checks for, and removes, malware that may have evaded the other protections via a Java exploit (see below.) MRT also runs when you install or update the Apple-supplied Java runtime (but not the Oracle runtime.) Like XProtect, MRT is effective against known threats, but not against unknown ones. It notifies you if it finds malware, but otherwise there's no user interface to MRT. 5. The built-in security features of OS X reduce the risk of malware attack, but they are not, and never will be, complete protection. Malware is a problem of human behavior, and a technological fix is not going to solve it. Trusting software to protect you will only make you more vulnerable. The best defense is always going to be your own intelligence. With the possible exception of Java exploits, all known malware circulating on the Internet that affects a fully-updated installation of OS X 10.6 or later takes the form of so-called "****** horses," which can only have an effect if the victim is duped into running them. The threat therefore amounts to a battle of wits between you and the scam artists. If you're smarter than they think you are, you'll win. That means, in practice, that you always stay within a safe harbor of computing practices. Malware defence By Linc Davis - https://discussions.apple.com/thread/6460085
5
1
3.1k
Jul ’22
CoreMedia I/O Camera Extension Installation Error (Invalid Signature)
Hi! I'm trying to move from CoreMedio I/O DAL Plug-In to CoreMedia I/O camera extensions, announced in macOS 12.3. I created a test extension, placed it inside my app bundle into Contents/Library/SystemExtensions and signed with codesigning certificate. But when I try to install my extension from inside my app, using this code (Swift): func requestActivation() { guard case .idle = status else { fatalError("Invalid state") } print("Requesting activation of extension \"\(extensionIdentifier)\"") let req = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: extensionIdentifier, queue: DispatchQueue.main) req.delegate = self OSSystemExtensionManager.shared.submitRequest(req) status = .requested } I'm getting an error: OSSystemExtensionErrorDomain error 8: Code Signature Invalid which is rather generic. Can anybody tell me what I am doing wrong? Or at least propose some steps to find it out? I'm posting here entitlements and codesign output for my extension and containing application for further information. kdg@admins-Mac-mini SystemExtensions % codesign -d --entitlements - ./com.visicom.VirtualCamera.avextension.systemextension Executable=/Applications/VirtualCamera.app/Contents/Library/SystemExtensions/com.visicom.VirtualCamera.avextension.systemextension/Contents/MacOS/com.visicom.VirtualCamera.avextension [Dict] [Key] com.apple.security.app-sandbox [Value] [Bool] true [Key] com.apple.security.application-groups [Value] [Array] [String] 6SUWV7QQBJ.com.visicom.VirtualCamera kdg@admins-Mac-mini /Applications % codesign -d --entitlements - ./VirtualCamera.app Executable=/Applications/VirtualCamera.app/Contents/MacOS/VirtualCamera [Dict] [Key] com.apple.developer.system-extension.install [Value] [Bool] true [Key] com.apple.security.app-sandbox [Value] [Bool] true [Key] com.apple.security.application-groups [Value] [Array] [String] 6SUWV7QQBJ.com.visicom.VirtualCamera [Key] com.apple.security.files.user-selected.read-only [Value] [Bool] true kdg@admins-Mac-mini SystemExtensions % codesign -dvvv ./com.visicom.VirtualCamera.avextension.systemextension Executable=/Applications/VirtualCamera.app/Contents/Library/SystemExtensions/com.visicom.VirtualCamera.avextension.systemextension/Contents/MacOS/com.visicom.VirtualCamera.avextension Identifier=com.visicom.VirtualCamera.avextension Format=bundle with Mach-O universal (x86_64 arm64) CodeDirectory v=20500 size=1553 flags=0x10700(hard,kill,expires,runtime) hashes=37+7 location=embedded Hash type=sha256 size=32 CandidateCDHash sha256=25bd80657bfd6e0ab95467146c7b532817e9e520 CandidateCDHashFull sha256=25bd80657bfd6e0ab95467146c7b532817e9e5209fd50b0cb7ceef40dcfb40e8 Hash choices=sha256 CMSDigest=25bd80657bfd6e0ab95467146c7b532817e9e5209fd50b0cb7ceef40dcfb40e8 CMSDigestType=2 CDHash=25bd80657bfd6e0ab95467146c7b532817e9e520 Signature size=9006 Authority=Developer ID Application: Visicom Media Inc. (6SUWV7QQBJ) Authority=Developer ID Certification Authority Authority=Apple Root CA Timestamp=7 Jul 2022, 21:49:32 Info.plist entries=23 TeamIdentifier=6SUWV7QQBJ Runtime Version=12.3.0 Sealed Resources version=2 rules=13 files=0 Internal requirements count=1 size=200 kdg@admins-Mac-mini /Applications % codesign -dvvv ./VirtualCamera.app Executable=/Applications/VirtualCamera.app/Contents/MacOS/VirtualCamera Identifier=com.visicom.VirtualCamera Format=app bundle with Mach-O universal (x86_64 arm64) CodeDirectory v=20500 size=1989 flags=0x10700(hard,kill,expires,runtime) hashes=51+7 location=embedded Hash type=sha256 size=32 CandidateCDHash sha256=31e15fbbd436a67a20c5b58c597d8a4796a67720 CandidateCDHashFull sha256=31e15fbbd436a67a20c5b58c597d8a4796a6772020308fb69f4ee80b4e32788b Hash choices=sha256 CMSDigest=31e15fbbd436a67a20c5b58c597d8a4796a6772020308fb69f4ee80b4e32788b CMSDigestType=2 CDHash=31e15fbbd436a67a20c5b58c597d8a4796a67720 Signature size=9006 Authority=Developer ID Application: Visicom Media Inc. (6SUWV7QQBJ) Authority=Developer ID Certification Authority Authority=Apple Root CA Timestamp=7 Jul 2022, 21:58:09 Info.plist entries=20 TeamIdentifier=6SUWV7QQBJ Runtime Version=12.3.0 Sealed Resources version=2 rules=13 files=4 Internal requirements count=1 size=188 Thanks in advance!
8
0
2.4k
Jul ’22
How to modify default APS Environment? (aps-environment)
It looks like APS Environment is configured by setting the aps-environment value in an app entitlements file to either development or production. However, it seems to be the case that, by default, Xcode automatically overrides the set value when an app is signed and the value is instead derived from the provisioning profile. So, for development profiles, you get development (sandbox) aps-environment, and for distribution profiles, you get production aps-environment configured - regardless of how the setting has been configured in the entitlements plist. This is documented here: https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment That document also states that this default behaviour can be overridden: "These default settings can be modified". Question is, how to override these default settings. In other words, how to point aps-environment to production, even if provisioning profile is development. Any insight appreciated, thx.
2
3
1.7k
Jul ’22
Unable to load contents of file list: '/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-input-files.xcfilelist'
Here is my ci_post_clone.sh #!/bin/sh # fail if any command fails set -e # debug log set -x # Install CocoaPods using Homebrew. HOMEBREW_NO_AUTO_UPDATE=1 # disable homebrew's automatic updates. brew install cocoapods # Install Flutter using git. git clone https://github.com/flutter/flutter.git -b stable $HOME/flutter export PATH="$PATH:$HOME/flutter/bin" # Install Flutter artifacts for iOS (--ios), or macOS (--macos) platforms. flutter precache --ios # Install Flutter dependencies. flutter channel master flutter doctor flutter pub get # Generate IOS file flutter build ios --release --no-codesign # Install CocoaPods dependencies. #cd ios && pod install # run `pod install` in the `ios` directory. exit 0
4
0
19k
Jul ’22
Where can I get used Offer Codes from?
I would like to programmatically keep track of offer codes that have been used. I just configured a Test Offer Code (Reference name), which contains 500 codes (Offer Codes) to buy a 1-month subscription for 0,49€. I was able to redeem the code and everything works, but I was expecting to receive the used code. Instead I received the Reference name in the payload from the App Store Server Notification in the field offer_code_ref_name="Test Offer Code". (expected was sth like offer_code_ref_name="JFFDS61SBJDBJ5BXJS4BX") I would be able to identify the Reference name by the code, if it was provided, because I have the following table in my app's backend: reference_name | code | url | expires_at | used | reserved Test Offer Code | xadz | zzz | 31-07-2022 | t | f Test Offer Code | asdf | *** | 31-07-2022 | f | f The used code doesn't seem to be included in the latest receipt. How can I obtain it? Can I somehow call App Store Connect API? Thanks
5
0
2.3k
Jul ’22
AppShortcuts limit for 10 shortcuts
Hi, according this WWDC session https://developer.apple.com/wwdc22/10170 App Shortcuts are defined in Swift code, by implementing the AppShortcutsProvider protocol. To implement the protocol, I'll simply create a single getter that returns all the app shortcuts I want to set up for the user. Note that in total, your app can have a maximum of 10 app shortcuts. However, most apps only need a few. there is a limit for up to 10 AppShortcuts. Could you please clarify how that limit handled? 🤔 (e.g. project failed to build / app will crash or malfunction / only 10 shortcuts will be handled on random/ordered choice by iOS) I suppose there is some way to manage shortcuts amount but see no details at documentation yet.
5
1
2.6k
Jul ’22
CarPlay Simulator not Working
I am trying to run my navigation app on a physical device, and want to view it using CarPlay Simulator (through XCode additional tools, NOT Hardware->Display->CarPlay), however, when I try to use the app, device has a Red dot next to it, and the simulator shows nothing. What I've tried: Running on a real CP device(my car): App works as intended, but want to run simulator so I can have live debugging Forgetting CP device and reconnecting All Steps of "Troubleshooting CP Simulator" (Updating to latest iOS, restarting phone, turn off hotspot, not connected to any other CP devices, ensure Firewall allows incoming connections) Tried both Xcode 13 CP sim and Xcode 14 beta CP sim Tried both work and personal laptops/phones Ideas: I am running on a M1 laptop, which could be messing with something. I am also running my Xcode in Rosetta(app has packages that cannot compile without Rosetta), but I don't believe this should be a problem because I am running on a physical device not Xcode simulator. Also can't run on Hardware->Display->CarPlay because of Application does not implement CarPlay template application lifecycle methods in its scene delegate and I can't figure out how to fix ("EXCLUDED_ARCHS[sdk=iphonesimulator*]"= "arm64" does not work)
7
6
5.3k
Jul ’22
URLComponent does not accept IPv6 address as host in iOS 16
iOS 16 introduced "Internationalized Domain Name" support for URLComponent. As a result, URLComponent does not accept IPv6 address as host in iOS 16. Is this expected behaviour or a bug, and what would be the best workaround in this case? // IPv4 URL var ipv4URLComponents = URLComponents() ipv4URLComponents.scheme = "https" ipv4URLComponents.host = "66.94.29.13" if let url = ipv4URLComponents.url {     print("IPv4 URL:", url) } // IPv6 URL var ipv6URLComponents = URLComponents() ipv6URLComponents.scheme = "https" ipv6URLComponents.host = "2001:0000:3238:dfe1:0063:0000:0000:fefb" if let url = ipv6URLComponents.url {     print("IPv6 URL:", url) } Output on iOS 15.5 device: IPv4 URL: https://66.94.29.13 IPv6 URL: https://2001%3A0000%3A3238%3Adfe1%3A0063%3A0000%3A0000%3Afefb Output on iOS 16 device: IPv4 URL: https://66.94.29.13 IPv6 URL: https: Related thread: https://developer.apple.com/forums/thread/709284
4
0
1.8k
Jul ’22
Start An NEPacketTunnelProvider Fail
My App is a VPN APP, use [com.apple.networkextension.packet-tunnel] extension app to provider a VPN service. A problem puzzled me for a long time: Sometimes the VPN doesn't start successfully, until the user restart the iOS System or reinstall my APP. The detail is : The user use the app normally for many times, and suddenly can't start the vpn service, the APP log show API "startVPNTunnelWithOptions" call success, and return success. but the VPN extension status(NEVPNStatus) change from Disconnect to Connecting and then nothing happen, the VPN process not started, and not any log of the VPN extension created, my VPN log is start from the init function of the class inherit from PacketTunnelProvider, so can see that the vpn process not started. My NETunnelProviderProtocol is : NETunnelProviderProtocol *tunnel = [[NETunnelProviderProtocol alloc] init]; tunnel.providerBundleIdentifier = kTunBundleId; tunnel.serverAddress = @""; tunnel.disconnectOnSleep = NO; [self.providerManager setEnabled:YES]; [self.providerManager setProtocolConfiguration:tunnel]; self.providerManager.localizedDescription = kAppName; very simple, because my app use openvpn3 to provide the vpn service,so no need to set the serverAddress. Because when this problem happened, I can't get any useful log (because APP can't get the iOS system log), so this is a really trouble for me. Could any body help !
5
0
1.5k
Aug ’22
Not receiving Persistent Store Remote Change Notification.
Before the code... CloudKit, background mode (remote notifications) and push notifications are added to Capabilities. Background sync is working fine and view loads current store on manual fetch. Code that initialises the persistent container in app delegate... - (NSPersistentCloudKitContainer *)persistentContainer {     // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.     @synchronized (self) {         if (_persistentContainer == nil) {             _persistentContainer = [[NSPersistentCloudKitContainer alloc] initWithName:@"Expenses"];             [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {                 if (error != nil) {                     __block NSPersistentStoreDescription *sDescription = storeDescription;                     dispatch_async(dispatch_get_main_queue(), ^(){                         [sDescription setOption:[NSNumber numberWithBool:YES] forKey:@"PersistentHistoryTracking"];                         [sDescription setOption:[NSNumber numberWithBool:YES] forKey:@"NSPersistentStoreRemoteChangeNotificationOptionKey"];                     }); #ifdef DEBUG                     NSLog(@"Unresolved error %@, %@", error, error.userInfo); #endif                     abort();                 }                 else #ifdef DEBUG                     NSLog(@"Store successfully initialized"); #endif             }];         }     }     return _persistentContainer; } In Home view controller which is the initial view controller i am adding an observer for the remote notification...     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadViewONCKChangeNotification) name:NSPersistentStoreRemoteChangeNotification object:[appDelegate.persistentContainer persistentStoreCoordinator]]; I am not receiving any store change notifications. Have added breakpoints to see if selector is fired. no go. CloudKit Console also doesn't show any pushes for the concerned time period.
4
0
1.5k
Aug ’22