Add iOS Today Widget to your React Native App

I am writing this tutorial to hopefully help others who want to experiment with Today Widgets in React Native. I am not an iOS developer and my work has been mostly trial and error, but I did end up with a working widget which can be modified from javascript, just like a normal React Native component.

A lot of credit goes to rclai. His repo really helped me getting started. I also want to credit dewski, who have provided valuable information on setting up the widget.

If you have any additions or improvements are very welcome to let me know.

Ok, lets get to it.

1. Add Today Extension Target to your React Native App

Go to File > New > Target… and select Today Extension. I simply named mine Today Widget, but you can give it any name.

Your new widget should now show up in the project navigator.

2. Modify the Today Widget Info.plist

First create App Transport Security Settingsand add Allow Arbitrary Loads
Then set TodayViewController as the NSExtensionPrincipalClass under NSExtension and remove NSExtensionMainStoryboard.

Finally delete theMainInterface.storyboard file as we won’t need it since our UI components will come from React Native.

3. Add Linker Flags

In the Build Settings of the Today Widget add -ObjC and -lc++ linker flags.

4. Add New Run Script Phase

Under Build Phases in the Today Widget add a new Run Script Phase.

Name it Bundle React Native code and images (this is the same as in your main app target). Then add the following, which is also defined in the main app target:

export NODE_BINARY=node

5. Add React Native Libraries

Now add all the React Native libraries to the widget target’s Build Phases in Link Binary with Libraries.

6. Modify the TodayViewController.m

There are a couple of things that are important to note. If you want your widget to be able to expand it is important that you definesetWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeExpanded in viewDidLoad. Remember to also set the desired height of the widget in expanded mode (set to 300 in this example).

If you don’t want your widget to be expandable use setWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeCompactinstead. Note that the height of the widget in compact mode is always 110.

Your TodayViewController.m should look something like this:

7. Register your Widget in index.ios.js

Now you can open the index.ios.js file and modify it. Start by defining a Widget component that you want to be rendered by your Today Widget. Then remember to register your component, just like the main app:

AppRegistry.registerComponent(‘TodayWidget’, () => Widget);

Hint: If you need to do something different based on whether the widget is in compact or expanded mode, you can add onLayout to your container View and listen for changes on the height of the view.

See the full example index.ios.js here:

That’s it — If you build your app on the simulator you should be able to add your widget to the widget screen and hopefully it displays Hello from React Native! Congratulations, you now have a working widget that can be modified in React Native.

Important! — If you are building your app on device the widget will only work in release mode. On the simulator it works both in debug and release mode. Maybe someone can find a solution to this, I have not spend much time on it.

I have also found that debugging the widget is hard. I haven’t been able to log anything from javascript and if there is any error the widget simply displays Unable to Load. If you find a solution to this, please don’t hesitate to share it.

Finally, keep in mind that Today Widgets are not suited for all cases. If you add long running tasks or complex functionality, the widget might not load. This is taken from the Apple documentation:

Make sure that the Today extension point is appropriate for the functionality you want to provide. The best widgets give users quick updates or enable very simple tasks. If you want to create an app extension that enables a multistep task or helps users perform a lengthy task, such as uploading or downloading content, the Today extension point is not the right choice.

I hope this tutorial was helpful, and as mentioned please do not hesitate to contribute with any corrections or improvements you might discover while working with your widget.