Lessons Learned: Configure Image Processing Tools on iOS Platform
We wanted to create a framework that uses OpenCV to process pictures, like shape and piece of paper detection. We are going to need it for our internal stuff.
I promise that we will inform you about it in the next weeks!
The first approach was to create a framework that can be managed through Carthage as we prefer Carthage than CocoaPods, because of prebuilt frameworks, which make building your app much faster. Unfortunately there is no easy way to install OpenCV via Carthage as it does not support Carthage, neither official or unofficial way.
Then work on CocoaPods Framework started. Fortunately there are two CocoaPods projects that allow integrating OpenCV easily: OpenCV (3.4.x) and OpenCV2 (4.x). This makes CocoaPods integration much easier and our framework is available through CocoaPods (at the moment it is a private repository, but we are going to open source it within a few months).
Objective-C + Swift + Framework = 💔
Another problem was integrating Objective-C, Swift and C++ in one project. As OpenCV is mostly written in C++, we need Objective-C wrapper (truly it is Objective-C++) for this code. Then we may wrap Objective-C with Swift code. Using Obj-C in Swift is pretty easy with bridging headers, but in framework targets you cannot have one. You can achieve it in a bit different way, but we decided to use only Obj-C wrapper with exposed Swift names through
@interface OpenCV: NSObject + (NSString *)openCVVersionString NS_SWIFT_NAME(openCVVersion()); @end
Of course we use .h and .mm files instead of .h and .m to let the Xcode understand that we use Objective-C++ instead of regular Objective-C.
Imports are not easy
Easy, huh? Does it work? No.
In Objective-C++ with OpenCV you need more complicated import, because the compiler needs to know which imports are valid for C++ and which for Objective-C.
#ifdef __cplusplus #import <opencv2/opencv.hpp> // And more if you need, like: #import <opencv2/core/core.hpp> #import <opencv2/imgcodecs/ios.h> #endif #ifdef __OBJC__ #import <Foundation/Foundation.h> #endif
This C preprocessor macros looks really powerful especially when comparing to Swift. They are still helpful, but hopefully we do not need them on a regular basis thanks to the Swift's simplicity.
Last but not least issue was related to Continuous Integration. We have 3 Github repositories: iOS, Android and shared framework. They are private, but it is pretty easy to use them with your user account. Unfortunately Bitrise needs an access to at least two of them in the same time (iOS + Framework, and Android + Framework). Single SSH key cannot be used in two repositories to grant access, so we decided to create a machine/bot user with granted access to the repositories and with Bitrise’s SSH key.
We had encountered a few problems, but then we successfully resolved them. This was an interesting experience as you do not build frameworks and work with C++ and Objective-C++ on a daily basis nowadays. I still prefer Swift as it is much easier to write efficient code, but sometimes you just need to stick with Obj-C and that can be really fun!