Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Xcode 16 #4066

Merged
merged 9 commits into from
Sep 30, 2024
Merged

Conversation

mludowise-stripe
Copy link
Collaborator

@mludowise-stripe mludowise-stripe commented Sep 26, 2024

Summary

  • Fixes StripeConnect and StripeCardScan to compile on Xcode 16
  • Adds Bitrise tests for Xcode 16 to ensure it compiles
  • Updates OCMock to an Xcode 16 compatible version

Note: OCMock doesn't work with SPM unless you add the dependency via commit hash as opposed to release version. We're using the commit hash that corresponds to v3.9.4:

Motivation

https://jira.corp.stripe.com/browse/MXMOBILE-2808

Testing

Manually tested CardScan example app:

RPReplay_Final1727495221.MP4

Comment on lines +177 to +204
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "41D17A3F2C5A73A6007C6EE6"
BuildableName = "StripeConnect.framework"
BlueprintName = "StripeConnect"
ReferencedContainer = "container:StripeConnect/StripeConnect.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "41D17A492C5A73A7007C6EE6"
BuildableName = "StripeConnectTests.xctest"
BlueprintName = "StripeConnectTests"
ReferencedContainer = "container:StripeConnect/StripeConnect.xcodeproj">
</BuildableReference>
</BuildActionEntry>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds StripeConnect to AllStripeFrameworks so we'll get CI failures when this module doesn't compile

Comment on lines +359 to +361
// Set beginning of scan session
ScanAnalyticsManager.shared.setScanSessionStartTime(time: Date())
/// Check and log torch availability
// Check and log torch availability
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swiftlint fix

Comment on lines 415 to +427
if self.machineLearningSemaphore.wait(timeout: .now()) == .success {
ScanBaseViewController.machineLearningQueue.async {
self.captureOutputWork(sampleBuffer: sampleBuffer)
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer),
let fullCameraImage = pixelBuffer.cgImage() else {
self.machineLearningSemaphore.signal()
return
}
}
}

func captureOutputWork(sampleBuffer: CMSampleBuffer) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}

guard let fullCameraImage = pixelBuffer.cgImage() else {
return
ScanBaseViewController.machineLearningQueue.async { [weak self] in
self?.captureOutputWork(fullCameraImage: fullCameraImage)
self?.machineLearningSemaphore.signal()
}
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both CMSampleBuffer and CVImageBuffer are not Sendable, which I think means that they can only be modified on the main thread? Solution was to convert them to CIImage before passing them to the dispatch queue.

I'm unsure if this is the intended behavior – if it's expensive to convert CMSampleBuffer -> CVImageBuffer -> CIImage, then we're now doing that work on the main thread.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on my memory from implementing the equivalent for Identity, captureOutput on the AVCaptureVideoDataOutputSampleBufferDelegate is always called off the main thread on its own dedicated thread, so I think this should be okay.

Copy link
Contributor

@davidme-stripe davidme-stripe Sep 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I think it might be a little expensive, but I agree that I don't think this will be called on the main thread
  • I don't have the full logic downloaded into my brain atm, but is it okay to call the machineLearningSemaphore outside the machineLearningQueue? That would free anyone else wait-ing on it, right? And no one else should be waiting on it anyway, because captureOutput() won't be called again until this function returns?

Copy link
Collaborator Author

@mludowise-stripe mludowise-stripe Sep 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it okay to call the machineLearningSemaphore outside the machineLearningQueue?

Yes. In fact, this is what it's designed for. Generally the camera feed is faster than the ML model can process images, so the idea is that you want to block the thread that is reading from the camera in order to finish processing the image in CoreML before asking for more camera frames, otherwise you end queuing up so much of the video buffer that the displayed camera feed begins to drop frames and the app lags.

Here's an excerpt from the copy of the CoreML survival guide that gives a basic example:
https://drive.google.com/open?id=1gwW8pgJvg8t_EOkM2cgnDsQDI5Hc_f4o&disco=AAAAVxpjn24

Public link (page 400):
https://www.scribd.com/document/689236733/Core-ML-Survival-Guide

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So yeah, given that we're explicitly calling wait in order to pause this DispatchQueue, I think that it's inconsequential that converting CMSampleBuffer -> CIImage could be non-performant

@@ -24,8 +24,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/erikdoe/ocmock",
"state" : {
"branch" : "master",
"revision" : "05cbc9d934e84ad32530fa53fd7d29c7966d5828"
"revision" : "2c0bfd373289f4a7716db5d6db471640f91a6507"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hash corresponds to the 3.9.4 release tag:
https://github.com/erikdoe/ocmock/releases/tag/v3.9.4

Swift Package manager doesn't allow OCMock unless you add it using a commit hash:
erikdoe/ocmock#500 (comment)

Comment on lines +57 to +59
- test-builds-xcode-16: {}
- test-builds-xcode-15-release: {}
- test-builds-xcode-16-release: {}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds tests to ensure the frameworks build on both Xcode 15 and 16

@mludowise-stripe mludowise-stripe changed the title Xcode 16 compile tests Support Xcode 16 Sep 27, 2024
@mludowise-stripe mludowise-stripe marked this pull request as ready for review September 27, 2024 01:03
davidme-stripe
davidme-stripe previously approved these changes Sep 28, 2024
Copy link
Contributor

@davidme-stripe davidme-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM, thanks for setting it up! Please give the CardImageVerification Example app a spin before merging if you haven't already.

@mludowise-stripe
Copy link
Collaborator Author

This LGTM, thanks for setting it up! Please give the CardImageVerification Example app a spin before merging if you haven't already.

I tested CardScan and it seemed like it was behaving as expected, I wasn't seeing any noticeable camera lag (see video in PR description).

I did find that switching between Xcode 15 and 16 was automatically making changes to the Package.resolved file, so I reverted back to the original originHash and that seemed to fix the issue, but I'll need another shipit.

@mludowise-stripe mludowise-stripe merged commit c8cf5d2 into master Sep 30, 2024
6 checks passed
@mludowise-stripe mludowise-stripe deleted the mludowise/MXMOBILE-2808_compile_xcode16 branch September 30, 2024 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants