To the thousands of people who made Talky calls on February 14, 2017, Talky didn’t seem much different. There were some icon and button color changes, but nothing to write home about. However, it was a very big day in our world.
For the past couple of years, we've been transitioning Talky from AmpersandJS to React. The reason for the transition is an article on its own, but to put it simply, I only need one word. Components, heard of 'em?
During the rewrite, we moved the core functionality of Talky into its own library of super slick React components which... [SPOILER ALERT] we'll very soon be making available to anyone who wants to build an app using them. This very simple webrtc react library enables us to build robust video chat features in very little time at all, and we're excited to say we'll be sharing it with the world in the coming months. 🎉
While Talky on the web was receiving consistent upgrades, our Talky iOS application hadn't been updated in quite some time, and it really needed an overhaul to take advantage of some backend upgrades. When trying to figure out what to do about our iOS application we had two options:
- Swift
- React Native
You'll notice I didn't include Objective C. I don’t know if you've ever seen that language, but I'm pretty sure I'd have a better chance understanding ancient hieroglyphs.
Choosing between React Native and Swift
React Native
React Native is an interesting beast with a very cool approach to writing mobile applications—it lets you write the app in Javascript (WHOA!). A few years ago when I was learning to code, I remember dabbling with it and being impressed, but it seemed very young and not production ready. It's really amazing how far it's come in just a few short years.
React Native works by translating JSX into native iOS and Android UIView
's and Views
. The main and Javascript thread communicate through a "bridge" which allows your Javascript code to handle application logic. There's obviously a lot more to it, but I don't quite feel qualified enough to try and explain it (it's literally magic).
Swift and Java (Android)
Writing native code for the platform would require use to rewrite all of the webrtc react library logic twice. On top of that, we're primarily a Javascript shop, so we'd be learning two new languages along with writing the application from scratch. While this does sound like fun, we just didn't have that kind of time.
We decided to go with React Native.
allJavascriptLibraries !== reactNativeCompatible
There are a number of core Node modules that don't work with React Native out of the box such as crypto
, buffer
, and events
. As you can imagine, a number of libraries in our dependecy tree for our webrtc react library depend on those. Luckily RN-Nodeify creates a shim.js
file that installs and shims the necessary modules for you. More magic!
In our webrtc react library, we also depend on a number of window
properties that are only found in the browser. React Native doesn't use the browser so we need to create a shim.webrtc.js
file for this as well.
const WebRTC = require('react-native-webrtc');
const {
RTCPeerConnection,
RTCIceCandidate,
RTCSessionDescription,
getUserMedia,
} = WebRTC;
global.window = global.window || {};
global.window.WebSocket = WebSocket;
global.window.RTCPeerConnection = RTCPeerConnection;
global.RTCPeerConnection = RTCPeerConnection;
global.RTCSessionDescription = RTCSessionDescription;
global.RTCIceCandidate = RTCIceCandidate;
Both of these files are imported at the very top of the very top of our component tree files. Most commonly App.js
WebRTC library orientation An interesting problem we encountered was actually in the WebRTC iOS SDK that was included with React-Native-Webrtc. The underlying video stream’s orientation wouldn’t change after pausing and resuming the local video feed and then rotating the phone. This ended up making the stream look like this:
We spent days searching for what in the world was going on and finally realized that we were probably going to need to lock the orientation of the stream. This required us to build WebRTC from source and modify some of the code in the iOS SDK.
Now as a noob web developer this was a daunting task. I had to download all these scary Google build tools and then do this thing called "compile" which apparently takes an astronomical amount of time the first time you do it. My fans sounded like my MacBook was about to take flight so I went upstairs to make some coffee while my new in-home wind turbine did its thing.
After linking, building, and compiling the library for what felt like the hundredth time, the project finally built with no errors and made a peer to peer connection! Surprisingly, something unintentional happened when this finally built...the bug was fixed! Apparently between v58 and v62 of WebRTC this orientation issue was fixed. Hooray!
A couple of weeks passed and we noticed what was dubbed the "Yaw Bug". Basically, when you changed the "yaw" (screen face up vs. screen face down) of your device while in landscape, the camera orientation changed to portrait.
Luckily we knew exactly where the video orientation was being done and started looking at the code.
This line here told the whole story. You'll notice it's inside the captureOutput
function that fires on device orientation change. It checks to see what orientation the device is and then changes the video's orientation based on that. Inside the switch
statement we can also see that on UIDeviceOrientationFaceUp
and UIDeviceOrientationFaceDown
we just ignore and return the default _rotation
...which is 90 degrees.
This works if we're laying in our bed with the phone in portrait mode, but in landscape it means you end up looking at your face sideways. Which is kinda cool, but also kinda annoying. Thinking about trying to pass this off as a feature and not a bug, we thought better of it and decided to fix it.
The solution was pretty straight forward. We just needed to move that variable declaration into the upper scope so it didn't reset the _rotation
variable on every layout change!
What about Android?
We’re super close to releasing the Android version of the app. Android posed some interesting challenges with how VoIP notifications are handled, but we made it past those. There are a number of methods in React Native that are either iOS-only or Android-only. Importing the Platform
module and checking Platform.OS
makes getting around those issues super easy!
We're incredibly excited about eventually having an Android app in the pipeline. Plus having both Platforms in one codebase and written in Javascript allows any of our developers to pick up and iterate on it without needing to learn a new language with new syntax.
Working with React Native has been a great experience overall. The tooling is wonderful, and the development flow makes writing mobile applications for a web developer a cinch! Sometimes a small change in user-land can represent a huge change in dev-land. A huge thank you to Facebook and all the open source contributors who helped make this possible. If you want to learn more about &yet’s unique approach to web and mobile development check out our website or reach out to us.