During development, before things eventually go live, if the associated server for a message filter extension has a self signed SSL then if/how can test iPhones be configured such that the OS will connect to the server when they are performing a message filter query request?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
If I run an app with a Message Filter Extension on iOS 18 then it works as expected, however if its installed onto a phone with iOS 17.6.1 then there is the following error:
dyld[1042]: Symbol not found: _$sSo40ILMessageFilterCapabilitiesQueryResponseC14IdentityLookupE21promotionalSubActionsSaySo0abI6ActionVGvs
Referenced from: <C82A1045-98F4-3751-8080-413FD0B0DEEB> /private/var/containers/Bundle/Application/F295C156-9B20-4927-AEFA-C6983388B193/Myapp.app/PlugIns/MyMessageFilterExtension.appex/CequintTextFilterExtension.debug.dylib
Expected in: <29BFFA34-9B52-3D14-A254-A0653545B72E> /System/Library/Frameworks/IdentityLookup.framework/IdentityLookup
(App built using XCode 16.2).
Here's code causing the issue:
import IdentityLookup
final class MessageFilterExtension: ILMessageFilterExtension {}
extension MessageFilterExtension: ILMessageFilterQueryHandling, ILMessageFilterCapabilitiesQueryHandling {
func handle(_ capabilitiesQueryRequest: ILMessageFilterCapabilitiesQueryRequest, context: ILMessageFilterExtensionContext, completion: @escaping (ILMessageFilterCapabilitiesQueryResponse) -> Void) {
let response = ILMessageFilterCapabilitiesQueryResponse()
response.transactionalSubActions = [.transactionalCarrier, .transactionalHealth, .transactionalPublicServices, .transactionalFinance, .transactionalWeather, .transactionalRewards, .transactionalOrders, .transactionalOthers, .transactionalReminders]
response.promotionalSubActions = [.promotionalOffers, .promotionalOthers, .promotionalCoupons]
completion(response)
}
Message filter sub actions were introduced in iOS 16, so why is this error occurring when the code is run on iOS 17, but its fine with iOS 18?
This isn't specific to my app, its easily reproducable in two minutes - create an app, add a message filter extension target, change the template code to add a transactional or promotional sub action and then run and it'll occur.
(Reported as issue FB16148083)
I'd like to determine, definitively, if nesting of "binaries" within other "binaries" is possible with iOS.
I put binaries in quotes because I've read documentation/forum posts stating things like nested frameworks isn't supported in iOS. A framework is a binary isn't it, or contains one. So does a statement such as that apply specifically and only to nested frameworks, or does it also apple to other scenarios - such as a SPM binary integrated into a framework?
Here's the specific scenario I'm seeking clarity on - suppose an SDK providing an API/functionality is built as an .xcframework and that SDK contains dependencies on two other components (Firebase, AlmoFire, RealmSwift, CocoaLumberjack, whatever etc.).
Lets say the SDK has two dependencies X and Y and it integrates them via SPM.
Q1: If there is an app A which integrates the SDK, and A doesn't use X and Y itself, then can X and Y be embedded within the SDK and thus opague to A? Is this possible in iOS?
Q2: If A integrates the SDK as above, but additionally, it itself uses X and Y independently of the SDK, then is this situation possible in iOS?
Presumably in Q1 the SDK needs to embed X and Y into the framework?
While presumably in Q2 it should not - because the app will be and hence that would lead to duplicate symbols and potential undefined behaviour (and therefore X and Y's SPM package spec needs to specify dynamic?)
I've been trying to get a clear picture of this for literally weeks and weeks, without reaching a clear conclusion.
So some definitive answer would be very much appreciated.
I've got a .ips file from a handset that had hang detection turned on.
Its not fully symbolicated, how can I symbolicate it?
On that topic, the instructions for symbolicating a .crash file are out of date:
https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report
It says "click the Device Logs button in the Devices and Simulators window, then drag and drop the crash report file into the list of device logs."
However with XCode 15.1 there is no Device Logs button in the Devices and Simulators window.
(If there were that button, presumably these instructions only apply for logs collected from the same device as listed in Devices and Simulators. What if you have a log collected from a device to which you don't have access for it to be in Devices and Simulators?)
I've got an app which is hanging, I turned on Hang Detection and got an .ips file and the top of the hang stack has this:
Dispatch queue: com.apple.main-thread (0)
0 __ulock_wait2
7 NSLog
8 _MMKVLogWithLevel
<snip>
MMKV is a 3rd party library being used in the app. But this looks like MMKV is calling NSLog and then that is hanging? Is that correct, if so then how and why is NSLog hanging and how to solve this issue?
Here's an image of the full stack from XCode when the .ips file is imported:
And here is the heaviest stack info when the .ips is opened as a text file:
Heaviest stack for the main thread of the target process:
411 start + 2240 (dyld + 23940) [0x1bcacad84]
411 main + 96 (MyApp + 108384) [0x10232e760]
411 UIApplicationMain + 340 (UIKitCore + 2270528) [0x19ad20540]
411 -[UIApplication _run] + 888 (UIKitCore + 2273028) [0x19ad20f04]
411 GSEventRunModal + 164 (GraphicsServices + 13536) [0x1dd8554e0]
411 CFRunLoopRunSpecific + 608 (CoreFoundation + 211304) [0x1988a6968]
397 __CFRunLoopRun + 1996 (CoreFoundation + 213528) [0x1988a7218]
397 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 (CoreFoundation + 226588) [0x1988aa51c]
397 _dispatch_main_queue_callback_4CF + 44 (libdispatch.dylib + 74168) [0x1a07831b8]
396 _dispatch_main_queue_drain + 1060 (libdispatch.dylib + 75244) [0x1a07835ec]
396 _dispatch_client_callout + 20 (libdispatch.dylib + 15828) [0x1a0774dd4]
396 _dispatch_call_block_and_release + 32 (libdispatch.dylib + 8508) [0x1a077313c]
396 __49-[RCTCxxBridge _prepareModulesWithDispatchGroup:]_block_invoke + 156 (MyApp + 11155392) [0x102db77c0]
396 -[RCTModuleData instance] + 816 (MyApp + 11498212) [0x102e0b2e4]
396 RCTUnsafeExecuteOnMainQueueSync + 52 (MyApp + 11906956) [0x102e6ef8c]
396 __25-[RCTModuleData instance]_block_invoke + 44 (MyApp + 11499132) [0x102e0b67c]
392 -[RCTModuleData setUpInstanceAndBridge:] + 1324 (MyApp + 11490784) [0x102e095e0]
392 __115-[RCTModuleData initWithModuleClass:bridge:moduleRegistry:viewRegistry_DEPRECATED:bundleManager:callableJSModules:]_block_invoke + 36 (MyApp + 11488056) [0x102e08b38]
392 -[MMKVNative init] + 100 (MyApp + 20934364) [0x10370aedc]
392 RCTExecuteOnMainQueue + 52 (MyApp + 11906684) [0x102e6ee7c]
392 __18-[MMKVNative init]_block_invoke + 232 (MyApp + 20934688) [0x10370b020]
392 +[MMKV initializeMMKV:] + 48 (MyApp + 9265708) [0x102bea22c]
392 +[MMKV initializeMMKV:logLevel:] + 80 (MyApp + 9265800) [0x102bea288]
392 _MMKVLogWithLevel(mmkv::MMKVLogLevel, char const*, char const*, int, char const*, ...) + 348 (MyApp + 9518596) [0x102c27e04]
392 NSLog + 56 (Foundation + 602868) [0x1977b42f4]
392 _NSLogv + 164 (Foundation + 603072) [0x1977b43c0]
392 _CFLogvEx3 + 252 (CoreFoundation + 652276) [0x1989123f4]
392 _CFLogvEx2Predicate + 352 (CoreFoundation + 652792) [0x1989125f8]
392 __CFLogCString + 84 (CoreFoundation + 652948) [0x198912694]
392 _logToStderr + 144 (CoreFoundation + 653980) [0x198912a9c]
392 __ulock_wait2 + 8 (libsystem_kernel.dylib + 59708) [0x1e1a7193c]
*392 ??? (<7ABFF6F3-9E55-3D7B-8DB8-8CF19FB41EFE> + 5068548) [0xfffffff008229704]
I reported this first here: https://developer.apple.com/forums/thread/746539
But have since discovered more findings. In that report there is a hang stack trace (from an .ips file) showing the 3rd party library KKMV featuring. However since posting that I have discovered that my app is hanging all over the place at random places, I've been collecting .ips files and they are all different - expect they all have one thing in common, which is that it always involves __ulock_wait2 / NSLog. There's one example posted in the linked post, but here's a different example but with the same last lines of __ulock_wait2/NSLog
Here's another snippet from a hang, again, just like all the others, it finishes with NSLog/__ulock_wait2
318 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 148 (CoreFoundation + 194472) [0x1988a27a8]
318 @objc CallExtensionManager.appBecameActive() + 28 (Myapp + 296292) [0x100ba8564]
317 CallExtensionManager.appBecameActive() + 912 (Myapp + 295912) [0x100ba83e8]
317 specialized static Logger.always(_:) + 316 (CallFilterFast + 108104) [0x100b7a648]
317 specialized withVaList<A>(_:_:) + 428 (Foundation + 5337508) [0x197c381a4]
317 _NSLogv + 164 (Foundation + 603072) [0x1977b43c0]
317 _CFLogvEx3 + 252 (CoreFoundation + 652276) [0x1989123f4]
317 _CFLogvEx2Predicate + 352 (CoreFoundation + 652792) [0x1989125f8]
317 __CFLogCString + 84 (CoreFoundation + 652948) [0x198912694]
317 _logToStderr + 144 (CoreFoundation + 653980) [0x198912a9c]
317 __ulock_wait2 + 8 (libsystem_kernel.dylib + 59708) [0x1e1a7193c]
*317 ??? (<7ABFF6F3-9E55-3D7B-8DB8-8CF19FB41EFE> + 5068548) [0xfffffff008229704]
Every time the app hangs, in the .ips logging is featured when the ips is opened in XCode or when the ips is examined it always features in the Heaviest stack for the main thread of the target process.
I've drastically reduced the amount of logging within the app in case it was too much, but it made no difference.
When the app hangs there's no crash, I'm running the app either from Testflight, or installing via XCode but then running it from XCode.
If its installed via XCode then a dialog pops up saying it crashed, but there is not crash stack (there's no .crash files on the iPhone, only .ips files, there's no crash reported to crashlytics, and if reported via Testflight there's also no crash info).
Why is NSLog featuring in every .ips file when this happen but at a different location everytime?
If the app is hanging and blocking the main thread, then why isn't it being terminated by Watchdog and thus not producing a .crash file?
I have a real problem with XCode (15 and 16) which is that all the time it'll get stuck installing/attaching to an app.
It'll be working fine one minute, I can make a code change, build, and run the app (on hardware) and everything will be fine. But then make another change, build and run again and now XCode will get stuck saying "Installing app to phone" / "Attaching to app on phone".
If I click stop and try and run again now there'll be two "Installing app to phone" instances running, do it again and then there'll be three and so on.
If I quit XCode and relaunch it then it does not fix the issue, I have to terminate XCode and reboot the phone.
And then it'll be ok again, but only for about 10 minutes, but then it'll start doing the exact same thing again.
Its impossible to work like this, having to reboot the phone every 10 minutes or so.
Is there any solution or tricks? (is it possible to kill the hung task within XCode for example?)
In iOS 18 if a number is registered with CallKit to be blocked, then if that number is also in contacts, then the number isn't blocked.
If a user has added a number to their contacts, then in all probability they might not want the number blocked, so this might seem reasonable behaviour.
However the point is, this is new behaviour for CallKit in iOS 18, and its never been like this before going back several years to the very first release. Why suddenly change it now, after all these years, without notice nor documentation, and take away that option from the user, should for some reason, they want to block a number which is also in their contacts.
This is quite a disruptive change for apps using CallKit.
If I run an app with a message filter extension on < iOS 18 everything is as expected, if I run the same app, without any changes on iOS 18 then it doesn't work.
I've discovered that problems occur if the extension has the following code:
extension MessageFilterExtension: ILMessageFilterQueryHandling, ILMessageFilterCapabilitiesQueryHandling {
func handle(_ capabilitiesQueryRequest: ILMessageFilterCapabilitiesQueryRequest, context: ILMessageFilterExtensionContext, completion: @escaping (ILMessageFilterCapabilitiesQueryResponse) -> Void) {
let response = ILMessageFilterCapabilitiesQueryResponse()
response.transactionalSubActions = [.transactionalCarrier, .transactionalHealth, .transactionalPublicServices, .transactionalFinance, .transactionalWeather, .transactionalRewards, .transactionalOrders, .transactionalOthers, .transactionalReminders]
response.transactionalSubActions = [.transactionalFinance,
.transactionalOrders,
.transactionalHealth]
completion(response)
}
This code doesn't run on iOS 18, however the following code does run on iOS 18:
let response = ILMessageFilterCapabilitiesQueryResponse()
completion(response)
I downloaded several apps from the app store which provide message filtering, within the Message app they all had one thing in common, on < iOS 18 they all show 12 filtering categories, but within iOS 18 they only show 2. So it seems the issue is endemic and effects other apps, not just mine.
If an app has a text filtering extension and associated server that the iPhone OS communicates with, then how can that communication be authenticated?
In other words, how can the server verify that the request is valid and coming from the iPhone and not from some spoofer?
If somebody reverse engineers the associated domain urls our of the app's info.plist or entitlement files and calls the server url directly, then how can the server detect this has occurred and the request is not coming from the iPhone OS of a handset on which the app is installed?
If a server is sending a push to an app, then how can it know whether it should be sending the push using the Apple sandbox push server, or the production server?
If the app is on the app store or testflight then it needs to be using the sandbox server, but if the app is being run via XCode interactively as devs are developing/testing then the push needs to be sent via the sandbox server.
But the server itself has no idea if the app was installed via Testflight/app store/XCode/ or a development .ipa. So the server can't know how to send the push.
The app has to send the push token to the server anyway, so the app could inform the server which environment it should be sent over. But then how can the app detect that itself?
A naive answer is to use #ifdef DEBUG to detect this, but that is incorrect. Which environment a push should be sent over is not correlated with that. For example an app could be being run with a debug scheme or a release scheme, but in both cases if the app is installed/running via xcode then the push environment has to be the sandbox.
So my question is, is there a way the app can detect which push environment a push should be sent over in order than it can instruct the server accordingly?