Fixing the React Native Error: “Unable to open URL: telprompt”
At Build.com, we use Bugsnag to help monitor our app for crashes and errors. The other day, I noticed a group of errors that all took the form:
Error: Unable to open URL: telprompt:5551231234
After some research, I figured out what was causing the bug and how to fix it.
Researching the error
The phone number that was appearing is the number that we give for our users to call us, and all of that happens through one function. So I was able to quickly narrow down where it happens.
Reading the documentation gave me the first clue about the error. I noticed in the documentation that openURL
can be used as a Promise
. However, our code was just calling openURL
and not catching any resulting errors. This type of pattern has caused us trouble in the past so I decided to explore it more.
Unfortunately, the iOS simulator isn’t capable of making phone calls; calls can only be triggered on a physical device. Our project requires a registered phone to be able to attach to Xcode and my test phone is still on its way, so I wasn’t able to reproduce the bug with our app.
Fortunately, the code is simple enough that I was able to create a small test app. I simply created a new app withreact-native init
, added a button to the sample screen, added a call handler and attached my new app to my personal iPhone.
Here’s the call handler that I wrote:
onPressCall() { const url = 'telprompt:5551231234'; Linking.canOpenURL(url) .then((supported) => { if (!supported) { console.error('Can\'t handle url: ' + url); } else { return Linking.openURL(url) .then((data) => console.error("then", data)) .catch((err) => { throw err; }); } }) .catch((err) => console.error('An error occurred', err)); }
Using this simple function, I was quickly able to reproduce the error. Note, I’m intentionally using console.error
and throw
to generate errors that will be visible on the app when it’s running in debugging mode.
Results of the test
The results that I got from my little test were a little surprising.
When the user triggers a phone call, a dialog box appears asking to confirm or cancel the call. I eventually determined that the action taken on this dialog will resolve or reject the Promise returned by
openURL
If the user confirms the call, the Promise is resolved, which causes my
.then()
to generate the following message. This occurs as soon as the user presses the Confirm button; it doesn’t wait for the user to return from the phone app.
If the user cancels the call, the Promise is rejected. This triggers the error you see in the screenshot. As you can see, the error message is close enough to the one captured by Bugsnag for me to be reasonably confident that this is the source of the errors.
Preventing the error
It turns out that the error captured by Bugsnag isn’t really a true error. It’s better classified as an “Unhandled promise rejection”. In this case, I’m not very concerned if the user decides to change their mind and cancel the call. So the solution is easy:
onPressCall() { const url = 'telprompt:5551231234'; Linking.canOpenURL(url) .then((supported) => { if (supported) { return Linking.openURL(url) .catch(() => null); } }); }
The solution that I implemented simply catches the error and swallows it by returning null.
Where else could this apply
The openURL
function is used for more than just making phone calls. It is used for opening any sort of link that needs to be opened in another application. This could include geo-coordinates, web URLs or links to other applications (for example, a link that sends the user to the Yelp app).
There may be situations where you’ll want to handle the rejection or resolution of the promise for those URLs.
great job, it’s help me on a project.
Thanks for reading!
Awesome! clear enough to answer all of my questions. great job dude.
Thanks for reading!