/
bridge.js
149 lines (129 loc) · 3.99 KB
/
bridge.js
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
const Event_Camera_Roll = 'cameraRoll'
const Event_Camera = 'camera'
const Event_Push_Notification = 'pushNotifications'
const validateWebView = (webview) => {
if (!webview) {
throw new Error('Webview should be setup to use React Native Wrapper from RN side.')
}
}
/**
* (PWA) sends a message to React Native
*
* @param { string } event a string for the event. It is what is used to match the event handler on the other React Native side.
* @param { object } data any extra data or options to be passed to the React Native side
*/
const sendToReactNative = function (event, data = {}) {
if (!isReactNative()) return;
window && window.postMessage(JSON.stringify({ event, data }));
}
/**
* (PWA) Registers to events coming from React Native. It augments the functionality
* by (trying to) parse the message into JSON for convenience
*
* @param {Function} func function to be called when the event is triggered from the React Native side
*/
const listenToReactNative = func => {
if (!isReactNative()) return
if (!window) {
throw new Error('Window object not found.')
}
window.receivedMessageFromReactNative = data => {
try {
const parsedData = JSON.parse(data)
func(parsedData)
} catch (err) {
console.warn(`Data received from React Native is not valid JSON. ${data}`)
func(data)
}
}
}
/**
* (PWA) to unregister from listening to messages from React Native
* typically add it componentWillUnmount()
*/
const unlistenToReactNative = function () {
if (!isReactNative()) return;
if (!window) {
throw new Error('Window object not found.')
}
delete window.receivedMessageFromReactNative
}
/**
* Alias to sendToReactNative passing Event_Camera_Roll
*/
const openCameraRoll = function () {
return sendToReactNative(Event_Camera_Roll)
}
/**
* Alias to sendToReactNative passing Event_Camera
*/
const openCamera = function () {
return sendToReactNative(Event_Camera)
}
/**
* (PWA) Helper method to check if the PWA is loaded inside React Native or just in a web browser
*/
const isReactNative = () => {
const isReactNative =
!!(
window &&
window.webkit &&
window.webkit.messageHandlers &&
window.webkit.messageHandlers.reactNative
) || !!window.originalPostMessage
console.warn(`IsReactNative ${isReactNative}`)
return isReactNative
}
/**
* (React Native) sets up the event handlers on React Native side so that
* when a PWA posts a message with { event: "event_name" } then
* the function defined here (the one mapped to "event_name") will be triggered
*
* @param {hashmap} eventMap map of event names to event handlers
*/
const handleMessages = (eventMap) => {
return e => {
if (e && e.nativeEvent && e.nativeEvent.data) {
const eventData = typeof e.nativeEvent.data === 'string' ? JSON.parse(e.nativeEvent.data): e.nativeEvent.data
const { event, data } = eventData
if (event && eventMap[event]) {
return eventMap[event](data)
} else {
console.warn(`no handler for event: "${event}"`)
}
}
}
}
/**
* (React Native) sends some data back to the PWA, for example, after photos
* are selected in a Camera Roll in the native side, those photos can be sent back
* to the PWA
*
* @param { WKWebView } webview references the webview in React Native
* @param { string } event the event name
* @param {*} data the data to send back to the PWA
*/
const sendToWebView = (webview, event, data) => {
validateWebView(webview)
const message = JSON.stringify({
event,
data
})
const func = webview.evaluateJavaScript || webview.injectJavaScript
func(`receivedMessageFromReactNative('${message}')`)
}
module.exports = {
Event_Camera_Roll,
Event_Camera,
Event_Push_Notification,
/* From PWA to React Native */
sendToReactNative,
listenToReactNative,
unlistenToReactNative,
openCamera,
openCameraRoll,
isReactNative,
/* From React Native to PWA */
handleMessages,
sendToWebView
}