Building a Fat WebRTC framework on iOS
At Telestax we strive to minimize the effort spent by App & Web developers to integrate with the Open Source Restcomm Platform when developing WebRTC applications, by providing high level Open Source WebRTC SDKs for iOS, Web and Android. One of the biggest challenges is properly bundling WebRTC for mobile devices and especially iOS, which tends to be more restrictive than Android. Thankfully, that has improved dramatically over the last few years. In this post we’ll go over some best practices for building a WebRTC Framework for iOS.
Building a universal (i.e. Fat) framework for deployment on iOS Devices & Simulators wasn’t always straightforward. In the old days you typically had to build a static library for each architecture separately and then combine them all to a universal library. Then you had to bundle header files together with the lib, so that that the iOS App is able to properly tap on the WebRTC media facilities. This meant time and considerable effort to get everything right. We can spend pages describing how tough things could get, but let’s focus on the present.
Right now you can automatically create an iOS Framework instead of a static lib, which makes it much easier to distribute (since headers are bundled together), and also configure GN (the new ninja generator the WebRTC folks have introduced lately) to make it universal right from the start. No need to make multiple iterations, each for a single architecture and then combine them manually. So here goes…
Fetch & Sync
First you need to fetch & sync the WebRTC code as described in the Getting the Code section of WebRTC Official guide for iOS, should be pretty straightforward.
Generate Ninja files with GN
Here we will deviate a bit from the Official guide as our goal is to:
- Build for multiple architectures at once
- Come up with a WebRTC Framework right from the command line
Here’s the GN command to combine the functionality we want:
$ gn gen out/Release-universal -args='target_os="ios" target_cpu="x64" additional_target_cpus=["arm", "arm64", "x86"] is_component_build=false is_debug=false ios_enable_code_signing=false'
Where:
- out/Release-universal is the path the ninja files will be generated and where the build will happen.
- target_os is the target operating system as the name implies, in this case iOS.
- target_cpu is the primary architecture for the build (for some reason when doing a multi-architecture build I had to put x64 architecture here in order to work, check related issue for more details).
- additional_target_cpus are the additional architectures we want built in our fat framework. So in our case we’ll have all of: arm, arm64, x86 and x64 architectures in a single library (contained in the framework).
- is_component_build governs whether we’ll get a static or dynamic build. We set to false because iOS needs static builds.
- is_debug governs whether we want a debug or release build (default is debug). Here we set it to false because we want a release build, which means much smaller framework.
- ios_enable_code_signing governs whether ninja will code sign the framework. You can can leave this off if you want (which defaults to sign), but in our case we had a big issue because there was an inconsistency between the generated Provisioning Profile inside the framework and the Provisioning Profile used by our App, which caused the loading of the framework on the device to fail.
So once you run that command you should get something like this:
Done. Made 1144 targets from 104 files in 1576ms
Build the Framework
Now that you have generated the ninja files, it’s time to build the actual framework:
$ ninja -C out/Release-universal rtc_sdk_framework_objc
Where:
- -C argument tells ninja which directory to use as root for the build.
- rtc_sdk_framework_objc is a target that the WebRTC folks have created to build the framework.
Once the building is over (for me building those 4 architectures took around 20 minutes) you will find your framework at out/Release-universal:
Use the Framework in your iOS App
You can now drop your framework in your iOS App. An important note at this point is that you have to add the framework as an Embedded Binary at your Xcode project settings in General:
This will make sure that the Framework is allowed to run on the device and also Xcode will automagically add it in the Linked Frameworks and Libraries section below. Important: if accustomed to iOS System Frameworks you add it only to Linked Frameworks and Libraries, the framework will fail to load, with a tough to read error.
That’s about it, you can now take advantage of WebRTC awesomeness ;)
You can also check our own Open Source Restcomm Olympus iOS App that uses the generated WebRTC.Framework that we described above, for more details on the client side integration here or even better take it for a spin in your iOS device by downloading our ready-made .ipa from TestFairy.
Last but not least, huge thanks are due to the WebRTC team efforts for simplifying this process and being so responsive in the webrtc-discuss mailing list.