sumup / sumup-ios-sdk

Other
46 stars 25 forks source link

iOS 17 crash when using AirPrint: [UIImage checkmarkImage] not loading, potentially affected by [UIColor(SumUp) colorForStyle] #131

Closed ls-philippe-casgrain closed 11 months ago

ls-philippe-casgrain commented 1 year ago

We have a feature where users can re-print a receipt using AirPrint, which brings up an OS dialog allowing you to change paper size and orientation. However, tapping either of those buttons causes a crash on iOS 17, which is very strange:

Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0xed178 __exceptionPreprocess
1  libobjc.A.dylib                0x2bc00 objc_exception_throw
2  CoreFoundation                 0x1895c -[__NSPlaceholderArray initWithObjects:count:]
3  CoreFoundation                 0x7f40 +[NSArray arrayWithObjects:count:]
4  UIKitCore                      0x108b640 -[_UIImageSystemImageVisualStyle checkmarkImage]
5  UIKitCore                      0x9f1af8 +[UIImage(PreconfiguredSystemImages) checkmarkImage]
6  PrintKitUI                     0x3c764 -[UIPrintPreviewPageCell addPageLabelAndImageView:]
[...]

Somehow, a system UIImage is not loading.

However, before the crash we have this in our logs:

2023-08-18 16:51:59.024521-0400 Restaurant[721:75562] +[SDSStyleSheet styleSheetFromURL:] (line 179): Could not load style sheet data from URL: (null)
2023-08-18 16:51:59.025949-0400 Restaurant[721:75562] +[SDSStyleSheet styleSheetFromURL:] (line 179): Could not load style sheet data from URL: (null)
2023-08-18 16:51:59.039609-0400 Restaurant[721:75562] +[SDSStyleSheet styleSheetFromURL:] (line 179): Could not load style sheet data from URL: (null)

So I set a breakpoint on [SDSStyleSheet styleSheetFromURL:] and this is happening before the crash:

#0  0x00000001159078b4 in +[SDSStyleSheet styleSheetFromURL:] ()
#1  0x0000000115906fa0 in +[SDSStyleSheet global] ()
#2  0x00000001158ba3cc in +[UIColor(SumUp) colorForStyle:] ()
#3  0x0000000198bb8320 in -[_UIImageSystemImageVisualStyle checkmarkImage] ()
#4  0x0000000198516174 in +[UIImage(PreconfiguredSystemImages) checkmarkImage] ()
#5  0x00000001f6cc3590 in -[UIPrintPreviewPageCell addPageLabelAndImageView:] ()
#6  0x00000001f6cae1c4 in -[UIPrintPreviewViewController collectionView:cellForItemAtIndexPath:] ()
#7  0x0000000197bedf40 in -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:notify:] ()
#8  0x0000000197becf68 in -[UICollectionView _createVisibleViewsForSingleCategoryAttributes:limitCreation:fadeForBoundsChange:] ()
#9  0x0000000197bec9d4 in -[UICollectionView _createVisibleViewsForAttributes:fadeForBoundsChange:notifyLayoutForVisibleCellsPass:] ()
#10 0x0000000197b97330 in -[UICollectionView _updateVisibleCellsNow:] ()
#11 0x0000000197b9665c in -[UICollectionView layoutSubviews] ()
#12 0x0000000197b4eec0 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#13 0x0000000196f677dc in CA::Layer::layout_if_needed(CA::Transaction*) ()
#14 0x0000000196f67364 in CA::Layer::layout_and_display_if_needed(CA::Transaction*) ()
#15 0x0000000196f6d8a0 in CA::Context::commit_transaction(CA::Transaction*, double, double*) ()
#16 0x0000000196f66b90 in CA::Transaction::commit() ()
#17 0x0000000196f66838 in CA::Transaction::flush_as_runloop_observer(bool) ()

I suspect that the SumUp SDK is swizzling [UIColor colorForStyle:] in a way that doesn't work with iOS 17.

If I remove the SumUp SDK, the crash goes away.

ls-philippe-casgrain commented 1 year ago

We were using version 4.1.1 and we can still reproduce the issue with version 4.3.4.

alghanor commented 1 year ago

we can confirm that just having the SumUp SDK linked we get a crash exactly like this... additional info: single page works, multiple pages crash - reproducible ... is there a way to swizzle the methods in questions so that it does not crash?

alghanor commented 1 year ago

we will use a workaround:

import Foundation
import UIKit

private var swizzleCounter = 0
private let swizzleQueue = DispatchQueue(label: "de.tillhub.SumUpFix.swizzleQueue", qos: .utility)

public extension UIImage {

    @objc static func checkmarkFixed() -> UIImage {
        return UIImage.strokedCheckmark
    }

    static func fixCheckmarkMethod() {
        swizzleQueue.sync {
            swizzleCounter += 1
            if (swizzleCounter == 1) {
                let className = NSStringFromClass(UIImage.self)

                let originalSelector: Selector = #selector(getter: UIImage.checkmark)
                let swizzledSelector: Selector = #selector(UIImage.checkmarkFixed)

                guard
                    let myClass: AnyClass = objc_getMetaClass(className) as? AnyClass,
                    let originalMethod = class_getClassMethod(myClass, originalSelector),
                    let swizzledMethod = class_getClassMethod(myClass, swizzledSelector)
                else {
                    return
                }

                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
    }
}
kkizlaitis commented 1 year ago

Please fix this ASAP, as this is creating many crashes for our customers in places which are not even related to SumUp.

By the way, @alghanor 's solution works as a temporary fix.

lampapos commented 1 year ago

We also are observing this issue starting from iOS 17. Reproducible both on SumUp SDK 4.3.1 and 4.3.4. Could you, please, share any updates on this?

annaafanasyeva-sumup commented 12 months ago

Hi, SDK 4.3.5 which includes the fix is available with iOS 12 & 13 minimum deployment target support. For a minimum deployment target of 14 or higher, please consider upgrading to 4.4.0 to fix this issue.