partner_react_native_sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/helpers/ServiceNames.js +3 -0
- package/lib/module/helpers/ServiceNames.js.map +1 -1
- package/lib/module/helpers/analytics/analytics_event_model.js +37 -0
- package/lib/module/helpers/analytics/analytics_event_model.js.map +1 -0
- package/lib/module/helpers/analytics/analytics_logger.js +72 -0
- package/lib/module/helpers/analytics/analytics_logger.js.map +1 -0
- package/lib/module/helpers/analytics/event_storage.js +35 -0
- package/lib/module/helpers/analytics/event_storage.js.map +1 -0
- package/lib/module/helpers/partner_library_react_native.js +23 -2
- package/lib/module/helpers/partner_library_react_native.js.map +1 -1
- package/lib/module/helpers/webview.js +31 -10
- package/lib/module/helpers/webview.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/helpers/ServiceNames.d.ts +1 -0
- package/lib/typescript/src/helpers/ServiceNames.d.ts.map +1 -1
- package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts +16 -0
- package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts.map +1 -0
- package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts +17 -0
- package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts.map +1 -0
- package/lib/typescript/src/helpers/analytics/event_storage.d.ts +8 -0
- package/lib/typescript/src/helpers/analytics/event_storage.d.ts.map +1 -0
- package/lib/typescript/src/helpers/partner_library_react_native.d.ts +1 -0
- package/lib/typescript/src/helpers/partner_library_react_native.d.ts.map +1 -1
- package/lib/typescript/src/helpers/webview.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -5
- package/src/helpers/ServiceNames.tsx +4 -0
- package/src/helpers/analytics/analytics_event_model.tsx +47 -0
- package/src/helpers/analytics/analytics_logger.tsx +90 -0
- package/src/helpers/analytics/event_storage.tsx +44 -0
- package/src/helpers/partner_library_react_native.tsx +26 -4
- package/src/helpers/webview.tsx +346 -306
- package/src/index.tsx +2 -1
- package/lib/typescript/package.json +0 -1
package/src/helpers/webview.tsx
CHANGED
|
@@ -1,231 +1,260 @@
|
|
|
1
1
|
import { WebView as RNWebView } from 'react-native-webview';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
BackHandler,
|
|
4
|
+
Platform,
|
|
5
|
+
Linking,
|
|
6
|
+
SafeAreaView,
|
|
7
|
+
ActivityIndicator,
|
|
8
|
+
View,
|
|
9
|
+
ToastAndroid,
|
|
10
|
+
StatusBar,
|
|
11
11
|
} from 'react-native';
|
|
12
12
|
import { useEffect, useRef, useState } from 'react';
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
import {
|
|
15
|
+
type WebViewProps,
|
|
16
|
+
type WebViewNavigation,
|
|
17
|
+
} from 'react-native-webview';
|
|
18
|
+
import {
|
|
19
|
+
WebViewCallback,
|
|
20
|
+
type WebViewCallbackFunction,
|
|
21
|
+
} from './utils/webviewCallback';
|
|
22
|
+
import {
|
|
23
|
+
check,
|
|
24
|
+
PERMISSIONS,
|
|
25
|
+
request,
|
|
26
|
+
RESULTS,
|
|
27
|
+
type Permission,
|
|
28
|
+
} from 'react-native-permissions';
|
|
17
29
|
import FileViewer from 'react-native-file-viewer';
|
|
18
30
|
import RNFS from 'react-native-fs';
|
|
19
31
|
import CookieManager from '@react-native-cookies/cookies';
|
|
32
|
+
import { AnalyticsLogger } from './analytics/analytics_logger';
|
|
20
33
|
|
|
21
34
|
interface ExtendedWebViewProps extends WebViewProps {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
onPermissionRequest?: (event: any) => void;
|
|
36
|
+
androidPermissions?: {
|
|
37
|
+
camera?: boolean;
|
|
38
|
+
microphone?: boolean;
|
|
39
|
+
geolocation?: boolean;
|
|
40
|
+
};
|
|
28
41
|
}
|
|
29
42
|
interface WebViewCustomProps {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
url: string;
|
|
44
|
+
options?: Partial<ExtendedWebViewProps>;
|
|
45
|
+
onCallback?: WebViewCallbackFunction;
|
|
46
|
+
hostName?: string;
|
|
47
|
+
whitelistedUrls?: string[];
|
|
48
|
+
onPageFinished?: () => void;
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
export const WebView = ({
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
url,
|
|
53
|
+
options,
|
|
54
|
+
onCallback,
|
|
55
|
+
hostName,
|
|
56
|
+
whitelistedUrls = [],
|
|
57
|
+
onPageFinished,
|
|
45
58
|
}: WebViewCustomProps) => {
|
|
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
|
-
const fileName = `${timestamp}.${fileExt}`;
|
|
106
|
-
|
|
107
|
-
const downloadPath = Platform.select({
|
|
108
|
-
ios: `${RNFS.DocumentDirectoryPath}/${fileName}`,
|
|
109
|
-
android: `${RNFS.DownloadDirectoryPath}/${fileName}`
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
if (!downloadPath) {
|
|
113
|
-
throw new Error('Could not determine download path');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
console.log('Downloading to:', downloadPath);
|
|
117
|
-
|
|
118
|
-
const options = {
|
|
119
|
-
fromUrl: fileUrl,
|
|
120
|
-
toFile: downloadPath,
|
|
121
|
-
headers: {
|
|
122
|
-
'Cookie': cookieString,
|
|
123
|
-
'Accept': 'application/pdf',
|
|
124
|
-
'Content-Type': 'application/pdf'
|
|
125
|
-
},
|
|
126
|
-
background: true,
|
|
127
|
-
begin: (res: any) => {
|
|
128
|
-
console.log('Download started with headers:', res);
|
|
129
|
-
},
|
|
130
|
-
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const response = await RNFS.downloadFile(options).promise;
|
|
134
|
-
|
|
135
|
-
if (response.statusCode === 200) {
|
|
136
|
-
console.log('File downloaded to:', downloadPath);
|
|
137
|
-
|
|
138
|
-
if (Platform.OS === 'android') {
|
|
139
|
-
ToastAndroid.show('File downloaded successfully', ToastAndroid.SHORT);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
await FileViewer.open(downloadPath, {
|
|
143
|
-
showOpenWithDialog: true,
|
|
144
|
-
onDismiss: () => {
|
|
145
|
-
if (Platform.OS === 'ios') {
|
|
146
|
-
RNFS.unlink(downloadPath).catch(console.error);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
} else {
|
|
151
|
-
throw new Error(`Download failed with status ${response.statusCode}`);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
} catch (error) {
|
|
155
|
-
console.error('File download/open error:', error);
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const handleOnShouldStartLoadWithRequest = (event: WebViewNavigation) => {
|
|
162
|
-
const { url } = event;
|
|
163
|
-
console.log('URL:', url);
|
|
164
|
-
if (url === 'about:blank' || url === 'about:srcdoc') {
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (url?.includes('/session-expired?status=') || url?.includes("/redirect?status=")) {
|
|
170
|
-
const status = getQueryParam(url, 'status');
|
|
59
|
+
const webviewRef = useRef<RNWebView | null>(null);
|
|
60
|
+
const [canGoBack, setCanGoBack] = useState(false);
|
|
61
|
+
const _analyticsLogger = new AnalyticsLogger();
|
|
62
|
+
// const [hasRedirected, setHasRedirected] = useState(false);
|
|
63
|
+
const [, setToast] = useState<{ visible: boolean; message: string } | null>(
|
|
64
|
+
null
|
|
65
|
+
);
|
|
66
|
+
const handleExternalUrl = async (url: string) => {
|
|
67
|
+
try {
|
|
68
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
69
|
+
await Linking.openURL(url);
|
|
70
|
+
// _analyticsLogger.logEvent({ event: 'REACT_NATIVE_OPEN_URL_EXTERNALLY' });
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// Implement your toast here
|
|
73
|
+
if (Platform.OS === 'android') {
|
|
74
|
+
ToastAndroid.show(
|
|
75
|
+
'Oops! Something went wrong. Please try again.',
|
|
76
|
+
ToastAndroid.LONG
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
console.log('Application not found to open link');
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const showToast_with_code_message = (syntheticEvent: any) => {
|
|
83
|
+
const { nativeEvent } = syntheticEvent;
|
|
84
|
+
const errorCodesToHandle = [-6, -8, -10];
|
|
85
|
+
if (errorCodesToHandle.includes(nativeEvent.code)) {
|
|
86
|
+
const message = `WebView Error: [${nativeEvent.code}] ${nativeEvent.description}`;
|
|
87
|
+
setToast({ visible: true, message });
|
|
88
|
+
if (Platform.OS === 'android') {
|
|
89
|
+
ToastAndroid.show(
|
|
90
|
+
'Oops! Something went wrong. Please try again.',
|
|
91
|
+
ToastAndroid.LONG
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
setTimeout(() => setToast(null), 5000);
|
|
95
|
+
onCallback?.(WebViewCallback.redirect('WEBVIEW_ERROR'));
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const getQueryParam = (url: string, param: string): string | null => {
|
|
100
|
+
const match = url.match(new RegExp('[?&]' + param + '=([^&#]*)'));
|
|
101
|
+
return match && match[1] ? decodeURIComponent(match[1]) : null;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const downloadAndOpenFile = async (fileUrl: string) => {
|
|
105
|
+
try {
|
|
106
|
+
console.log('Starting file download...', fileUrl);
|
|
107
|
+
|
|
108
|
+
// Get cookies using CookieManager
|
|
109
|
+
let cookieString = '';
|
|
110
|
+
try {
|
|
111
|
+
const cookies = await CookieManager.get(fileUrl);
|
|
112
|
+
cookieString = Object.keys(cookies)
|
|
113
|
+
.map((key) => `${key}=${cookies[key]?.value ?? ''}`)
|
|
114
|
+
.join('; ');
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.error('Failed to get cookies:', e);
|
|
117
|
+
}
|
|
171
118
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
119
|
+
// Create a clean filename from the URL
|
|
120
|
+
const timestamp = new Date().getTime();
|
|
121
|
+
// Extract only the last part of the path for the filename
|
|
122
|
+
const urlParts = fileUrl.split('/');
|
|
123
|
+
const lastPart = urlParts[urlParts.length - 1];
|
|
124
|
+
const fileExt = lastPart?.split('.').pop() || 'pdf';
|
|
125
|
+
const fileName = `${timestamp}.${fileExt}`;
|
|
126
|
+
|
|
127
|
+
const downloadPath = Platform.select({
|
|
128
|
+
ios: `${RNFS.DocumentDirectoryPath}/${fileName}`,
|
|
129
|
+
android: `${RNFS.DownloadDirectoryPath}/${fileName}`,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (!downloadPath) {
|
|
133
|
+
throw new Error('Could not determine download path');
|
|
134
|
+
}
|
|
180
135
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
136
|
+
console.log('Downloading to:', downloadPath);
|
|
137
|
+
|
|
138
|
+
const options = {
|
|
139
|
+
fromUrl: fileUrl,
|
|
140
|
+
toFile: downloadPath,
|
|
141
|
+
headers: {
|
|
142
|
+
'Cookie': cookieString,
|
|
143
|
+
'Accept': 'application/pdf',
|
|
144
|
+
'Content-Type': 'application/pdf',
|
|
145
|
+
},
|
|
146
|
+
background: true,
|
|
147
|
+
begin: (res: any) => {
|
|
148
|
+
console.log('Download started with headers:', res);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const response = await RNFS.downloadFile(options).promise;
|
|
153
|
+
|
|
154
|
+
if (response.statusCode === 200) {
|
|
155
|
+
console.log('File downloaded to:', downloadPath);
|
|
156
|
+
|
|
157
|
+
if (Platform.OS === 'android') {
|
|
158
|
+
ToastAndroid.show('File downloaded successfully', ToastAndroid.SHORT);
|
|
200
159
|
}
|
|
201
160
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
161
|
+
await FileViewer.open(downloadPath, {
|
|
162
|
+
showOpenWithDialog: true,
|
|
163
|
+
onDismiss: () => {
|
|
164
|
+
if (Platform.OS === 'ios') {
|
|
165
|
+
RNFS.unlink(downloadPath).catch(console.error);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
} else {
|
|
170
|
+
throw new Error(`Download failed with status ${response.statusCode}`);
|
|
171
|
+
}
|
|
172
|
+
} catch (error) {
|
|
173
|
+
console.error('File download/open error:', error);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const handleOnShouldStartLoadWithRequest = (event: WebViewNavigation) => {
|
|
178
|
+
const { url } = event;
|
|
179
|
+
console.log('URL:', url);
|
|
180
|
+
if (url === 'about:blank' || url === 'about:srcdoc') {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
// _analyticsLogger.logEvent({ event: 'REACT_NATIVE_LOADING_URL ', url });
|
|
184
|
+
|
|
185
|
+
if (
|
|
186
|
+
url?.includes('/session-expired?status=') ||
|
|
187
|
+
url?.includes('/redirect?status=')
|
|
188
|
+
) {
|
|
189
|
+
console.log('overriding url');
|
|
190
|
+
const status = getQueryParam(url, 'status');
|
|
191
|
+
|
|
192
|
+
console.log('Status thrown from webview ', status);
|
|
193
|
+
// _analyticsLogger.logEvent({
|
|
194
|
+
// event: 'REACT_NATIVE_WEBVIEW_CALLBACK ',
|
|
195
|
+
// status,
|
|
196
|
+
// });
|
|
197
|
+
|
|
198
|
+
StatusBar.setBackgroundColor('#7E7E7EFF');
|
|
199
|
+
onCallback?.(WebViewCallback.redirect(status ?? undefined));
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Handle whitelisted URLs
|
|
204
|
+
const isWhitelisted =
|
|
205
|
+
whitelistedUrls.some((white) => url.includes(white)) ||
|
|
206
|
+
(hostName && url.includes(hostName));
|
|
207
|
+
|
|
208
|
+
if (
|
|
209
|
+
!isWhitelisted &&
|
|
210
|
+
url &&
|
|
211
|
+
url !== 'about:blank' &&
|
|
212
|
+
url !== 'about:srcdoc'
|
|
213
|
+
) {
|
|
214
|
+
console.log('External URL detected:', url);
|
|
215
|
+
handleExternalUrl(url);
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
if (
|
|
219
|
+
url.includes('.pdf') ||
|
|
220
|
+
url.includes('/statements/') ||
|
|
221
|
+
url.includes('/download_statements')
|
|
222
|
+
) {
|
|
223
|
+
console.log('File download URL detected:', url);
|
|
224
|
+
downloadAndOpenFile(url);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return true;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const handleBackButton = () => {
|
|
232
|
+
if (canGoBack && webviewRef.current) {
|
|
233
|
+
webviewRef.current.goBack();
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
const backHandler = BackHandler.addEventListener(
|
|
241
|
+
'hardwareBackPress',
|
|
242
|
+
handleBackButton
|
|
243
|
+
);
|
|
244
|
+
return () => {
|
|
245
|
+
backHandler.remove();
|
|
211
246
|
};
|
|
247
|
+
}, [canGoBack]);
|
|
212
248
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}, [canGoBack]);
|
|
219
|
-
|
|
220
|
-
const Loading = () => (
|
|
221
|
-
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
222
|
-
<ActivityIndicator size="large" />
|
|
223
|
-
</View>
|
|
224
|
-
);
|
|
249
|
+
const Loading = () => (
|
|
250
|
+
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
251
|
+
<ActivityIndicator size="large" />
|
|
252
|
+
</View>
|
|
253
|
+
);
|
|
225
254
|
|
|
226
|
-
|
|
255
|
+
// Cookie injection script
|
|
227
256
|
|
|
228
|
-
|
|
257
|
+
const injectedJavaScript = `
|
|
229
258
|
window.onerror = function(message, source, lineno, colno, error) {
|
|
230
259
|
if (message.includes('RATE_LIMIT_USER')) {
|
|
231
260
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
@@ -236,108 +265,119 @@ export const WebView = ({
|
|
|
236
265
|
true;
|
|
237
266
|
`;
|
|
238
267
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (result === RESULTS.DENIED) {
|
|
244
|
-
const requestResult = await request(permission);
|
|
245
|
-
return requestResult === RESULTS.GRANTED;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return result === RESULTS.GRANTED;
|
|
249
|
-
} catch (error) {
|
|
250
|
-
console.error('Permission request failed:', error);
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
const handlePermissionRequest = async (event: any) => {
|
|
256
|
-
const { resources } = event.nativeEvent;
|
|
257
|
-
console.log('Permission requested:', resources);
|
|
258
|
-
|
|
259
|
-
const permissionsToRequest: Permission[] = [];
|
|
268
|
+
const requestPermission = async (permission: Permission) => {
|
|
269
|
+
try {
|
|
270
|
+
const result = await check(permission);
|
|
260
271
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
: PERMISSIONS.ANDROID.CAMERA
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
if (resources.includes('microphone')) {
|
|
269
|
-
permissionsToRequest.push(
|
|
270
|
-
Platform.OS === 'ios'
|
|
271
|
-
? PERMISSIONS.IOS.MICROPHONE
|
|
272
|
-
: PERMISSIONS.ANDROID.RECORD_AUDIO
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
if (resources.includes('geolocation')) {
|
|
276
|
-
permissionsToRequest.push(
|
|
277
|
-
Platform.OS === 'ios'
|
|
278
|
-
? PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
|
|
279
|
-
: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION
|
|
280
|
-
);
|
|
281
|
-
}
|
|
272
|
+
if (result === RESULTS.DENIED) {
|
|
273
|
+
const requestResult = await request(permission);
|
|
274
|
+
return requestResult === RESULTS.GRANTED;
|
|
275
|
+
}
|
|
282
276
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
277
|
+
return result === RESULTS.GRANTED;
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.error('Permission request failed:', error);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const handlePermissionRequest = async (event: any) => {
|
|
285
|
+
const { resources } = event.nativeEvent;
|
|
286
|
+
console.log('Permission requested:', resources);
|
|
287
|
+
|
|
288
|
+
const permissionsToRequest: Permission[] = [];
|
|
289
|
+
|
|
290
|
+
if (resources.includes('video')) {
|
|
291
|
+
permissionsToRequest.push(
|
|
292
|
+
Platform.OS === 'ios'
|
|
293
|
+
? PERMISSIONS.IOS.CAMERA
|
|
294
|
+
: PERMISSIONS.ANDROID.CAMERA
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
if (resources.includes('microphone')) {
|
|
298
|
+
permissionsToRequest.push(
|
|
299
|
+
Platform.OS === 'ios'
|
|
300
|
+
? PERMISSIONS.IOS.MICROPHONE
|
|
301
|
+
: PERMISSIONS.ANDROID.RECORD_AUDIO
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
if (resources.includes('geolocation')) {
|
|
305
|
+
permissionsToRequest.push(
|
|
306
|
+
Platform.OS === 'ios'
|
|
307
|
+
? PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
|
|
308
|
+
: PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
try {
|
|
313
|
+
const results = await Promise.all(
|
|
314
|
+
permissionsToRequest.map((permission) => requestPermission(permission))
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const granted = results.every((result) => result === true);
|
|
318
|
+
if (granted) {
|
|
319
|
+
// @ts-ignore - grant exists on the event
|
|
320
|
+
event.nativeEvent.grant();
|
|
321
|
+
} else {
|
|
322
|
+
// @ts-ignore - deny exists on the event
|
|
323
|
+
event.nativeEvent.deny();
|
|
324
|
+
}
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error('Permission handling failed:', error);
|
|
327
|
+
// @ts-ignore - deny exists on the event
|
|
328
|
+
event.nativeEvent.deny();
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const handleWebViewLoadEnd = (syntheticEvent: any) => {
|
|
333
|
+
const loadedUrl = syntheticEvent?.nativeEvent?.url || url;
|
|
334
|
+
// _analyticsLogger.logEvent({
|
|
335
|
+
// event: 'REACT_NATIVE_WEBVIEW_LOADED',
|
|
336
|
+
// url: loadedUrl,
|
|
337
|
+
// });
|
|
338
|
+
|
|
339
|
+
onPageFinished?.();
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
return (
|
|
343
|
+
<SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
|
|
344
|
+
<RNWebView
|
|
345
|
+
ref={webviewRef}
|
|
346
|
+
source={{ uri: url }}
|
|
347
|
+
onPermissionRequest={
|
|
348
|
+
handlePermissionRequest as ExtendedWebViewProps['onPermissionRequest']
|
|
300
349
|
}
|
|
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
|
-
sharedCookiesEnabled={true}
|
|
336
|
-
setSupportMultipleWindows={false}
|
|
337
|
-
mixedContentMode="always"
|
|
338
|
-
allowsLinkPreview={true}
|
|
339
|
-
{...options}
|
|
340
|
-
/>
|
|
341
|
-
</SafeAreaView>
|
|
342
|
-
);
|
|
343
|
-
};
|
|
350
|
+
geolocationEnabled={true}
|
|
351
|
+
androidPermissions={{
|
|
352
|
+
camera: true,
|
|
353
|
+
microphone: true,
|
|
354
|
+
geolocation: true,
|
|
355
|
+
}}
|
|
356
|
+
onError={(e) => {
|
|
357
|
+
showToast_with_code_message(e);
|
|
358
|
+
options?.onError?.(e as any);
|
|
359
|
+
}}
|
|
360
|
+
{...options}
|
|
361
|
+
startInLoadingState={true}
|
|
362
|
+
renderLoading={() => <Loading />}
|
|
363
|
+
onLoadEnd={handleWebViewLoadEnd}
|
|
364
|
+
originWhitelist={['*']}
|
|
365
|
+
javaScriptEnabled={true}
|
|
366
|
+
domStorageEnabled={true}
|
|
367
|
+
mediaPlaybackRequiresUserAction={false}
|
|
368
|
+
allowsInlineMediaPlayback={true}
|
|
369
|
+
onShouldStartLoadWithRequest={handleOnShouldStartLoadWithRequest}
|
|
370
|
+
onNavigationStateChange={(navState) => {
|
|
371
|
+
setCanGoBack(navState.canGoBack);
|
|
372
|
+
}}
|
|
373
|
+
injectedJavaScript={injectedJavaScript}
|
|
374
|
+
decelerationRate={Platform.OS === 'ios' ? 'normal' : 0.9}
|
|
375
|
+
allowsBackForwardNavigationGestures={Platform.OS === 'ios'}
|
|
376
|
+
sharedCookiesEnabled={true}
|
|
377
|
+
setSupportMultipleWindows={false}
|
|
378
|
+
mixedContentMode="always"
|
|
379
|
+
allowsLinkPreview={true}
|
|
380
|
+
/>
|
|
381
|
+
</SafeAreaView>
|
|
382
|
+
);
|
|
383
|
+
};
|