@exodus/react-native-webview 11.26.1-exodus.9 → 13.16.0-exodus.1
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/README.md +36 -63
- package/android/build.gradle +83 -110
- package/android/gradle.properties +3 -4
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/AndroidManifestNew.xml +26 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java +11 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +407 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +468 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +330 -0
- package/android/src/main/java/com/reactnativecommunity/webview/{WebViewConfig.java → RNCWebViewConfig.java} +3 -4
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +1 -1
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +746 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMessagingModule.kt +9 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java +554 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +57 -12
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewWrapper.kt +39 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/SubResourceErrorEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt +24 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopNewWindowEvent.kt +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +25 -0
- package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +570 -0
- package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java +57 -0
- package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +341 -0
- package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java +59 -0
- package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
- package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
- package/apple/RNCWebView.h +26 -100
- package/apple/RNCWebView.mm +555 -0
- package/apple/RNCWebViewDecisionManager.h +20 -0
- package/apple/RNCWebViewDecisionManager.m +47 -0
- package/apple/RNCWebViewImpl.h +164 -0
- package/apple/{RNCWebView.m → RNCWebViewImpl.m} +802 -225
- package/apple/RNCWebViewManager.h +4 -8
- package/apple/RNCWebViewManager.mm +221 -0
- package/apple/RNCWebViewModule.h +23 -0
- package/apple/RNCWebViewModule.mm +34 -0
- package/index.d.ts +2 -3
- package/lib/NativeRNCWebViewModule.d.ts +8 -0
- package/lib/NativeRNCWebViewModule.js +1 -0
- package/lib/RNCWebViewNativeComponent.d.ts +245 -0
- package/lib/RNCWebViewNativeComponent.js +1 -0
- package/lib/WebView.android.d.ts +0 -1
- package/lib/WebView.android.js +1 -135
- package/lib/WebView.d.ts +2 -3
- package/lib/WebView.ios.d.ts +0 -1
- package/lib/WebView.ios.js +1 -114
- package/lib/WebView.js +1 -11
- package/lib/WebView.macos.d.ts +6 -0
- package/lib/WebView.macos.js +1 -0
- package/lib/WebView.styles.d.ts +37 -11
- package/lib/WebView.styles.js +1 -33
- package/lib/WebView.windows.d.ts +17 -0
- package/lib/WebView.windows.js +1 -0
- package/lib/WebViewNativeComponent.macos.d.ts +3 -0
- package/lib/WebViewNativeComponent.macos.js +1 -0
- package/lib/WebViewNativeComponent.windows.d.ts +3 -0
- package/lib/WebViewNativeComponent.windows.js +1 -0
- package/lib/WebViewShared.d.ts +30 -9
- package/lib/WebViewShared.js +1 -174
- package/lib/WebViewTypes.d.ts +514 -98
- package/lib/WebViewTypes.js +1 -6
- package/lib/index.d.ts +0 -1
- package/lib/index.js +1 -3
- package/lib/validation.d.ts +3 -0
- package/lib/validation.js +1 -0
- package/package.json +57 -33
- package/react-native-webview.podspec +32 -5
- package/react-native.config.js +22 -18
- package/src/NativeRNCWebViewModule.ts +13 -0
- package/src/RNCWebViewNativeComponent.ts +348 -0
- package/src/WebView.android.tsx +345 -0
- package/src/WebView.ios.tsx +341 -0
- package/src/WebView.macos.tsx +252 -0
- package/src/WebView.styles.ts +41 -0
- package/src/WebView.tsx +25 -0
- package/src/WebView.windows.tsx +217 -0
- package/src/WebViewNativeComponent.macos.ts +7 -0
- package/src/WebViewNativeComponent.windows.ts +8 -0
- package/src/WebViewShared.tsx +476 -0
- package/src/WebViewTypes.ts +1402 -0
- package/src/__tests__/WebViewShared-test.js +323 -0
- package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
- package/src/__tests__/validation-test.js +38 -0
- package/src/index.ts +4 -0
- package/src/validation.ts +20 -0
- package/android/.editorconfig +0 -6
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +0 -1408
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java +0 -506
- package/apple/RNCWebViewManager.m +0 -278
- package/lib/WebViewNativeComponent.android.d.ts +0 -4
- package/lib/WebViewNativeComponent.android.js +0 -3
- package/lib/WebViewNativeComponent.ios.d.ts +0 -4
- package/lib/WebViewNativeComponent.ios.js +0 -3
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
package com.reactnativecommunity.webview
|
|
2
|
+
|
|
3
|
+
import android.app.DownloadManager
|
|
4
|
+
import android.content.pm.ActivityInfo
|
|
5
|
+
import android.graphics.Bitmap
|
|
6
|
+
import android.graphics.Color
|
|
7
|
+
import android.net.Uri
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import android.os.Environment
|
|
10
|
+
import android.util.Log
|
|
11
|
+
import android.view.View
|
|
12
|
+
import android.view.ViewGroup
|
|
13
|
+
import android.view.WindowManager
|
|
14
|
+
import android.webkit.CookieManager
|
|
15
|
+
import android.webkit.DownloadListener
|
|
16
|
+
import android.webkit.URLUtil
|
|
17
|
+
import android.webkit.WebSettings
|
|
18
|
+
import android.webkit.WebView
|
|
19
|
+
import androidx.webkit.WebSettingsCompat
|
|
20
|
+
import androidx.webkit.WebViewFeature
|
|
21
|
+
import com.facebook.react.bridge.ReadableArray
|
|
22
|
+
import com.facebook.react.bridge.ReadableMap
|
|
23
|
+
import com.facebook.react.common.MapBuilder
|
|
24
|
+
import com.facebook.react.common.build.ReactBuildConfig
|
|
25
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
26
|
+
import org.json.JSONException
|
|
27
|
+
import org.json.JSONObject
|
|
28
|
+
import java.io.UnsupportedEncodingException
|
|
29
|
+
import java.net.MalformedURLException
|
|
30
|
+
import java.net.URL
|
|
31
|
+
import java.util.HashSet
|
|
32
|
+
import java.util.Locale
|
|
33
|
+
|
|
34
|
+
val invalidCharRegex = "[\\\\/%\"]".toRegex()
|
|
35
|
+
|
|
36
|
+
class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
|
|
37
|
+
companion object {
|
|
38
|
+
const val NAME = "RNCWebView"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private val TAG = "RNCWebViewManagerImpl"
|
|
42
|
+
private var mWebViewConfig: RNCWebViewConfig = RNCWebViewConfig { webView: WebView? -> }
|
|
43
|
+
private var mAllowsFullscreenVideo = false
|
|
44
|
+
private var mAllowsProtectedMedia = false
|
|
45
|
+
private var mDownloadingMessage: String? = null
|
|
46
|
+
private var mLackPermissionToDownloadMessage: String? = null
|
|
47
|
+
private var mHasOnOpenWindowEvent = false
|
|
48
|
+
private var mPendingSource: ReadableMap? = null
|
|
49
|
+
|
|
50
|
+
private var mUserAgent: String? = null
|
|
51
|
+
private var mUserAgentWithApplicationName: String? = null
|
|
52
|
+
private val HTML_ENCODING = "UTF-8"
|
|
53
|
+
private val HTML_MIME_TYPE = "text/html"
|
|
54
|
+
private val HTTP_METHOD_POST = "POST"
|
|
55
|
+
|
|
56
|
+
// Use `webView.loadUrl("about:blank")` to reliably reset the view
|
|
57
|
+
// state and release page resources (including any running JavaScript).
|
|
58
|
+
private val BLANK_URL = "about:blank"
|
|
59
|
+
|
|
60
|
+
private val DEFAULT_DOWNLOADING_MESSAGE = "Downloading"
|
|
61
|
+
private val DEFAULT_LACK_PERMISSION_TO_DOWNLOAD_MESSAGE =
|
|
62
|
+
"Cannot download files as permission was denied. Please provide permission to write to storage, in order to download files."
|
|
63
|
+
|
|
64
|
+
fun createRNCWebViewInstance(context: ThemedReactContext): RNCWebView {
|
|
65
|
+
return RNCWebView(context)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fun createViewInstance(context: ThemedReactContext): RNCWebViewWrapper {
|
|
69
|
+
val webView = createRNCWebViewInstance(context)
|
|
70
|
+
return createViewInstance(context, webView);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fun createViewInstance(context: ThemedReactContext, webView: RNCWebView): RNCWebViewWrapper {
|
|
74
|
+
setupWebChromeClient(webView)
|
|
75
|
+
context.addLifecycleEventListener(webView)
|
|
76
|
+
mWebViewConfig.configWebView(webView)
|
|
77
|
+
val settings = webView.settings
|
|
78
|
+
settings.builtInZoomControls = true
|
|
79
|
+
settings.displayZoomControls = false
|
|
80
|
+
settings.domStorageEnabled = true
|
|
81
|
+
settings.setSupportMultipleWindows(true)
|
|
82
|
+
settings.allowFileAccess = false
|
|
83
|
+
settings.allowContentAccess = false
|
|
84
|
+
settings.allowFileAccessFromFileURLs = false
|
|
85
|
+
settings.allowUniversalAccessFromFileURLs = false
|
|
86
|
+
settings.mixedContentMode = WebSettings.MIXED_CONTENT_NEVER_ALLOW
|
|
87
|
+
|
|
88
|
+
// Fixes broken full-screen modals/galleries due to body height being 0.
|
|
89
|
+
webView.layoutParams = ViewGroup.LayoutParams(
|
|
90
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
91
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
92
|
+
)
|
|
93
|
+
if (ReactBuildConfig.DEBUG) {
|
|
94
|
+
WebView.setWebContentsDebuggingEnabled(true)
|
|
95
|
+
}
|
|
96
|
+
webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
|
|
97
|
+
val module = webView.reactApplicationContext.getNativeModule(RNCWebViewModule::class.java) ?: return@DownloadListener
|
|
98
|
+
val request: DownloadManager.Request = try {
|
|
99
|
+
DownloadManager.Request(Uri.parse(url))
|
|
100
|
+
} catch (e: IllegalArgumentException) {
|
|
101
|
+
Log.w(TAG, "Unsupported URI, aborting download", e)
|
|
102
|
+
return@DownloadListener
|
|
103
|
+
}
|
|
104
|
+
var fileName = URLUtil.guessFileName(url, contentDisposition, mimetype)
|
|
105
|
+
|
|
106
|
+
// Sanitize filename by replacing invalid characters with "_"
|
|
107
|
+
fileName = fileName.replace(invalidCharRegex, "_")
|
|
108
|
+
|
|
109
|
+
val downloadMessage = "Downloading $fileName"
|
|
110
|
+
|
|
111
|
+
//Attempt to add cookie, if it exists
|
|
112
|
+
var urlObj: URL? = null
|
|
113
|
+
try {
|
|
114
|
+
urlObj = URL(url)
|
|
115
|
+
val baseUrl = urlObj.protocol + "://" + urlObj.host
|
|
116
|
+
val cookie = CookieManager.getInstance().getCookie(baseUrl)
|
|
117
|
+
request.addRequestHeader("Cookie", cookie)
|
|
118
|
+
} catch (e: MalformedURLException) {
|
|
119
|
+
Log.w(TAG, "Error getting cookie for DownloadManager", e)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//Finish setting up request
|
|
123
|
+
request.addRequestHeader("User-Agent", userAgent)
|
|
124
|
+
request.setTitle(fileName)
|
|
125
|
+
request.setDescription(downloadMessage)
|
|
126
|
+
request.allowScanningByMediaScanner()
|
|
127
|
+
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
|
128
|
+
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
|
|
129
|
+
module.setDownloadRequest(request)
|
|
130
|
+
if (module.grantFileDownloaderPermissions(
|
|
131
|
+
getDownloadingMessageOrDefault(),
|
|
132
|
+
getLackPermissionToDownloadMessageOrDefault()
|
|
133
|
+
)
|
|
134
|
+
) {
|
|
135
|
+
module.downloadFile(
|
|
136
|
+
getDownloadingMessageOrDefault()
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
return RNCWebViewWrapper(context, webView)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private fun setupWebChromeClient(
|
|
144
|
+
webView: RNCWebView,
|
|
145
|
+
) {
|
|
146
|
+
val activity = webView.themedReactContext.currentActivity
|
|
147
|
+
if (mAllowsFullscreenVideo && activity != null) {
|
|
148
|
+
val initialRequestedOrientation = activity.requestedOrientation
|
|
149
|
+
val webChromeClient: RNCWebChromeClient =
|
|
150
|
+
object : RNCWebChromeClient(webView) {
|
|
151
|
+
override fun getDefaultVideoPoster(): Bitmap? {
|
|
152
|
+
return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
override fun onShowCustomView(view: View, callback: CustomViewCallback) {
|
|
156
|
+
if (mVideoView != null) {
|
|
157
|
+
callback.onCustomViewHidden()
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
mVideoView = view
|
|
161
|
+
mCustomViewCallback = callback
|
|
162
|
+
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
|
163
|
+
mVideoView.systemUiVisibility = FULLSCREEN_SYSTEM_UI_VISIBILITY
|
|
164
|
+
activity.window.setFlags(
|
|
165
|
+
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
|
166
|
+
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
|
|
167
|
+
)
|
|
168
|
+
mVideoView.setBackgroundColor(Color.BLACK)
|
|
169
|
+
|
|
170
|
+
// Since RN's Modals interfere with the View hierarchy
|
|
171
|
+
// we will decide which View to hide if the hierarchy
|
|
172
|
+
// does not match (i.e., the WebView is within a Modal)
|
|
173
|
+
// NOTE: We could use `mWebView.getRootView()` instead of `getRootView()`
|
|
174
|
+
// but that breaks the Modal's styles and layout, so we need this to render
|
|
175
|
+
// in the main View hierarchy regardless
|
|
176
|
+
val rootView = rootView
|
|
177
|
+
rootView.addView(mVideoView, FULLSCREEN_LAYOUT_PARAMS)
|
|
178
|
+
|
|
179
|
+
// Different root views, we are in a Modal
|
|
180
|
+
if (rootView.rootView !== mWebView.rootView) {
|
|
181
|
+
mWebView.rootView.visibility = View.GONE
|
|
182
|
+
} else {
|
|
183
|
+
// Same view hierarchy (no Modal), just hide the WebView then
|
|
184
|
+
mWebView.visibility = View.GONE
|
|
185
|
+
}
|
|
186
|
+
mWebView.themedReactContext.addLifecycleEventListener(this)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
override fun onHideCustomView() {
|
|
190
|
+
if (mVideoView == null) {
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Same logic as above
|
|
195
|
+
val rootView = rootView
|
|
196
|
+
if (rootView.rootView !== mWebView.rootView) {
|
|
197
|
+
mWebView.rootView.visibility = View.VISIBLE
|
|
198
|
+
} else {
|
|
199
|
+
// Same view hierarchy (no Modal)
|
|
200
|
+
mWebView.visibility = View.VISIBLE
|
|
201
|
+
}
|
|
202
|
+
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
|
203
|
+
rootView.removeView(mVideoView)
|
|
204
|
+
mCustomViewCallback.onCustomViewHidden()
|
|
205
|
+
mVideoView = null
|
|
206
|
+
mCustomViewCallback = null
|
|
207
|
+
activity.requestedOrientation = initialRequestedOrientation
|
|
208
|
+
mWebView.themedReactContext.removeLifecycleEventListener(this)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
webChromeClient.setAllowsProtectedMedia(mAllowsProtectedMedia);
|
|
212
|
+
webChromeClient.setHasOnOpenWindowEvent(mHasOnOpenWindowEvent);
|
|
213
|
+
webView.webChromeClient = webChromeClient
|
|
214
|
+
} else {
|
|
215
|
+
var webChromeClient = webView.webChromeClient as RNCWebChromeClient?
|
|
216
|
+
webChromeClient?.onHideCustomView()
|
|
217
|
+
webChromeClient = object : RNCWebChromeClient(webView) {
|
|
218
|
+
override fun getDefaultVideoPoster(): Bitmap? {
|
|
219
|
+
return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
webChromeClient.setAllowsProtectedMedia(mAllowsProtectedMedia);
|
|
223
|
+
webChromeClient.setHasOnOpenWindowEvent(mHasOnOpenWindowEvent);
|
|
224
|
+
webView.webChromeClient = webChromeClient
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
fun setUserAgent(viewWrapper: RNCWebViewWrapper, userAgent: String?) {
|
|
229
|
+
mUserAgent = userAgent
|
|
230
|
+
setUserAgentString(viewWrapper)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
fun setApplicationNameForUserAgent(viewWrapper: RNCWebViewWrapper, applicationName: String?) {
|
|
234
|
+
when {
|
|
235
|
+
applicationName != null -> {
|
|
236
|
+
val defaultUserAgent = WebSettings.getDefaultUserAgent(viewWrapper.webView.context)
|
|
237
|
+
mUserAgentWithApplicationName = "$defaultUserAgent $applicationName"
|
|
238
|
+
}
|
|
239
|
+
else -> {
|
|
240
|
+
mUserAgentWithApplicationName = null
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
setUserAgentString(viewWrapper)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private fun setUserAgentString(viewWrapper: RNCWebViewWrapper) {
|
|
247
|
+
val view = viewWrapper.webView
|
|
248
|
+
when {
|
|
249
|
+
mUserAgent != null -> {
|
|
250
|
+
view.settings.userAgentString = mUserAgent
|
|
251
|
+
}
|
|
252
|
+
mUserAgentWithApplicationName != null -> {
|
|
253
|
+
view.settings.userAgentString = mUserAgentWithApplicationName
|
|
254
|
+
}
|
|
255
|
+
else -> {
|
|
256
|
+
view.settings.userAgentString = WebSettings.getDefaultUserAgent(view.context)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
fun setBasicAuthCredential(viewWrapper: RNCWebViewWrapper, credential: ReadableMap?) {
|
|
262
|
+
var basicAuthCredential: RNCBasicAuthCredential? = null
|
|
263
|
+
if (credential != null) {
|
|
264
|
+
if (credential.hasKey("username") && credential.hasKey("password")) {
|
|
265
|
+
val username = credential.getString("username")
|
|
266
|
+
val password = credential.getString("password")
|
|
267
|
+
basicAuthCredential = RNCBasicAuthCredential(username, password)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
viewWrapper.webView.setBasicAuthCredential(basicAuthCredential)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fun onAfterUpdateTransaction(viewWrapper: RNCWebViewWrapper) {
|
|
274
|
+
mPendingSource?.let { source ->
|
|
275
|
+
loadSource(viewWrapper, source)
|
|
276
|
+
}
|
|
277
|
+
mPendingSource = null
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
fun onDropViewInstance(viewWrapper: RNCWebViewWrapper) {
|
|
281
|
+
val webView = viewWrapper.webView
|
|
282
|
+
webView.themedReactContext.removeLifecycleEventListener(webView)
|
|
283
|
+
webView.cleanupCallbacksAndDestroy()
|
|
284
|
+
webView.mWebChromeClient = null
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
val COMMAND_GO_BACK = 1
|
|
288
|
+
val COMMAND_GO_FORWARD = 2
|
|
289
|
+
val COMMAND_RELOAD = 3
|
|
290
|
+
val COMMAND_STOP_LOADING = 4
|
|
291
|
+
val COMMAND_POST_MESSAGE = 5
|
|
292
|
+
val COMMAND_INJECT_JAVASCRIPT = 6
|
|
293
|
+
val COMMAND_LOAD_URL = 7
|
|
294
|
+
val COMMAND_FOCUS = 8
|
|
295
|
+
|
|
296
|
+
// android commands
|
|
297
|
+
val COMMAND_CLEAR_FORM_DATA = 1000
|
|
298
|
+
val COMMAND_CLEAR_CACHE = 1001
|
|
299
|
+
val COMMAND_CLEAR_HISTORY = 1002
|
|
300
|
+
|
|
301
|
+
fun getCommandsMap(): Map<String, Int>? {
|
|
302
|
+
return MapBuilder.builder<String, Int>()
|
|
303
|
+
.put("goBack", COMMAND_GO_BACK)
|
|
304
|
+
.put("goForward", COMMAND_GO_FORWARD)
|
|
305
|
+
.put("reload", COMMAND_RELOAD)
|
|
306
|
+
.put("stopLoading", COMMAND_STOP_LOADING)
|
|
307
|
+
.put("postMessage", COMMAND_POST_MESSAGE)
|
|
308
|
+
.put("injectJavaScript", COMMAND_INJECT_JAVASCRIPT)
|
|
309
|
+
.put("loadUrl", COMMAND_LOAD_URL)
|
|
310
|
+
.put("requestFocus", COMMAND_FOCUS)
|
|
311
|
+
.put("clearFormData", COMMAND_CLEAR_FORM_DATA)
|
|
312
|
+
.put("clearCache", COMMAND_CLEAR_CACHE)
|
|
313
|
+
.put("clearHistory", COMMAND_CLEAR_HISTORY)
|
|
314
|
+
.build()
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
fun receiveCommand(viewWrapper: RNCWebViewWrapper, commandId: String, args: ReadableArray) {
|
|
318
|
+
val webView = viewWrapper.webView
|
|
319
|
+
when (commandId) {
|
|
320
|
+
"goBack" -> webView.goBack()
|
|
321
|
+
"goForward" -> webView.goForward()
|
|
322
|
+
"reload" -> webView.reload()
|
|
323
|
+
"stopLoading" -> webView.stopLoading()
|
|
324
|
+
"postMessage" -> try {
|
|
325
|
+
val eventInitDict = JSONObject()
|
|
326
|
+
eventInitDict.put("data", args.getString(0))
|
|
327
|
+
webView.evaluateJavascriptWithFallback(
|
|
328
|
+
"(function () {" +
|
|
329
|
+
"var event;" +
|
|
330
|
+
"var data = " + eventInitDict.toString() + ";" +
|
|
331
|
+
"try {" +
|
|
332
|
+
"event = new MessageEvent('message', data);" +
|
|
333
|
+
"} catch (e) {" +
|
|
334
|
+
"event = document.createEvent('MessageEvent');" +
|
|
335
|
+
"event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" +
|
|
336
|
+
"}" +
|
|
337
|
+
"document.dispatchEvent(event);" +
|
|
338
|
+
"})();"
|
|
339
|
+
)
|
|
340
|
+
} catch (e: JSONException) {
|
|
341
|
+
throw RuntimeException(e)
|
|
342
|
+
}
|
|
343
|
+
"injectJavaScript" -> webView.evaluateJavascriptWithFallback(args.getString(0))
|
|
344
|
+
"loadUrl" -> {
|
|
345
|
+
val url = args?.getString(0) ?: throw RuntimeException("Arguments for loading an url are null!")
|
|
346
|
+
webView.progressChangedFilter.setWaitingForCommandLoadUrl(false)
|
|
347
|
+
webView.loadUrl(url)
|
|
348
|
+
}
|
|
349
|
+
"requestFocus" -> webView.requestFocus()
|
|
350
|
+
"clearFormData" -> webView.clearFormData()
|
|
351
|
+
"clearCache" -> {
|
|
352
|
+
val includeDiskFiles = args != null && args.getBoolean(0)
|
|
353
|
+
webView.clearCache(includeDiskFiles)
|
|
354
|
+
}
|
|
355
|
+
"clearHistory" -> webView.clearHistory()
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
fun setMixedContentMode(viewWrapper: RNCWebViewWrapper, mixedContentMode: String?) {
|
|
360
|
+
val view = viewWrapper.webView
|
|
361
|
+
if (mixedContentMode == null || "never" == mixedContentMode) {
|
|
362
|
+
view.settings.mixedContentMode = WebSettings.MIXED_CONTENT_NEVER_ALLOW
|
|
363
|
+
} else if ("always" == mixedContentMode) {
|
|
364
|
+
view.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
|
|
365
|
+
} else if ("compatibility" == mixedContentMode) {
|
|
366
|
+
view.settings.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
fun setAllowUniversalAccessFromFileURLs(viewWrapper: RNCWebViewWrapper, allow: Boolean) {
|
|
371
|
+
viewWrapper.webView.settings.allowUniversalAccessFromFileURLs = allow
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private fun getDownloadingMessageOrDefault(): String? {
|
|
375
|
+
return mDownloadingMessage ?: DEFAULT_DOWNLOADING_MESSAGE
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private fun getLackPermissionToDownloadMessageOrDefault(): String? {
|
|
379
|
+
return mLackPermissionToDownloadMessage
|
|
380
|
+
?: DEFAULT_LACK_PERMISSION_TO_DOWNLOAD_MESSAGE
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
fun setSource(viewWrapper: RNCWebViewWrapper, source: ReadableMap?) {
|
|
384
|
+
mPendingSource = source
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private fun loadSource(viewWrapper: RNCWebViewWrapper, source: ReadableMap?) {
|
|
388
|
+
val view = viewWrapper.webView
|
|
389
|
+
if (source != null) {
|
|
390
|
+
if (source.hasKey("html")) {
|
|
391
|
+
val html = source.getString("html")
|
|
392
|
+
val baseUrl = if (source.hasKey("baseUrl")) source.getString("baseUrl") else ""
|
|
393
|
+
view.loadDataWithBaseURL(
|
|
394
|
+
baseUrl,
|
|
395
|
+
html!!,
|
|
396
|
+
HTML_MIME_TYPE,
|
|
397
|
+
HTML_ENCODING,
|
|
398
|
+
null
|
|
399
|
+
)
|
|
400
|
+
return
|
|
401
|
+
}
|
|
402
|
+
if (source.hasKey("uri")) {
|
|
403
|
+
val url = source.getString("uri")
|
|
404
|
+
val previousUrl = view.url
|
|
405
|
+
if (previousUrl != null && previousUrl == url) {
|
|
406
|
+
return
|
|
407
|
+
}
|
|
408
|
+
if (source.hasKey("method")) {
|
|
409
|
+
val method = source.getString("method")
|
|
410
|
+
if (method.equals(HTTP_METHOD_POST, ignoreCase = true)) {
|
|
411
|
+
var postData: ByteArray? = null
|
|
412
|
+
if (source.hasKey("body")) {
|
|
413
|
+
val body = source.getString("body")
|
|
414
|
+
postData = try {
|
|
415
|
+
body!!.toByteArray(charset("UTF-8"))
|
|
416
|
+
} catch (e: UnsupportedEncodingException) {
|
|
417
|
+
body!!.toByteArray()
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (postData == null) {
|
|
421
|
+
postData = ByteArray(0)
|
|
422
|
+
}
|
|
423
|
+
view.postUrl(url!!, postData)
|
|
424
|
+
return
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
val headerMap = HashMap<String, String?>()
|
|
428
|
+
if (source.hasKey("headers")) {
|
|
429
|
+
if (newArch) {
|
|
430
|
+
val headerArray = source.getArray("headers");
|
|
431
|
+
for (header in headerArray!!.toArrayList()) {
|
|
432
|
+
val headerCasted = header as HashMap<String, String>
|
|
433
|
+
val name = headerCasted.get("name") ?: ""
|
|
434
|
+
val value = headerCasted.get("value") ?: ""
|
|
435
|
+
if ("user-agent" == name.lowercase(Locale.ENGLISH)) {
|
|
436
|
+
view.settings.userAgentString = value
|
|
437
|
+
} else {
|
|
438
|
+
headerMap[name] = value
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
val headers = source.getMap("headers")
|
|
443
|
+
val iter = headers!!.keySetIterator()
|
|
444
|
+
while (iter.hasNextKey()) {
|
|
445
|
+
val key = iter.nextKey()
|
|
446
|
+
if ("user-agent" == key.lowercase(Locale.ENGLISH)) {
|
|
447
|
+
view.settings.userAgentString = headers.getString(key)
|
|
448
|
+
} else {
|
|
449
|
+
headerMap[key] = headers.getString(key)
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
view.loadUrl(url!!, headerMap)
|
|
455
|
+
return
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
view.loadUrl(BLANK_URL)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
fun setMessagingModuleName(viewWrapper: RNCWebViewWrapper, value: String?) {
|
|
462
|
+
val view = viewWrapper.webView
|
|
463
|
+
view.messagingModuleName = value
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
fun setCacheEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
467
|
+
val view = viewWrapper.webView
|
|
468
|
+
view.settings.cacheMode = if (enabled) WebSettings.LOAD_DEFAULT else WebSettings.LOAD_NO_CACHE
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
fun setIncognito(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
472
|
+
val view = viewWrapper.webView
|
|
473
|
+
// Don't do anything when incognito is disabled
|
|
474
|
+
if (!enabled) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Remove all previous cookies
|
|
479
|
+
CookieManager.getInstance().removeAllCookies(null);
|
|
480
|
+
|
|
481
|
+
// Disable caching
|
|
482
|
+
view.settings.cacheMode = WebSettings.LOAD_NO_CACHE
|
|
483
|
+
view.clearHistory();
|
|
484
|
+
view.clearCache(true);
|
|
485
|
+
|
|
486
|
+
// No form data or autofill enabled
|
|
487
|
+
view.clearFormData();
|
|
488
|
+
view.settings.savePassword = false;
|
|
489
|
+
view.settings.saveFormData = false;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
fun setInjectedJavaScript(viewWrapper: RNCWebViewWrapper, injectedJavaScript: String?) {
|
|
493
|
+
val view = viewWrapper.webView
|
|
494
|
+
view.injectedJS = injectedJavaScript
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
fun setInjectedJavaScriptBeforeContentLoaded(viewWrapper: RNCWebViewWrapper, value: String?) {
|
|
498
|
+
val view = viewWrapper.webView
|
|
499
|
+
view.injectedJSBeforeContentLoaded = value
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
fun setInjectedJavaScriptForMainFrameOnly(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
503
|
+
val view = viewWrapper.webView
|
|
504
|
+
view.injectedJavaScriptForMainFrameOnly = value
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
fun setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
508
|
+
val view = viewWrapper.webView
|
|
509
|
+
view.injectedJavaScriptBeforeContentLoadedForMainFrameOnly = value
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
fun setInjectedJavaScriptObject(viewWrapper: RNCWebViewWrapper, value: String?) {
|
|
513
|
+
val view = viewWrapper.webView
|
|
514
|
+
view.setInjectedJavaScriptObject(value)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
fun setJavaScriptCanOpenWindowsAutomatically(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
518
|
+
val view = viewWrapper.webView
|
|
519
|
+
view.settings.javaScriptCanOpenWindowsAutomatically = value
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
fun setShowsVerticalScrollIndicator(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
523
|
+
val view = viewWrapper.webView
|
|
524
|
+
view.isVerticalScrollBarEnabled = value
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
fun setShowsHorizontalScrollIndicator(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
528
|
+
val view = viewWrapper.webView
|
|
529
|
+
view.isHorizontalScrollBarEnabled = value
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
fun setMessagingEnabled(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
533
|
+
val view = viewWrapper.webView
|
|
534
|
+
view.setMessagingEnabled(value)
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
fun setMediaPlaybackRequiresUserAction(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
538
|
+
val view = viewWrapper.webView
|
|
539
|
+
view.settings.mediaPlaybackRequiresUserGesture = value
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
fun setHasOnScroll(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
543
|
+
val view = viewWrapper.webView
|
|
544
|
+
view.setHasScrollEvent(value)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
fun setJavaScriptEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
548
|
+
val view = viewWrapper.webView
|
|
549
|
+
view.settings.javaScriptEnabled = enabled
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
fun setAllowFileAccess(viewWrapper: RNCWebViewWrapper, allowFileAccess: Boolean) {
|
|
553
|
+
val view = viewWrapper.webView
|
|
554
|
+
view.settings.allowFileAccess = allowFileAccess;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
fun setAllowFileAccessFromFileURLs(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
558
|
+
val view = viewWrapper.webView
|
|
559
|
+
view.settings.allowFileAccessFromFileURLs = value;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
fun setAllowsFullscreenVideo(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
563
|
+
val view = viewWrapper.webView
|
|
564
|
+
mAllowsFullscreenVideo = value
|
|
565
|
+
setupWebChromeClient(view)
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
fun setAndroidLayerType(viewWrapper: RNCWebViewWrapper, layerTypeString: String?) {
|
|
569
|
+
val view = viewWrapper.webView
|
|
570
|
+
val layerType = when (layerTypeString) {
|
|
571
|
+
"hardware" -> View.LAYER_TYPE_HARDWARE
|
|
572
|
+
"software" -> View.LAYER_TYPE_SOFTWARE
|
|
573
|
+
else -> View.LAYER_TYPE_NONE
|
|
574
|
+
}
|
|
575
|
+
view.setLayerType(layerType, null)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
fun setCacheMode(viewWrapper: RNCWebViewWrapper, cacheModeString: String?) {
|
|
579
|
+
val view = viewWrapper.webView
|
|
580
|
+
view.settings.cacheMode = when (cacheModeString) {
|
|
581
|
+
"LOAD_CACHE_ONLY" -> WebSettings.LOAD_CACHE_ONLY
|
|
582
|
+
"LOAD_CACHE_ELSE_NETWORK" -> WebSettings.LOAD_CACHE_ELSE_NETWORK
|
|
583
|
+
"LOAD_NO_CACHE" -> WebSettings.LOAD_NO_CACHE
|
|
584
|
+
"LOAD_DEFAULT" -> WebSettings.LOAD_DEFAULT
|
|
585
|
+
else -> WebSettings.LOAD_DEFAULT
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
fun setDomStorageEnabled(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
590
|
+
val view = viewWrapper.webView
|
|
591
|
+
view.settings.domStorageEnabled = value
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
fun setDownloadingMessage(value: String?) {
|
|
595
|
+
mDownloadingMessage = value
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
fun setForceDarkOn(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
599
|
+
val view = viewWrapper.webView
|
|
600
|
+
// Only Android 10+ support dark mode
|
|
601
|
+
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
|
602
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
|
|
603
|
+
val forceDarkMode =
|
|
604
|
+
if (enabled) WebSettingsCompat.FORCE_DARK_ON else WebSettingsCompat.FORCE_DARK_OFF
|
|
605
|
+
WebSettingsCompat.setForceDark(view.settings, forceDarkMode)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Set how WebView content should be darkened.
|
|
609
|
+
// PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING: checks for the "color-scheme" <meta> tag.
|
|
610
|
+
// If present, it uses media queries. If absent, it applies user-agent (automatic)
|
|
611
|
+
// More information about Force Dark Strategy can be found here:
|
|
612
|
+
// https://developer.android.com/reference/androidx/webkit/WebSettingsCompat#setForceDarkStrategy(android.webkit.WebSettings)
|
|
613
|
+
if (enabled && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
|
|
614
|
+
WebSettingsCompat.setForceDarkStrategy(
|
|
615
|
+
view.settings,
|
|
616
|
+
WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING
|
|
617
|
+
)
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
fun setGeolocationEnabled(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
623
|
+
val view = viewWrapper.webView
|
|
624
|
+
view.settings.setGeolocationEnabled(value)
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
fun setLackPermissionToDownloadMessage(value: String?) {
|
|
628
|
+
mLackPermissionToDownloadMessage = value
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
fun setHasOnOpenWindowEvent(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
632
|
+
val view = viewWrapper.webView
|
|
633
|
+
mHasOnOpenWindowEvent = value
|
|
634
|
+
setupWebChromeClient(view)
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
fun setMinimumFontSize(viewWrapper: RNCWebViewWrapper, value: Int) {
|
|
638
|
+
val view = viewWrapper.webView
|
|
639
|
+
view.settings.minimumFontSize = value
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
fun setAllowsProtectedMedia(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
643
|
+
val view = viewWrapper.webView
|
|
644
|
+
// This variable is used to keep consistency
|
|
645
|
+
// in case a new WebChromeClient is created
|
|
646
|
+
// (eg. when mAllowsFullScreenVideo changes)
|
|
647
|
+
mAllowsProtectedMedia = enabled
|
|
648
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
649
|
+
val client = view.webChromeClient
|
|
650
|
+
if (client != null && client is RNCWebChromeClient) {
|
|
651
|
+
client.setAllowsProtectedMedia(enabled)
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
fun setMenuCustomItems(viewWrapper: RNCWebViewWrapper, value: ReadableArray?) {
|
|
657
|
+
val view = viewWrapper.webView
|
|
658
|
+
when (value) {
|
|
659
|
+
null -> view.setMenuCustomItems(null)
|
|
660
|
+
else -> view.setMenuCustomItems(value.toArrayList() as List<Map<String, String>>)
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
fun setNestedScrollEnabled(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
665
|
+
val view = viewWrapper.webView
|
|
666
|
+
view.nestedScrollEnabled = value
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
fun setOverScrollMode(viewWrapper: RNCWebViewWrapper, overScrollModeString: String?) {
|
|
670
|
+
val view = viewWrapper.webView
|
|
671
|
+
view.overScrollMode = when (overScrollModeString) {
|
|
672
|
+
"never" -> View.OVER_SCROLL_NEVER
|
|
673
|
+
"content" -> View.OVER_SCROLL_IF_CONTENT_SCROLLS
|
|
674
|
+
"always" -> View.OVER_SCROLL_ALWAYS
|
|
675
|
+
else -> View.OVER_SCROLL_ALWAYS
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
fun setSaveFormDataDisabled(viewWrapper: RNCWebViewWrapper, disabled: Boolean) {
|
|
680
|
+
val view = viewWrapper.webView
|
|
681
|
+
view.settings.saveFormData = !disabled
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
fun setScalesPageToFit(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
685
|
+
val view = viewWrapper.webView
|
|
686
|
+
view.settings.loadWithOverviewMode = value
|
|
687
|
+
view.settings.useWideViewPort = value
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
fun setSetBuiltInZoomControls(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
691
|
+
val view = viewWrapper.webView
|
|
692
|
+
view.settings.builtInZoomControls = value
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
fun setSetDisplayZoomControls(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
696
|
+
val view = viewWrapper.webView
|
|
697
|
+
view.settings.displayZoomControls = value
|
|
698
|
+
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
fun setSetSupportMultipleWindows(viewWrapper: RNCWebViewWrapper, value: Boolean) {
|
|
702
|
+
val view = viewWrapper.webView
|
|
703
|
+
view.settings.setSupportMultipleWindows(value)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
fun setTextZoom(viewWrapper: RNCWebViewWrapper, value: Int) {
|
|
707
|
+
val view = viewWrapper.webView
|
|
708
|
+
view.settings.textZoom = value
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
fun setThirdPartyCookiesEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
712
|
+
val view = viewWrapper.webView
|
|
713
|
+
CookieManager.getInstance().setAcceptThirdPartyCookies(view, enabled)
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
fun setWebviewDebuggingEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
717
|
+
RNCWebView.setWebContentsDebuggingEnabled(enabled)
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
fun setPaymentRequestEnabled(viewWrapper: RNCWebViewWrapper, enabled: Boolean) {
|
|
721
|
+
val view = viewWrapper.webView
|
|
722
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.PAYMENT_REQUEST)) {
|
|
723
|
+
WebSettingsCompat.setPaymentRequestEnabled(view.settings, enabled)
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Exodus: Set camera permission origin whitelist.
|
|
729
|
+
* Only origins in this whitelist will be allowed to request camera/microphone permissions.
|
|
730
|
+
*/
|
|
731
|
+
fun setCameraPermissionOriginWhitelist(viewWrapper: RNCWebViewWrapper, whitelist: ReadableArray?) {
|
|
732
|
+
val view = viewWrapper.webView
|
|
733
|
+
val whitelistSet = HashSet<String>()
|
|
734
|
+
whitelist?.let {
|
|
735
|
+
for (i in 0 until it.size()) {
|
|
736
|
+
it.getString(i)?.let { origin ->
|
|
737
|
+
whitelistSet.add(origin)
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
val client = view.webChromeClient
|
|
742
|
+
if (client != null && client is RNCWebChromeClient) {
|
|
743
|
+
client.setCameraPermissionOriginWhitelist(whitelistSet)
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|