forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
465 lines (422 loc) · 68.4 KB
/
index.html
File metadata and controls
465 lines (422 loc) · 68.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Native Modules · React Native</title><meta name="viewport" content="width=device-width"/><meta name="generator" content="Docusaurus"/><meta name="description" content="Sometimes an app needs to access a platform API and React Native doesn't have a corresponding module yet. Maybe you want to reuse some existing Objective-C, Swift or C++ code without having to reimplement it in JavaScript, or write some high performance, multi-threaded code such as for image processing, a database, or any number of advanced extensions."/><meta name="docsearch:version" content="0.23"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Native Modules · React Native"/><meta property="og:type" content="website"/><meta property="og:url" content="https://reactnative.dev/"/><meta property="og:description" content="Sometimes an app needs to access a platform API and React Native doesn't have a corresponding module yet. Maybe you want to reuse some existing Objective-C, Swift or C++ code without having to reimplement it in JavaScript, or write some high performance, multi-threaded code such as for image processing, a database, or any number of advanced extensions."/><meta property="og:image" content="https://reactnative.dev/img/logo-og.png"/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://reactnative.dev/img/logo-og.png"/><link rel="shortcut icon" href="/img/favicon.ico"/><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/solarized-dark.min.css"/><link rel="alternate" type="application/atom+xml" href="https://reactnative.dev/blog/atom.xml" title="React Native Blog ATOM Feed"/><link rel="alternate" type="application/rss+xml" href="https://reactnative.dev/blog/feed.xml" title="React Native Blog RSS Feed"/><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-41298772-2', 'auto');
ga('send', 'pageview');
</script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/focus-visible@5.0.2/dist/focus-visible.min.js"></script><script type="text/javascript" src="https://snack.expo.io/embed.js"></script><script type="text/javascript" src="https://platform.twitter.com/widgets.js"></script><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><script type="text/javascript" src="/js/codeblocks.js"></script><script type="text/javascript" src="/js/tabs.js"></script><script type="text/javascript" src="/js/docs-rating.js"></script><script type="text/javascript" src="/js/announcement.js"></script><script src="https://unpkg.com/vanilla-back-to-top@7.1.14/dist/vanilla-back-to-top.min.js"></script><script>
document.addEventListener('DOMContentLoaded', function() {
addBackToTop(
{"zIndex":100}
)
});
</script><script src="/js/scrollSpy.js"></script><link rel="stylesheet" href="/css/prism.css"/><link rel="stylesheet" href="/css/main.css"/><script src="/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/"><img class="logo" src="/img/header_logo.svg" alt="React Native"/><h2 class="headerTitleWithLogo">React Native</h2></a><a href="/versions"><h3>0.23</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/0.23/getting-started" target="_self">Docs</a></li><li class="siteNavGroupActive"><a href="/docs/0.23/components-and-apis" target="_self">Components</a></li><li class=""><a href="/docs/0.23/accessibilityinfo" target="_self">API</a></li><li class=""><a href="/help" target="_self">Community</a></li><li class=""><a href="/blog/" target="_self">Blog</a></li><li class="navSearchWrapper reactNavSearchWrapper"><input type="text" id="search_input_react" placeholder="Search" title="Search"/></li><li class=""><a href="https://github.com/facebook/react-native" target="_self">GitHub</a></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><div class="hamburger-menu"><div class="line1"></div><div class="line2"></div><div class="line3"></div></div></div><h2><i>›</i><span>Guides (iOS)</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle collapsible">The Basics<span class="arrow"><svg width="24" height="24" viewBox="0 0 24 24"><path fill="#565656" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></span></h3><ul class="hide"><li class="navListItem"><a class="navItem" href="/docs/0.23/getting-started">Getting Started</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/tutorial">Learn the Basics</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/props">Props</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/state">State</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/style">Style</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/height-and-width">Height and Width</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/flexbox">Layout with Flexbox</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/handling-text-input">Handling Text Input</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/handling-touches">Handling Touches</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/using-a-scrollview">Using a ScrollView</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/using-a-listview">Using List Views</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/network">Networking</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/more-resources">More Resources</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle collapsible">Guides<span class="arrow"><svg width="24" height="24" viewBox="0 0 24 24"><path fill="#565656" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></span></h3><ul class="hide"><li class="navListItem"><a class="navItem" href="/docs/0.23/components-and-apis">Components and APIs</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/platform-specific-code">Platform Specific Code</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/navigation">Navigating Between Screens</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/images">Images</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/animations">Animations</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/accessibility">Accessibility</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/improvingux">Improving User Experience</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/timers">Timers</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/debugging">Debugging</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/performance">Performance</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/gesture-responder-system">Gesture Responder System</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/javascript-environment">JavaScript Environment</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/direct-manipulation">Direct Manipulation</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/colors">Color Reference</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/integration-with-existing-apps">Integration with Existing Apps</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/running-on-device">Running On Device</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/upgrading">Upgrading to new React Native versions</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/troubleshooting">Troubleshooting</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/native-modules-setup">Native Modules Setup</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle collapsible">Guides (iOS)<span class="arrow"><svg width="24" height="24" viewBox="0 0 24 24"><path fill="#565656" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></span></h3><ul class="hide"><li class="navListItem navListItemActive"><a class="navItem" href="/docs/0.23/native-modules-ios">Native Modules</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/native-components-ios">Native UI Components</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/linking-libraries-ios">Linking Libraries</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/running-on-simulator-ios">Running On Simulator</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/communication-ios">Communication between native and React Native</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/building-for-tv">Building For TV Devices</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/app-extensions">App Extensions</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle collapsible">Guides (Android)<span class="arrow"><svg width="24" height="24" viewBox="0 0 24 24"><path fill="#565656" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></span></h3><ul class="hide"><li class="navListItem"><a class="navItem" href="/docs/0.23/native-modules-android">Native Modules</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/native-components-android">Native UI Components</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/headless-js-android">Headless JS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/signed-apk-android">Publishing to Google Play Store</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/removing-default-permissions">Removing Default Permissions</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle collapsible">Components<span class="arrow"><svg width="24" height="24" viewBox="0 0 24 24"><path fill="#565656" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></span></h3><ul class="hide"><li class="navListItem"><a class="navItem" href="/docs/0.23/datepickerios">DatePickerIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/drawerlayoutandroid">DrawerLayoutAndroid</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/image">Image</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/modal">Modal</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/navigator">Navigator</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/navigatorios">NavigatorIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/picker">Picker</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/progressbarandroid">ProgressBarAndroid</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/progressviewios">ProgressViewIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/refreshcontrol">RefreshControl</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/scrollview">ScrollView</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/segmentedcontrolios">SegmentedControlIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/snapshotviewios">SnapshotViewIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/statusbar">StatusBar</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/switch">Switch</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/tabbarios">TabBarIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/tabbarios-item">TabBarIOS.Item</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/text">Text</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/textinput">TextInput</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/toolbarandroid">ToolbarAndroid</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/touchablehighlight">TouchableHighlight</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/touchablenativefeedback">TouchableNativeFeedback</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/touchableopacity">TouchableOpacity</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/touchablewithoutfeedback">TouchableWithoutFeedback</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/viewpagerandroid">ViewPagerAndroid</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/webview">WebView</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle collapsible">APIs<span class="arrow"><svg width="24" height="24" viewBox="0 0 24 24"><path fill="#565656" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></span></h3><ul class="hide"><li class="navListItem"><a class="navItem" href="/docs/0.23/actionsheetios">ActionSheetIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/animated">Animated</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/appstate">AppState</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/asyncstorage">AsyncStorage</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/cameraroll">CameraRoll</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/clipboard">Clipboard</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/datepickerandroid">DatePickerAndroid</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/dimensions">Dimensions</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/easing">Easing</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/geolocation">Geolocation</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/imageeditor">ImageEditor</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/imagepickerios">ImagePickerIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/imagestore">ImageStore</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/image-style-props">Image Style Props</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/interactionmanager">InteractionManager</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/layout-props">Layout Props</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/layoutanimation">LayoutAnimation</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/linking">Linking</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/netinfo">NetInfo</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/pixelratio">PixelRatio</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/pushnotificationios">PushNotificationIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/settings">Settings</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/shadow-props">Shadow Props</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/statusbarios">StatusBarIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/stylesheet">StyleSheet</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/text-style-props">Text Style Props</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/timepickerandroid">TimePickerAndroid</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/toastandroid">ToastAndroid</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/transforms">Transforms</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/vibration">Vibration</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/vibrationios">VibrationIOS</a></li><li class="navListItem"><a class="navItem" href="/docs/0.23/view-style-props">View Style Props</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
var headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
var el = event.target;
while(el !== headings){
if (el.tagName === 'A') {
document.body.classList.remove('tocActive');
break;
} else{
el = el.parentNode;
}
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer docsContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/facebook/react-native-website/blob/master/docs/native-modules-ios.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">Native Modules</h1></header><article><div><span><p>Sometimes an app needs to access a platform API and React Native doesn't have a corresponding module yet. Maybe you want to reuse some existing Objective-C, Swift or C++ code without having to reimplement it in JavaScript, or write some high performance, multi-threaded code such as for image processing, a database, or any number of advanced extensions.</p>
<p>We designed React Native such that it is possible for you to write real native code and have access to the full power of the platform. This is a more advanced feature and we don't expect it to be part of the usual development process, however it is essential that it exists. If React Native doesn't support a native feature that you need, you should be able to build it yourself.</p>
<p>This is a more advanced guide that shows how to build a native module. It assumes the reader knows Objective-C or Swift and core libraries (Foundation, UIKit).</p>
<h2><a class="anchor" aria-hidden="true" id="native-module-setup"></a><a href="#native-module-setup" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Native Module Setup</h2>
<p>Native modules are usually distributed as npm packages, except that for them to be native modules they will contain an Xcode library project. To get the basic scaffolding make sure to read <a href="native-modules-setup">Native Modules Setup</a> guide first.</p>
<h2><a class="anchor" aria-hidden="true" id="ios-calendar-module-example"></a><a href="#ios-calendar-module-example" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>iOS Calendar Module Example</h2>
<p>This guide will use the <a href="https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html">iOS Calendar API</a> example. Let's say we would like to be able to access the iOS calendar from JavaScript.</p>
<p>A native module is an Objective-C class that implements the <code>RCTBridgeModule</code> protocol. If you are wondering, RCT is an abbreviation of ReaCT.</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-comment">// CalendarManager.h</span>
<span class="hljs-meta">#import <span class="hljs-meta-string"><React/RCTBridgeModule.h></span></span>
<span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">CalendarManager</span> : <span class="hljs-title">NSObject</span> <<span class="hljs-title">RCTBridgeModule</span>></span>
<span class="hljs-keyword">@end</span>
</code></pre>
<p>In addition to implementing the <code>RCTBridgeModule</code> protocol, your class must also include the <code>RCT_EXPORT_MODULE()</code> macro. This takes an optional argument that specifies the name that the module will be accessible as in your JavaScript code (more on this later). If you do not specify a name, the JavaScript module name will match the Objective-C class name. If the Objective-C class name begins with RCT, the JavaScript module name will exclude the RCT prefix.</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-comment">// CalendarManager.m</span>
<span class="hljs-meta">#import <span class="hljs-meta-string">"CalendarManager.h"</span></span>
<span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">CalendarManager</span></span>
<span class="hljs-comment">// To export a module named CalendarManager</span>
RCT_EXPORT_MODULE();
<span class="hljs-comment">// This would name the module AwesomeCalendarManager instead</span>
<span class="hljs-comment">// RCT_EXPORT_MODULE(AwesomeCalendarManager);</span>
<span class="hljs-keyword">@end</span>
</code></pre>
<p>React Native will not expose any methods of <code>CalendarManager</code> to JavaScript unless explicitly told to. This is done using the <code>RCT_EXPORT_METHOD()</code> macro:</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-meta">#import <span class="hljs-meta-string">"CalendarManager.h"</span></span>
<span class="hljs-meta">#import <span class="hljs-meta-string"><React/RCTLog.h></span></span>
<span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">CalendarManager</span></span>
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(addEvent:(<span class="hljs-built_in">NSString</span> *)name location:(<span class="hljs-built_in">NSString</span> *)location)
{
RCTLogInfo(<span class="hljs-string">@"Pretending to create an event %@ at %@"</span>, name, location);
}
<span class="hljs-keyword">@end</span>
</code></pre>
<p>Now, from your JavaScript file you can call the method like this:</p>
<pre><code class="hljs css language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> NativeModules <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> CalendarManager <span class="token operator">=</span> NativeModules<span class="token punctuation">.</span>CalendarManager<span class="token punctuation">;</span>
CalendarManager<span class="token punctuation">.</span><span class="token function">addEvent</span><span class="token punctuation">(</span>
<span class="token string">'Birthday Party'</span><span class="token punctuation">,</span>
<span class="token string">'4 Privet Drive, Surrey'</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<blockquote>
<p><strong>NOTE</strong>: JavaScript method names</p>
<p>The name of the method exported to JavaScript is the native method's name up to the first colon. React Native also defines a macro called <code>RCT_REMAP_METHOD()</code> to specify the JavaScript method's name. This is useful when multiple native methods are the same up to the first colon and would have conflicting JavaScript names.</p>
</blockquote>
<p>The CalendarManager module is instantiated on the Objective-C side using a [CalendarManager new] call. The return type of bridge methods is always <code>void</code>. React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events (see below).</p>
<h2><a class="anchor" aria-hidden="true" id="argument-types"></a><a href="#argument-types" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Argument Types</h2>
<p><code>RCT_EXPORT_METHOD</code> supports all standard JSON object types, such as:</p>
<ul>
<li>string (<code>NSString</code>)</li>
<li>number (<code>NSInteger</code>, <code>float</code>, <code>double</code>, <code>CGFloat</code>, <code>NSNumber</code>)</li>
<li>boolean (<code>BOOL</code>, <code>NSNumber</code>)</li>
<li>array (<code>NSArray</code>) of any types from this list</li>
<li>object (<code>NSDictionary</code>) with string keys and values of any type from this list</li>
<li>function (<code>RCTResponseSenderBlock</code>)</li>
</ul>
<p>But it also works with any type that is supported by the <code>RCTConvert</code> class (see <a href="https://github.com/facebook/react-native/blob/master/React/Base/RCTConvert.h"><code>RCTConvert</code></a> for details). The <code>RCTConvert</code> helper functions all accept a JSON value as input and map it to a native Objective-C type or class.</p>
<p>In our <code>CalendarManager</code> example, we need to pass the event date to the native method. We can't send JavaScript Date objects over the bridge, so we need to convert the date to a string or number. We could write our native function like this:</p>
<pre><code class="hljs css language-objectivec">RCT_EXPORT_METHOD(addEvent:(<span class="hljs-built_in">NSString</span> *)name location:(<span class="hljs-built_in">NSString</span> *)location date:(<span class="hljs-keyword">nonnull</span> <span class="hljs-built_in">NSNumber</span> *)secondsSinceUnixEpoch)
{
<span class="hljs-built_in">NSDate</span> *date = [RCTConvert <span class="hljs-built_in">NSDate</span>:secondsSinceUnixEpoch];
}
</code></pre>
<p>or like this:</p>
<pre><code class="hljs css language-objectivec">RCT_EXPORT_METHOD(addEvent:(<span class="hljs-built_in">NSString</span> *)name location:(<span class="hljs-built_in">NSString</span> *)location date:(<span class="hljs-built_in">NSString</span> *)ISO8601DateString)
{
<span class="hljs-built_in">NSDate</span> *date = [RCTConvert <span class="hljs-built_in">NSDate</span>:ISO8601DateString];
}
</code></pre>
<p>But by using the automatic type conversion feature, we can skip the manual conversion step completely, and write:</p>
<pre><code class="hljs css language-objectivec">RCT_EXPORT_METHOD(addEvent:(<span class="hljs-built_in">NSString</span> *)name location:(<span class="hljs-built_in">NSString</span> *)location date:(<span class="hljs-built_in">NSDate</span> *)date)
{
<span class="hljs-comment">// Date is ready to use!</span>
}
</code></pre>
<p>You would then call this from JavaScript by using either:</p>
<pre><code class="hljs css language-jsx">CalendarManager<span class="token punctuation">.</span><span class="token function">addEvent</span><span class="token punctuation">(</span>
<span class="token string">'Birthday Party'</span><span class="token punctuation">,</span>
<span class="token string">'4 Privet Drive, Surrey'</span><span class="token punctuation">,</span>
date<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// passing date as number of milliseconds since Unix epoch</span>
</code></pre>
<p>or</p>
<pre><code class="hljs css language-jsx">CalendarManager<span class="token punctuation">.</span><span class="token function">addEvent</span><span class="token punctuation">(</span>
<span class="token string">'Birthday Party'</span><span class="token punctuation">,</span>
<span class="token string">'4 Privet Drive, Surrey'</span><span class="token punctuation">,</span>
date<span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// passing date as ISO-8601 string</span>
</code></pre>
<p>And both values would get converted correctly to the native <code>NSDate</code>. A bad value, like an <code>Array</code>, would generate a helpful "RedBox" error message.</p>
<p>As <code>CalendarManager.addEvent</code> method gets more and more complex, the number of arguments will grow. Some of them might be optional. In this case it's worth considering changing the API a little bit to accept a dictionary of event attributes, like this:</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-meta">#import <span class="hljs-meta-string"><React/RCTConvert.h></span></span>
RCT_EXPORT_METHOD(addEvent:(<span class="hljs-built_in">NSString</span> *)name details:(<span class="hljs-built_in">NSDictionary</span> *)details)
{
<span class="hljs-built_in">NSString</span> *location = [RCTConvert <span class="hljs-built_in">NSString</span>:details[<span class="hljs-string">@"location"</span>]];
<span class="hljs-built_in">NSDate</span> *time = [RCTConvert <span class="hljs-built_in">NSDate</span>:details[<span class="hljs-string">@"time"</span>]];
...
}
</code></pre>
<p>and call it from JavaScript:</p>
<pre><code class="hljs css language-jsx">CalendarManager<span class="token punctuation">.</span><span class="token function">addEvent</span><span class="token punctuation">(</span><span class="token string">'Birthday Party'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
location<span class="token punctuation">:</span> <span class="token string">'4 Privet Drive, Surrey'</span><span class="token punctuation">,</span>
time<span class="token punctuation">:</span> date<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
description<span class="token punctuation">:</span> <span class="token string">'...'</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<blockquote>
<p><strong>NOTE</strong>: About array and map</p>
<p>Objective-C doesn't provide any guarantees about the types of values in these structures. Your native module might expect an array of strings, but if JavaScript calls your method with an array containing numbers and strings, you'll get an <code>NSArray</code> containing a mix of <code>NSNumber</code> and <code>NSString</code>. For arrays, <code>RCTConvert</code> provides some typed collections you can use in your method declaration, such as <code>NSStringArray</code>, or <code>UIColorArray</code>. For maps, it is the developer's responsibility to check the value types individually by manually calling <code>RCTConvert</code> helper methods.</p>
</blockquote>
<h2><a class="anchor" aria-hidden="true" id="callbacks"></a><a href="#callbacks" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Callbacks</h2>
<blockquote>
<p><strong>WARNING</strong></p>
<p>This section is more experimental than others because we don't have a solid set of best practices around callbacks yet.</p>
</blockquote>
<p>Native modules also supports a unique kind of argument- a callback. In most cases it is used to provide the function call result to JavaScript.</p>
<pre><code class="hljs css language-objectivec">RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback)
{
<span class="hljs-built_in">NSArray</span> *events = ...
callback(@[[<span class="hljs-built_in">NSNull</span> null], events]);
}
</code></pre>
<p><code>RCTResponseSenderBlock</code> accepts only one argument - an array of parameters to pass to the JavaScript callback. In this case we use Node's convention to make the first parameter an error object (usually <code>null</code> when there is no error) and the rest are the results of the function.</p>
<pre><code class="hljs css language-jsx">CalendarManager<span class="token punctuation">.</span><span class="token function">findEvents</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> events</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> events<span class="token punctuation">:</span> events <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>A native module should invoke its callback exactly once. It's okay to store the callback and invoke it later. This pattern is often used to wrap iOS APIs that require delegates - see <a href="https://github.com/facebook/react-native/blob/master/React/Modules/RCTAlertManager.m"><code>RCTAlertManager</code></a> for an example. If the callback is never invoked, some memory is leaked. If both <code>onSuccess</code> and <code>onFail</code> callbacks are passed, you should only invoke one of them.</p>
<p>If you want to pass error-like objects to JavaScript, use <code>RCTMakeError</code> from <a href="https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h"><code>RCTUtils.h</code></a>. Right now this only passes an Error-shaped dictionary to JavaScript, but we would like to automatically generate real JavaScript <code>Error</code> objects in the future.</p>
<h2><a class="anchor" aria-hidden="true" id="promises"></a><a href="#promises" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Promises</h2>
<p>Native modules can also fulfill a promise, which can simplify your code, especially when using ES2016's <code>async/await</code> syntax. When the last parameters of a bridged native method are an <code>RCTPromiseResolveBlock</code> and <code>RCTPromiseRejectBlock</code>, its corresponding JS method will return a JS Promise object.</p>
<p>Refactoring the above code to use a promise instead of callbacks looks like this:</p>
<pre><code class="hljs css language-objectivec">RCT_REMAP_METHOD(findEvents,
findEventsWithResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
<span class="hljs-built_in">NSArray</span> *events = ...
<span class="hljs-keyword">if</span> (events) {
resolve(events);
} <span class="hljs-keyword">else</span> {
<span class="hljs-built_in">NSError</span> *error = ...
reject(<span class="hljs-string">@"no_events"</span>, <span class="hljs-string">@"There were no events"</span>, error);
}
}
</code></pre>
<p>The JavaScript counterpart of this method returns a Promise. This means you can use the <code>await</code> keyword within an async function to call it and wait for its result:</p>
<pre><code class="hljs css language-jsx"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">updateEvents</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">var</span> events <span class="token operator">=</span> <span class="token keyword">await</span> CalendarManager<span class="token punctuation">.</span><span class="token function">findEvents</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> events <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token function">updateEvents</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<h2><a class="anchor" aria-hidden="true" id="threading"></a><a href="#threading" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Threading</h2>
<p>The native module should not have any assumptions about what thread it is being called on. React Native invokes native modules methods on a separate serial GCD queue, but this is an implementation detail and might change. The <code>- (dispatch_queue_t)methodQueue</code> method allows the native module to specify which queue its methods should be run on. For example, if it needs to use a main-thread-only iOS API, it should specify this via:</p>
<pre><code class="hljs css language-objectivec">- (<span class="hljs-built_in">dispatch_queue_t</span>)methodQueue
{
<span class="hljs-keyword">return</span> dispatch_get_main_queue();
}
</code></pre>
<p>Similarly, if an operation may take a long time to complete, the native module should not block and can specify it's own queue to run operations on. For example, the <code>RCTAsyncLocalStorage</code> module creates its own queue so the React queue isn't blocked waiting on potentially slow disk access:</p>
<pre><code class="hljs css language-objectivec">- (<span class="hljs-built_in">dispatch_queue_t</span>)methodQueue
{
<span class="hljs-keyword">return</span> dispatch_queue_create(<span class="hljs-string">"com.facebook.React.AsyncLocalStorageQueue"</span>, DISPATCH_QUEUE_SERIAL);
}
</code></pre>
<p>The specified <code>methodQueue</code> will be shared by all of the methods in your module. If <em>only one</em> of your methods is long-running (or needs to be run on a different queue than the others for some reason), you can use <code>dispatch_async</code> inside the method to perform that particular method's code on another queue, without affecting the others:</p>
<pre><code class="hljs css language-objectivec">RCT_EXPORT_METHOD(doSomethingExpensive:(<span class="hljs-built_in">NSString</span> *)param callback:(RCTResponseSenderBlock)callback)
{
<span class="hljs-built_in">dispatch_async</span>(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, <span class="hljs-number">0</span>), ^{
<span class="hljs-comment">// Call long-running code on background thread</span>
...
<span class="hljs-comment">// You can invoke callback from any thread/queue</span>
callback(@[...]);
});
}
</code></pre>
<blockquote>
<p><strong>NOTE</strong>: Sharing dispatch queues between modules</p>
<p>The <code>methodQueue</code> method will be called once when the module is initialized, and then retained by the bridge, so there is no need to retain the queue yourself, unless you wish to make use of it within your module. However, if you wish to share the same queue between multiple modules then you will need to ensure that you retain and return the same queue instance for each of them; merely returning a queue of the same name for each won't work.</p>
</blockquote>
<h2><a class="anchor" aria-hidden="true" id="dependency-injection"></a><a href="#dependency-injection" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Dependency Injection</h2>
<p>The bridge initializes any registered RCTBridgeModules automatically, however you may wish to instantiate your own module instances (so you may inject dependencies, for example).</p>
<p>You can do this by creating a class that implements the RCTBridgeDelegate Protocol, initializing an RCTBridge with the delegate as an argument and initialising a RCTRootView with the initialized bridge.</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-keyword">id</span><RCTBridgeDelegate> moduleInitialiser = [[classThatImplementsRCTBridgeDelegate alloc] init];
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:moduleInitialiser launchOptions:<span class="hljs-literal">nil</span>];
RCTRootView *rootView = [[RCTRootView alloc]
initWithBridge:bridge
moduleName:kModuleName
initialProperties:<span class="hljs-literal">nil</span>];
</code></pre>
<h2><a class="anchor" aria-hidden="true" id="exporting-constants"></a><a href="#exporting-constants" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Exporting Constants</h2>
<p>A native module can export constants that are immediately available to JavaScript at runtime. This is useful for communicating static data that would otherwise require a round-trip through the bridge.</p>
<pre><code class="hljs css language-objectivec">- (<span class="hljs-built_in">NSDictionary</span> *)constantsToExport
{
<span class="hljs-keyword">return</span> @{ <span class="hljs-string">@"firstDayOfTheWeek"</span>: <span class="hljs-string">@"Monday"</span> };
}
</code></pre>
<p>JavaScript can use this value right away, synchronously:</p>
<pre><code class="hljs css language-jsx">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>CalendarManager<span class="token punctuation">.</span>firstDayOfTheWeek<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Note that the constants are exported only at initialization time, so if you change <code>constantsToExport</code> values at runtime it won't affect the JavaScript environment.</p>
<h3><a class="anchor" aria-hidden="true" id="implementing--requiresmainqueuesetup"></a><a href="#implementing--requiresmainqueuesetup" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Implementing <code>+ requiresMainQueueSetup</code></h3>
<p>If you override <code>- constantsToExport</code> then you should also implement <code>+ requiresMainQueueSetup</code> to let React Native know if your module needs to be initialized on the main thread. Otherwise you will see a warning that in the future your module may be initialized on a background thread unless you explicitly opt out with <code>+ requiresMainQueueSetup</code>:</p>
<pre><code class="hljs css language-objectivec">+ (<span class="hljs-built_in">BOOL</span>)requiresMainQueueSetup
{
<span class="hljs-keyword">return</span> <span class="hljs-literal">YES</span>; <span class="hljs-comment">// only do this if your module initialization relies on calling UIKit!</span>
}
</code></pre>
<p>If your module does not require access to UIKit, then you should respond to <code>+ requiresMainQueueSetup</code> with <code>NO</code>.</p>
<h3><a class="anchor" aria-hidden="true" id="enum-constants"></a><a href="#enum-constants" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Enum Constants</h3>
<p>Enums that are defined via <code>NS_ENUM</code> cannot be used as method arguments without first extending RCTConvert.</p>
<p>In order to export the following <code>NS_ENUM</code> definition:</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-keyword">typedef</span> <span class="hljs-built_in">NS_ENUM</span>(<span class="hljs-built_in">NSInteger</span>, <span class="hljs-built_in">UIStatusBarAnimation</span>) {
<span class="hljs-built_in">UIStatusBarAnimationNone</span>,
<span class="hljs-built_in">UIStatusBarAnimationFade</span>,
<span class="hljs-built_in">UIStatusBarAnimationSlide</span>,
};
</code></pre>
<p>You must create a class extension of RCTConvert like so:</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">RCTConvert</span> (<span class="hljs-title">StatusBarAnimation</span>)</span>
RCT_ENUM_CONVERTER(<span class="hljs-built_in">UIStatusBarAnimation</span>, (@{ <span class="hljs-string">@"statusBarAnimationNone"</span> : @(<span class="hljs-built_in">UIStatusBarAnimationNone</span>),
<span class="hljs-string">@"statusBarAnimationFade"</span> : @(<span class="hljs-built_in">UIStatusBarAnimationFade</span>),
<span class="hljs-string">@"statusBarAnimationSlide"</span> : @(<span class="hljs-built_in">UIStatusBarAnimationSlide</span>)}),
<span class="hljs-built_in">UIStatusBarAnimationNone</span>, integerValue)
<span class="hljs-keyword">@end</span>
</code></pre>
<p>You can then define methods and export your enum constants like this:</p>
<pre><code class="hljs css language-objectivec">- (<span class="hljs-built_in">NSDictionary</span> *)constantsToExport
{
<span class="hljs-keyword">return</span> @{ <span class="hljs-string">@"statusBarAnimationNone"</span> : @(<span class="hljs-built_in">UIStatusBarAnimationNone</span>),
<span class="hljs-string">@"statusBarAnimationFade"</span> : @(<span class="hljs-built_in">UIStatusBarAnimationFade</span>),
<span class="hljs-string">@"statusBarAnimationSlide"</span> : @(<span class="hljs-built_in">UIStatusBarAnimationSlide</span>) };
};
RCT_EXPORT_METHOD(updateStatusBarAnimation:(<span class="hljs-built_in">UIStatusBarAnimation</span>)animation
completion:(RCTResponseSenderBlock)callback)
</code></pre>
<p>Your enum will then be automatically unwrapped using the selector provided (<code>integerValue</code> in the above example) before being passed to your exported method.</p>
<h2><a class="anchor" aria-hidden="true" id="sending-events-to-javascript"></a><a href="#sending-events-to-javascript" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Sending Events to JavaScript</h2>
<p>The native module can signal events to JavaScript without being invoked directly. The preferred way to do this is to subclass <code>RCTEventEmitter</code>, implement <code>supportedEvents</code> and call <code>self sendEventWithName</code>:</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-comment">// CalendarManager.h</span>
<span class="hljs-meta">#import <span class="hljs-meta-string"><React/RCTBridgeModule.h></span></span>
<span class="hljs-meta">#import <span class="hljs-meta-string"><React/RCTEventEmitter.h></span></span>
<span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">CalendarManager</span> : <span class="hljs-title">RCTEventEmitter</span> <<span class="hljs-title">RCTBridgeModule</span>></span>
<span class="hljs-keyword">@end</span>
</code></pre>
<pre><code class="hljs css language-objectivec"><span class="hljs-comment">// CalendarManager.m</span>
<span class="hljs-meta">#import <span class="hljs-meta-string">"CalendarManager.h"</span></span>
<span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">CalendarManager</span></span>
RCT_EXPORT_MODULE();
- (<span class="hljs-built_in">NSArray</span><<span class="hljs-built_in">NSString</span> *> *)supportedEvents
{
<span class="hljs-keyword">return</span> @[<span class="hljs-string">@"EventReminder"</span>];
}
- (<span class="hljs-keyword">void</span>)calendarEventReminderReceived:(<span class="hljs-built_in">NSNotification</span> *)notification
{
<span class="hljs-built_in">NSString</span> *eventName = notification.userInfo[<span class="hljs-string">@"name"</span>];
[<span class="hljs-keyword">self</span> sendEventWithName:<span class="hljs-string">@"EventReminder"</span> body:@{<span class="hljs-string">@"name"</span>: eventName}];
}
<span class="hljs-keyword">@end</span>
</code></pre>
<p>JavaScript code can subscribe to these events by creating a new <code>NativeEventEmitter</code> instance around your module.</p>
<pre><code class="hljs css language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> NativeEventEmitter<span class="token punctuation">,</span> NativeModules <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> CalendarManager <span class="token punctuation">}</span> <span class="token operator">=</span> NativeModules<span class="token punctuation">;</span>
<span class="token keyword">const</span> calendarManagerEmitter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">NativeEventEmitter</span><span class="token punctuation">(</span>CalendarManager<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> subscription <span class="token operator">=</span> calendarManagerEmitter<span class="token punctuation">.</span><span class="token function">addListener</span><span class="token punctuation">(</span>
<span class="token string">'EventReminder'</span><span class="token punctuation">,</span>
<span class="token punctuation">(</span><span class="token parameter">reminder</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>reminder<span class="token punctuation">.</span>name<span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token operator">...</span>
<span class="token comment">// Don't forget to unsubscribe, typically in componentWillUnmount</span>
subscription<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>For more examples of sending events to JavaScript, see <a href="https://github.com/facebook/react-native/blob/master/Libraries/Geolocation/RCTLocationObserver.m"><code>RCTLocationObserver</code></a>.</p>
<h3><a class="anchor" aria-hidden="true" id="optimizing-for-zero-listeners"></a><a href="#optimizing-for-zero-listeners" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Optimizing for zero listeners</h3>
<p>You will receive a warning if you expend resources unnecessarily by emitting an event while there are no listeners. To avoid this, and to optimize your module's workload (e.g. by unsubscribing from upstream notifications or pausing background tasks), you can override <code>startObserving</code> and <code>stopObserving</code> in your <code>RCTEventEmitter</code> subclass.</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">CalendarManager</span></span>
{
<span class="hljs-keyword">bool</span> hasListeners;
}
<span class="hljs-comment">// Will be called when this module's first listener is added.</span>
-(<span class="hljs-keyword">void</span>)startObserving {
hasListeners = <span class="hljs-literal">YES</span>;
<span class="hljs-comment">// Set up any upstream listeners or background tasks as necessary</span>
}
<span class="hljs-comment">// Will be called when this module's last listener is removed, or on dealloc.</span>
-(<span class="hljs-keyword">void</span>)stopObserving {
hasListeners = <span class="hljs-literal">NO</span>;
<span class="hljs-comment">// Remove upstream listeners, stop unnecessary background tasks</span>
}
- (<span class="hljs-keyword">void</span>)calendarEventReminderReceived:(<span class="hljs-built_in">NSNotification</span> *)notification
{
<span class="hljs-built_in">NSString</span> *eventName = notification.userInfo[<span class="hljs-string">@"name"</span>];
<span class="hljs-keyword">if</span> (hasListeners) { <span class="hljs-comment">// Only send events if anyone is listening</span>
[<span class="hljs-keyword">self</span> sendEventWithName:<span class="hljs-string">@"EventReminder"</span> body:@{<span class="hljs-string">@"name"</span>: eventName}];
}
}
</code></pre>
<h2><a class="anchor" aria-hidden="true" id="exporting-swift"></a><a href="#exporting-swift" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Exporting Swift</h2>
<p>Swift doesn't have support for macros so exposing it to React Native requires a bit more setup but works relatively the same.</p>
<p>Let's say we have the same <code>CalendarManager</code> but as a Swift class:</p>
<pre><code class="hljs css language-swift"><span class="hljs-comment">// CalendarManager.swift</span>
<span class="hljs-meta">@objc</span>(<span class="hljs-type">CalendarManager</span>)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CalendarManager</span>: <span class="hljs-title">NSObject</span> </span>{
<span class="hljs-meta">@objc</span>(addEvent:location:date:)
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">addEvent</span><span class="hljs-params">(name: String, location: String, date: NSNumber)</span></span> -> <span class="hljs-type">Void</span> {
<span class="hljs-comment">// Date is ready to use!</span>
}
<span class="hljs-meta">@objc</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">constantsToExport</span><span class="hljs-params">()</span></span> -> [<span class="hljs-type">String</span>: <span class="hljs-type">Any</span>]! {
<span class="hljs-keyword">return</span> [<span class="hljs-string">"someKey"</span>: <span class="hljs-string">"someValue"</span>]
}
}
</code></pre>
<blockquote>
<p><strong>NOTE</strong>: It is important to use the @objc modifiers to ensure the class and functions are exported properly to the Objective-C runtime.</p>
</blockquote>
<p>Then create a private implementation file that will register the required information with the React Native bridge:</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-comment">// CalendarManagerBridge.m</span>
<span class="hljs-meta">#import <span class="hljs-meta-string"><React/RCTBridgeModule.h></span></span>
<span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">RCT_EXTERN_MODULE</span>(<span class="hljs-title">CalendarManager</span>, <span class="hljs-title">NSObject</span>)</span>
RCT_EXTERN_METHOD(addEvent:(<span class="hljs-built_in">NSString</span> *)name location:(<span class="hljs-built_in">NSString</span> *)location date:(<span class="hljs-keyword">nonnull</span> <span class="hljs-built_in">NSNumber</span> *)date)
<span class="hljs-keyword">@end</span>
</code></pre>
<p>For those of you new to Swift and Objective-C, whenever you <a href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html">mix the two languages in an iOS project</a>, you will also need an additional bridging file, known as a bridging header, to expose the Objective-C files to Swift. Xcode will offer to create this header file for you if you add your Swift file to your app through the Xcode <code>File>New File</code> menu option. You will need to import <code>RCTBridgeModule.h</code> in this header file.</p>
<pre><code class="hljs css language-objectivec"><span class="hljs-comment">// CalendarManager-Bridging-Header.h</span>
<span class="hljs-meta">#import <span class="hljs-meta-string"><React/RCTBridgeModule.h></span></span>
</code></pre>
<p>You can also use <code>RCT_EXTERN_REMAP_MODULE</code> and <code>_RCT_EXTERN_REMAP_METHOD</code> to alter the JavaScript name of the module or methods you are exporting. For more information see <a href="https://github.com/facebook/react-native/blob/master/React/Base/RCTBridgeModule.h"><code>RCTBridgeModule</code></a>.</p>
<blockquote>
<p><strong>Important when making third party modules</strong>: Static libraries with Swift are only supported in Xcode 9 and later. In order for the Xcode project to build when you use Swift in the iOS static library you include in the module, your main app project must contain Swift code and a bridging header itself. If your app project does not contain any Swift code, a workaround can be a single empty .swift file and an empty bridging header.</p>
</blockquote>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/0.23/native-modules-setup"><span class="arrow-prev">← </span><span>Native Modules Setup</span></a><a class="docs-next button" href="/docs/0.23/native-components-ios"><span>Native UI Components</span><span class="arrow-next"> →</span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#native-module-setup">Native Module Setup</a></li><li><a href="#ios-calendar-module-example">iOS Calendar Module Example</a></li><li><a href="#argument-types">Argument Types</a></li><li><a href="#callbacks">Callbacks</a></li><li><a href="#promises">Promises</a></li><li><a href="#threading">Threading</a></li><li><a href="#dependency-injection">Dependency Injection</a></li><li><a href="#exporting-constants">Exporting Constants</a><ul class="toc-headings"><li><a href="#implementing--requiresmainqueuesetup">Implementing <code>+ requiresMainQueueSetup</code></a></li><li><a href="#enum-constants">Enum Constants</a></li></ul></li><li><a href="#sending-events-to-javascript">Sending Events to JavaScript</a><ul class="toc-headings"><li><a href="#optimizing-for-zero-listeners">Optimizing for zero listeners</a></li></ul></li><li><a href="#exporting-swift">Exporting Swift</a></li></ul></nav></div><footer class="nav-footer" id="footer"><section class="sitemap"><div><h5>Docs</h5><a href="/docs/getting-started">Getting Started</a><a href="/docs/tutorial">Tutorial</a><a href="/docs/components-and-apis">Components and APIs</a><a href="/docs/more-resources">More Resources</a></div><div><h5>Community</h5><a href="/help">The React Native Community</a><a href="/showcase">Who's using React Native?</a><a href="https://stackoverflow.com/questions/tagged/react-native" target="_blank">Ask Questions on Stack Overflow</a><a href="https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md">Contributor Guide</a><a href="https://dev.to/t/reactnative" target="_blank">DEV Community</a></div><div><h5>More Resources</h5><a href="/blog">Blog</a><a href="https://twitter.com/reactnative" target="_blank">Twitter</a><a href="https://github.com/facebook/react-native" target="_blank">GitHub</a><a href="https://reactjs.org" target="_blank">React</a></div></section><a href="https://code.facebook.com/projects/" target="_blank" class="fbOpenSource"><img src="/img/oss_logo.png" alt="Facebook Open Source" width="170" height="45"/></a><section class="copyright">Copyright © 2020 Facebook Inc.</section></footer></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script><script>window.fbAsyncInit = function() {FB.init({appId:'1677033832619985',xfbml:true,version:'v2.7'});};(function(d, s, id){var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) {return;}js = d.createElement(s); js.id = id;js.src = '//connect.facebook.net/en_US/sdk.js';fjs.parentNode.insertBefore(js, fjs);}(document, 'script','facebook-jssdk'));
</script><script>window.twttr=(function(d,s, id){var js,fjs=d.getElementsByTagName(s)[0],t=window.twttr||{};if(d.getElementById(id))return t;js=d.createElement(s);js.id=id;js.src='https://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js, fjs);t._e = [];t.ready = function(f) {t._e.push(f);};return t;}(document, 'script', 'twitter-wjs'));</script><script>
document.addEventListener('keyup', function(e) {
if (e.target !== document.body) {
return;
}
// keyCode for '/' (slash)
if (e.keyCode === 191) {
const search = document.getElementById('search_input_react');
search && search.focus();
}
});
</script><script>
var search = docsearch({
apiKey: '2c98749b4a1e588efec53b2acec13025',
indexName: 'react-native-versions',
inputSelector: '#search_input_react',
algoliaOptions: {"facetFilters":["tags:0.23"],"hitsPerPage":5}
});
</script></body></html>