@javascriptcommon/react-native-webview 13.12.16

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.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/android/build.gradle +110 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +15 -0
  6. package/android/src/main/AndroidManifestNew.xml +13 -0
  7. package/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java +11 -0
  8. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +372 -0
  9. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +450 -0
  10. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +328 -0
  11. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewConfig.java +11 -0
  12. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +14 -0
  13. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +720 -0
  14. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMessagingModule.kt +19 -0
  15. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java +554 -0
  16. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +56 -0
  17. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewWrapper.kt +39 -0
  18. package/android/src/main/java/com/reactnativecommunity/webview/URLUtil.java +179 -0
  19. package/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt +24 -0
  20. package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +25 -0
  21. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingErrorEvent.kt +25 -0
  22. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingFinishEvent.kt +24 -0
  23. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingProgressEvent.kt +24 -0
  24. package/android/src/main/java/com/reactnativecommunity/webview/events/TopLoadingStartEvent.kt +25 -0
  25. package/android/src/main/java/com/reactnativecommunity/webview/events/TopMessageEvent.kt +24 -0
  26. package/android/src/main/java/com/reactnativecommunity/webview/events/TopNewWindowEvent.kt +25 -0
  27. package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +26 -0
  28. package/android/src/main/java/com/reactnativecommunity/webview/events/TopShouldStartLoadWithRequestEvent.kt +29 -0
  29. package/android/src/main/res/xml/file_provider_paths.xml +6 -0
  30. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +553 -0
  31. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java +63 -0
  32. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +328 -0
  33. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java +59 -0
  34. package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
  35. package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
  36. package/apple/RNCWKProcessPoolManager.h +15 -0
  37. package/apple/RNCWKProcessPoolManager.m +36 -0
  38. package/apple/RNCWebView.h +35 -0
  39. package/apple/RNCWebView.mm +546 -0
  40. package/apple/RNCWebViewDecisionManager.h +20 -0
  41. package/apple/RNCWebViewDecisionManager.m +47 -0
  42. package/apple/RNCWebViewImpl.h +161 -0
  43. package/apple/RNCWebViewImpl.m +1979 -0
  44. package/apple/RNCWebViewManager.h +9 -0
  45. package/apple/RNCWebViewManager.mm +215 -0
  46. package/apple/RNCWebViewModule.h +23 -0
  47. package/apple/RNCWebViewModule.mm +34 -0
  48. package/index.d.ts +65 -0
  49. package/index.js +4 -0
  50. package/ios/RNCWebView.xcodeproj/project.pbxproj +273 -0
  51. package/lib/NativeRNCWebViewModule.d.ts +10 -0
  52. package/lib/NativeRNCWebViewModule.js +1 -0
  53. package/lib/RNCWebViewNativeComponent.d.ts +242 -0
  54. package/lib/RNCWebViewNativeComponent.js +1 -0
  55. package/lib/WebView.android.d.ts +6 -0
  56. package/lib/WebView.android.js +1 -0
  57. package/lib/WebView.d.ts +6 -0
  58. package/lib/WebView.ios.d.ts +6 -0
  59. package/lib/WebView.ios.js +1 -0
  60. package/lib/WebView.js +1 -0
  61. package/lib/WebView.macos.d.ts +6 -0
  62. package/lib/WebView.macos.js +1 -0
  63. package/lib/WebView.styles.d.ts +38 -0
  64. package/lib/WebView.styles.js +1 -0
  65. package/lib/WebView.windows.d.ts +17 -0
  66. package/lib/WebView.windows.js +1 -0
  67. package/lib/WebViewNativeComponent.macos.d.ts +3 -0
  68. package/lib/WebViewNativeComponent.macos.js +1 -0
  69. package/lib/WebViewNativeComponent.windows.d.ts +3 -0
  70. package/lib/WebViewNativeComponent.windows.js +1 -0
  71. package/lib/WebViewShared.d.ts +38 -0
  72. package/lib/WebViewShared.js +1 -0
  73. package/lib/WebViewTypes.d.ts +1093 -0
  74. package/lib/WebViewTypes.js +1 -0
  75. package/lib/index.d.ts +3 -0
  76. package/lib/index.js +1 -0
  77. package/macos/RNCWebView.xcodeproj/project.pbxproj +363 -0
  78. package/package.json +101 -0
  79. package/react-native-webview.podspec +46 -0
  80. package/react-native.config.js +44 -0
  81. package/src/NativeRNCWebViewModule.ts +15 -0
  82. package/src/RNCWebViewNativeComponent.ts +342 -0
  83. package/src/WebView.android.tsx +317 -0
  84. package/src/WebView.ios.tsx +299 -0
  85. package/src/WebView.macos.tsx +245 -0
  86. package/src/WebView.styles.ts +41 -0
  87. package/src/WebView.tsx +25 -0
  88. package/src/WebView.windows.tsx +210 -0
  89. package/src/WebViewNativeComponent.macos.ts +7 -0
  90. package/src/WebViewNativeComponent.windows.ts +8 -0
  91. package/src/WebViewShared.tsx +283 -0
  92. package/src/WebViewTypes.ts +1332 -0
  93. package/src/__tests__/WebViewShared-test.js +323 -0
  94. package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
  95. package/src/index.ts +4 -0
  96. package/windows/ExperimentalFeatures.props +11 -0
  97. package/windows/ReactNativeWebView/PropertySheet.props +16 -0
  98. package/windows/ReactNativeWebView/ReactNativeWebView.def +3 -0
  99. package/windows/ReactNativeWebView/ReactNativeWebView.filters +33 -0
  100. package/windows/ReactNativeWebView/ReactNativeWebView.vcxproj +189 -0
  101. package/windows/ReactNativeWebView/ReactPackageProvider.cpp +26 -0
  102. package/windows/ReactNativeWebView/ReactPackageProvider.h +20 -0
  103. package/windows/ReactNativeWebView/ReactPackageProvider.idl +7 -0
  104. package/windows/ReactNativeWebView/ReactWebView.cpp +242 -0
  105. package/windows/ReactNativeWebView/ReactWebView.h +56 -0
  106. package/windows/ReactNativeWebView/ReactWebView.idl +31 -0
  107. package/windows/ReactNativeWebView/ReactWebView2.cpp +473 -0
  108. package/windows/ReactNativeWebView/ReactWebView2.h +91 -0
  109. package/windows/ReactNativeWebView/ReactWebView2Manager.cpp +205 -0
  110. package/windows/ReactNativeWebView/ReactWebView2Manager.h +57 -0
  111. package/windows/ReactNativeWebView/ReactWebViewHelpers.cpp +70 -0
  112. package/windows/ReactNativeWebView/ReactWebViewHelpers.h +16 -0
  113. package/windows/ReactNativeWebView/ReactWebViewManager.cpp +224 -0
  114. package/windows/ReactNativeWebView/ReactWebViewManager.h +58 -0
  115. package/windows/ReactNativeWebView/WebBridge.cpp +19 -0
  116. package/windows/ReactNativeWebView/WebBridge.h +24 -0
  117. package/windows/ReactNativeWebView/WebBridge.idl +11 -0
  118. package/windows/ReactNativeWebView/pch.cpp +1 -0
  119. package/windows/ReactNativeWebView/pch.h +37 -0
  120. package/windows/ReactNativeWebView.sln +185 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2015-present, Facebook, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # React Native WebView
2
+
3
+ ![star this repo](https://img.shields.io/github/stars/react-native-webview/react-native-webview?style=flat-square)
4
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
5
+ [![NPM Version](https://img.shields.io/npm/v/react-native-webview.svg?style=flat-square)](https://www.npmjs.com/package/react-native-webview)
6
+ ![Npm Downloads](https://img.shields.io/npm/dm/react-native-webview.svg)
7
+
8
+ **React Native WebView** is a community-maintained WebView component for React Native. It is intended to be a replacement for the built-in WebView (which was [removed from core](https://github.com/react-native-community/discussions-and-proposals/pull/3)).
9
+
10
+ ### Maintainers
11
+
12
+ **Many thanks to these companies** for providing us with time to work on open source.
13
+ Please note that maintainers spend a lot of free time working on this too so feel free to sponsor them, **it really makes a difference.**
14
+
15
+ - [Thibault Malbranche](https://github.com/Titozzz) ([Twitter @titozzz](https://twitter.com/titozzz)) from [Brigad](https://www.brigad.co/en-gb/about-us)
16
+ [*Sponsor me* ❤️ !](https://github.com/sponsors/Titozzz)
17
+
18
+
19
+ Windows and macOS are managed by Microsoft, notably:
20
+ - [Alexander Sklar](https://github.com/asklar) ([Twitter @alexsklar](https://twitter.com/alexsklar)) from [React Native for Windows](https://microsoft.github.io/react-native-windows/)
21
+ - [Chiara Mooney](https://github.com/chiaramooney) from [React Native for Windows @ Microsoft](https://microsoft.github.io/react-native-windows/)
22
+
23
+ Shout-out to [Jamon Holmgren](https://github.com/jamonholmgren) from [Infinite Red](https://infinite.red) for helping a lot with the repo when he had more available time.
24
+
25
+ ### Disclaimer
26
+
27
+ Maintaining WebView is very complex because it is often used for many different use cases (rendering SVGs, PDFs, login flows, and much more). We also support many platforms and both architectures of react-native.
28
+
29
+ Since WebView was extracted from the React Native core, nearly 500 pull requests have been merged.
30
+ Considering that we have limited time, issues will mostly serve as a discussion place for the community, while **we will prioritize reviewing and merging pull requests.**
31
+
32
+ ### Platform compatibility
33
+
34
+ This project is compatible with **iOS**, **Android**, **Windows** and **macOS**.
35
+ This project supports both **the old** (paper) **and the new architecture** (fabric).
36
+ This project is compatible with [expo](https://docs.expo.dev/versions/latest/sdk/webview/).
37
+
38
+ ### Getting Started
39
+
40
+ Read our [Getting Started Guide](docs/Getting-Started.md). If any step seems unclear, please create a pull request.
41
+
42
+ ### Versioning
43
+
44
+ This project follows [semantic versioning](https://semver.org/). We do not hesitate to release breaking changes but they will be in a major version.
45
+
46
+ ### Usage
47
+
48
+ Import the `WebView` component from `react-native-webview` and use it like so:
49
+
50
+ ```tsx
51
+ import React, { Component } from 'react';
52
+ import { StyleSheet, Text, View } from 'react-native';
53
+ import { WebView } from 'react-native-webview';
54
+
55
+ // ...
56
+ const MyWebComponent = () => {
57
+ return <WebView source={{ uri: 'https://reactnative.dev/' }} style={{ flex: 1 }} />;
58
+ }
59
+ ```
60
+
61
+ For more, read the [API Reference](./docs/Reference.md) and [Guide](./docs/Guide.md). If you're interested in contributing, check out the [Contributing Guide](./docs/Contributing.md).
62
+
63
+ ### Common issues
64
+
65
+ - If you're getting `Invariant Violation: Native component for "RNCWebView does not exist"` it likely means you forgot to run `react-native link` or there was some error with the linking process
66
+ - If you encounter a build error during the task `:app:mergeDexRelease`, you need to enable multidex support in `android/app/build.gradle` as discussed in [this issue](https://github.com/react-native-webview/react-native-webview/issues/1344#issuecomment-650544648)
67
+
68
+ #### Contributing
69
+
70
+ Contributions are welcome, see [Contributing.md](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Contributing.md)
71
+
72
+ ### License
73
+
74
+ MIT
75
+
76
+ ### Translations
77
+
78
+ This readme is available in:
79
+
80
+ - [Brazilian portuguese](docs/README.portuguese.md)
81
+ - [French](docs/README.french.md)
82
+ - [Italian](docs/README.italian.md)
@@ -0,0 +1,110 @@
1
+ import java.nio.file.Paths
2
+
3
+ buildscript {
4
+ ext.safeExtGet = {prop ->
5
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : project.properties['ReactNativeWebView_' + prop]
6
+ }
7
+ repositories {
8
+ google()
9
+ gradlePluginPortal()
10
+ }
11
+ dependencies {
12
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion')}")
13
+ classpath("com.android.tools.build:gradle:7.0.4")
14
+ }
15
+ }
16
+
17
+ def getExtOrIntegerDefault(prop) {
18
+ return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : (project.properties['ReactNativeWebView_' + prop]).toInteger()
19
+ }
20
+
21
+ static def findNodeModulePath(baseDir, packageName) {
22
+ def basePath = baseDir.toPath().normalize()
23
+ // Node's module resolution algorithm searches up to the root directory,
24
+ // after which the base path will be null
25
+ while (basePath) {
26
+ def candidatePath = Paths.get(basePath.toString(), "node_modules", packageName)
27
+ if (candidatePath.toFile().exists()) {
28
+ return candidatePath.toString()
29
+ }
30
+ basePath = basePath.getParent()
31
+ }
32
+ return null
33
+ }
34
+
35
+ def isNewArchitectureEnabled() {
36
+ return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
37
+ }
38
+
39
+ def supportsNamespace() {
40
+ def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
41
+ def major = parsed[0].toInteger()
42
+ def minor = parsed[1].toInteger()
43
+
44
+ // Namespace support was added in 7.3.0
45
+ if (major == 7 && minor >= 3) {
46
+ return true
47
+ }
48
+
49
+ return major >= 8
50
+ }
51
+
52
+ apply plugin: 'com.android.library'
53
+ if (isNewArchitectureEnabled()) {
54
+ apply plugin: 'com.facebook.react'
55
+ }
56
+ apply plugin: 'kotlin-android'
57
+
58
+ android {
59
+ if (supportsNamespace()) {
60
+ namespace "com.reactnativecommunity.webview"
61
+ buildFeatures {
62
+ buildConfig true
63
+ }
64
+
65
+ sourceSets {
66
+ main {
67
+ manifest.srcFile "src/main/AndroidManifestNew.xml"
68
+ }
69
+ }
70
+ }
71
+
72
+ compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
73
+
74
+ defaultConfig {
75
+ minSdkVersion getExtOrIntegerDefault('minSdkVersion')
76
+ targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
77
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
78
+ }
79
+
80
+ sourceSets {
81
+ main {
82
+ if (isNewArchitectureEnabled()) {
83
+ java.srcDirs += ['src/newarch']
84
+ } else {
85
+ java.srcDirs += ['src/oldarch']
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ def reactNativePath = findNodeModulePath(projectDir, "react-native")
92
+ def codegenPath = findNodeModulePath(projectDir, "@react-native/codegen")
93
+ if (codegenPath == null) {
94
+ // Compat for 0.71 and lower (to be removed)
95
+ codegenPath = findNodeModulePath(projectDir, "react-native-codegen")
96
+ }
97
+
98
+ repositories {
99
+ maven {
100
+ url "${reactNativePath}/android"
101
+ }
102
+ mavenCentral()
103
+ google()
104
+ }
105
+
106
+ dependencies {
107
+ implementation 'com.facebook.react:react-native:+'
108
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:${safeExtGet('kotlinVersion')}"
109
+ implementation "androidx.webkit:webkit:${safeExtGet('webkitVersion')}"
110
+ }
@@ -0,0 +1,5 @@
1
+ ReactNativeWebView_kotlinVersion=1.6.0
2
+ ReactNativeWebView_webkitVersion=1.4.0
3
+ ReactNativeWebView_compileSdkVersion=31
4
+ ReactNativeWebView_targetSdkVersion=31
5
+ ReactNativeWebView_minSdkVersion=21
@@ -0,0 +1,15 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.reactnativecommunity.webview">
3
+
4
+ <application>
5
+ <provider
6
+ android:name=".RNCWebViewFileProvider"
7
+ android:authorities="${applicationId}.fileprovider"
8
+ android:exported="false"
9
+ android:grantUriPermissions="true">
10
+ <meta-data
11
+ android:name="android.support.FILE_PROVIDER_PATHS"
12
+ android:resource="@xml/file_provider_paths" />
13
+ </provider>
14
+ </application>
15
+ </manifest>
@@ -0,0 +1,13 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <application>
3
+ <provider
4
+ android:name=".RNCWebViewFileProvider"
5
+ android:authorities="${applicationId}.fileprovider"
6
+ android:exported="false"
7
+ android:grantUriPermissions="true">
8
+ <meta-data
9
+ android:name="android.support.FILE_PROVIDER_PATHS"
10
+ android:resource="@xml/file_provider_paths" />
11
+ </provider>
12
+ </application>
13
+ </manifest>
@@ -0,0 +1,11 @@
1
+ package com.reactnativecommunity.webview;
2
+
3
+ class RNCBasicAuthCredential {
4
+ String username;
5
+ String password;
6
+
7
+ RNCBasicAuthCredential(String username, String password) {
8
+ this.username = username;
9
+ this.password = password;
10
+ }
11
+ }
@@ -0,0 +1,372 @@
1
+ package com.reactnativecommunity.webview;
2
+
3
+ import android.Manifest;
4
+ import android.annotation.TargetApi;
5
+ import android.app.Activity;
6
+ import android.content.pm.PackageManager;
7
+ import android.net.Uri;
8
+ import android.os.Build;
9
+ import android.os.Message;
10
+ import android.view.Gravity;
11
+ import android.view.View;
12
+ import android.view.ViewGroup;
13
+ import android.webkit.ConsoleMessage;
14
+ import android.webkit.GeolocationPermissions;
15
+ import android.webkit.PermissionRequest;
16
+ import android.webkit.ValueCallback;
17
+ import android.webkit.WebChromeClient;
18
+ import android.webkit.WebView;
19
+ import android.webkit.WebViewClient;
20
+ import android.widget.FrameLayout;
21
+
22
+ import androidx.annotation.RequiresApi;
23
+ import androidx.core.content.ContextCompat;
24
+
25
+ import com.facebook.react.bridge.Arguments;
26
+ import com.facebook.react.bridge.LifecycleEventListener;
27
+ import com.facebook.react.bridge.WritableMap;
28
+ import com.facebook.react.common.build.ReactBuildConfig;
29
+ import com.facebook.react.modules.core.PermissionAwareActivity;
30
+ import com.facebook.react.modules.core.PermissionListener;
31
+ import com.facebook.react.uimanager.UIManagerHelper;
32
+ import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
33
+ import com.reactnativecommunity.webview.events.TopOpenWindowEvent;
34
+
35
+ import java.util.ArrayList;
36
+ import java.util.Collections;
37
+ import java.util.List;
38
+
39
+ public class RNCWebChromeClient extends WebChromeClient implements LifecycleEventListener {
40
+ protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams(
41
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
42
+
43
+ protected static final int FULLSCREEN_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
44
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
45
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
46
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
47
+ View.SYSTEM_UI_FLAG_FULLSCREEN |
48
+ View.SYSTEM_UI_FLAG_IMMERSIVE |
49
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
50
+
51
+ protected static final int COMMON_PERMISSION_REQUEST = 3;
52
+
53
+ protected RNCWebView mWebView;
54
+
55
+ protected View mVideoView;
56
+ protected WebChromeClient.CustomViewCallback mCustomViewCallback;
57
+
58
+ /*
59
+ * - Permissions -
60
+ * As native permissions are asynchronously handled by the PermissionListener, many fields have
61
+ * to be stored to send permissions results to the webview
62
+ */
63
+
64
+ // Webview camera & audio permission callback
65
+ protected PermissionRequest permissionRequest;
66
+ // Webview camera & audio permission already granted
67
+ protected List<String> grantedPermissions;
68
+
69
+ // Webview geolocation permission callback
70
+ protected GeolocationPermissions.Callback geolocationPermissionCallback;
71
+ // Webview geolocation permission origin callback
72
+ protected String geolocationPermissionOrigin;
73
+
74
+ // true if native permissions dialog is shown, false otherwise
75
+ protected boolean permissionsRequestShown = false;
76
+ // Pending Android permissions for the next request
77
+ protected List<String> pendingPermissions = new ArrayList<>();
78
+
79
+ protected RNCWebView.ProgressChangedFilter progressChangedFilter = null;
80
+ protected boolean mAllowsProtectedMedia = false;
81
+
82
+ protected boolean mHasOnOpenWindowEvent = false;
83
+
84
+ public RNCWebChromeClient(RNCWebView webView) {
85
+ this.mWebView = webView;
86
+ }
87
+
88
+ @Override
89
+ public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
90
+
91
+ final WebView newWebView = new WebView(view.getContext());
92
+
93
+ if(mHasOnOpenWindowEvent) {
94
+ newWebView.setWebViewClient(new WebViewClient(){
95
+ @Override
96
+ public boolean shouldOverrideUrlLoading (WebView subview, String url) {
97
+ WritableMap event = Arguments.createMap();
98
+ event.putString("targetUrl", url);
99
+
100
+ ((RNCWebView) view).dispatchEvent(
101
+ view,
102
+ new TopOpenWindowEvent(RNCWebViewWrapper.getReactTagFromWebView(view), event)
103
+ );
104
+
105
+ return true;
106
+ }
107
+ });
108
+ }
109
+
110
+ final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
111
+ transport.setWebView(newWebView);
112
+ resultMsg.sendToTarget();
113
+
114
+ return true;
115
+ }
116
+
117
+ @Override
118
+ public boolean onConsoleMessage(ConsoleMessage message) {
119
+ if (ReactBuildConfig.DEBUG) {
120
+ return super.onConsoleMessage(message);
121
+ }
122
+ // Ignore console logs in non debug builds.
123
+ return true;
124
+ }
125
+
126
+ @Override
127
+ public void onProgressChanged(WebView webView, int newProgress) {
128
+ super.onProgressChanged(webView, newProgress);
129
+ final String url = webView.getUrl();
130
+ if (progressChangedFilter.isWaitingForCommandLoadUrl()) {
131
+ return;
132
+ }
133
+ int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
134
+ WritableMap event = Arguments.createMap();
135
+ event.putDouble("target", reactTag);
136
+ event.putString("title", webView.getTitle());
137
+ event.putString("url", url);
138
+ event.putBoolean("canGoBack", webView.canGoBack());
139
+ event.putBoolean("canGoForward", webView.canGoForward());
140
+ event.putDouble("progress", (float) newProgress / 100);
141
+
142
+ UIManagerHelper.getEventDispatcherForReactTag(this.mWebView.getThemedReactContext(), reactTag).dispatchEvent(new TopLoadingProgressEvent(reactTag, event));
143
+ }
144
+
145
+ @Override
146
+ public void onPermissionRequest(final PermissionRequest request) {
147
+
148
+ grantedPermissions = new ArrayList<>();
149
+
150
+ ArrayList<String> requestedAndroidPermissions = new ArrayList<>();
151
+ for (String requestedResource : request.getResources()) {
152
+ String androidPermission = null;
153
+
154
+ if (requestedResource.equals(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) {
155
+ androidPermission = Manifest.permission.RECORD_AUDIO;
156
+ } else if (requestedResource.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
157
+ androidPermission = Manifest.permission.CAMERA;
158
+ } else if(requestedResource.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) {
159
+ if (mAllowsProtectedMedia) {
160
+ grantedPermissions.add(requestedResource);
161
+ } else {
162
+ /**
163
+ * Legacy handling (Kept in case it was working under some conditions (given Android version or something))
164
+ *
165
+ * Try to ask user to grant permission using Activity.requestPermissions
166
+ *
167
+ * Find more details here: https://github.com/react-native-webview/react-native-webview/pull/2732
168
+ */
169
+ androidPermission = PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID;
170
+ } }
171
+ // TODO: RESOURCE_MIDI_SYSEX, RESOURCE_PROTECTED_MEDIA_ID.
172
+ if (androidPermission != null) {
173
+ if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), androidPermission) == PackageManager.PERMISSION_GRANTED) {
174
+ grantedPermissions.add(requestedResource);
175
+ } else {
176
+ requestedAndroidPermissions.add(androidPermission);
177
+ }
178
+ }
179
+ }
180
+
181
+ // If all the permissions are already granted, send the response to the WebView synchronously
182
+ if (requestedAndroidPermissions.isEmpty()) {
183
+ request.grant(grantedPermissions.toArray(new String[0]));
184
+ grantedPermissions = null;
185
+ return;
186
+ }
187
+
188
+ // Otherwise, ask to Android System for native permissions asynchronously
189
+
190
+ this.permissionRequest = request;
191
+
192
+ requestPermissions(requestedAndroidPermissions);
193
+ }
194
+
195
+
196
+ @Override
197
+ public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
198
+
199
+ if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), Manifest.permission.ACCESS_FINE_LOCATION)
200
+ != PackageManager.PERMISSION_GRANTED) {
201
+
202
+ /*
203
+ * Keep the trace of callback and origin for the async permission request
204
+ */
205
+ geolocationPermissionCallback = callback;
206
+ geolocationPermissionOrigin = origin;
207
+
208
+ requestPermissions(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION));
209
+
210
+ } else {
211
+ callback.invoke(origin, true, false);
212
+ }
213
+ }
214
+
215
+ private PermissionAwareActivity getPermissionAwareActivity() {
216
+ Activity activity = this.mWebView.getThemedReactContext().getCurrentActivity();
217
+ if (activity == null) {
218
+ throw new IllegalStateException("Tried to use permissions API while not attached to an Activity.");
219
+ } else if (!(activity instanceof PermissionAwareActivity)) {
220
+ throw new IllegalStateException("Tried to use permissions API but the host Activity doesn't implement PermissionAwareActivity.");
221
+ }
222
+ return (PermissionAwareActivity) activity;
223
+ }
224
+
225
+ private synchronized void requestPermissions(List<String> permissions) {
226
+
227
+ /*
228
+ * If permissions request dialog is displayed on the screen and another request is sent to the
229
+ * activity, the last permission asked is skipped. As a work-around, we use pendingPermissions
230
+ * to store next required permissions.
231
+ */
232
+
233
+ if (permissionsRequestShown) {
234
+ pendingPermissions.addAll(permissions);
235
+ return;
236
+ }
237
+
238
+ PermissionAwareActivity activity = getPermissionAwareActivity();
239
+ permissionsRequestShown = true;
240
+
241
+ activity.requestPermissions(
242
+ permissions.toArray(new String[0]),
243
+ COMMON_PERMISSION_REQUEST,
244
+ webviewPermissionsListener
245
+ );
246
+
247
+ // Pending permissions have been sent, the list can be cleared
248
+ pendingPermissions.clear();
249
+ }
250
+
251
+
252
+ private PermissionListener webviewPermissionsListener = (requestCode, permissions, grantResults) -> {
253
+
254
+ permissionsRequestShown = false;
255
+
256
+ /*
257
+ * As a "pending requests" approach is used, requestCode cannot help to define if the request
258
+ * came from geolocation or camera/audio. This is why shouldAnswerToPermissionRequest is used
259
+ */
260
+ boolean shouldAnswerToPermissionRequest = false;
261
+
262
+ for (int i = 0; i < permissions.length; i++) {
263
+
264
+ String permission = permissions[i];
265
+ boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
266
+
267
+ if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)
268
+ && geolocationPermissionCallback != null
269
+ && geolocationPermissionOrigin != null) {
270
+
271
+ if (granted) {
272
+ geolocationPermissionCallback.invoke(geolocationPermissionOrigin, true, false);
273
+ } else {
274
+ geolocationPermissionCallback.invoke(geolocationPermissionOrigin, false, false);
275
+ }
276
+
277
+ geolocationPermissionCallback = null;
278
+ geolocationPermissionOrigin = null;
279
+ }
280
+
281
+ if (permission.equals(Manifest.permission.RECORD_AUDIO)) {
282
+ if (granted && grantedPermissions != null) {
283
+ grantedPermissions.add(PermissionRequest.RESOURCE_AUDIO_CAPTURE);
284
+ }
285
+ shouldAnswerToPermissionRequest = true;
286
+ }
287
+
288
+ if (permission.equals(Manifest.permission.CAMERA)) {
289
+ if (granted && grantedPermissions != null) {
290
+ grantedPermissions.add(PermissionRequest.RESOURCE_VIDEO_CAPTURE);
291
+ }
292
+ shouldAnswerToPermissionRequest = true;
293
+ }
294
+
295
+ if (permission.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) {
296
+ if (granted && grantedPermissions != null) {
297
+ grantedPermissions.add(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID);
298
+ }
299
+ shouldAnswerToPermissionRequest = true;
300
+ }
301
+ }
302
+
303
+ if (shouldAnswerToPermissionRequest
304
+ && permissionRequest != null
305
+ && grantedPermissions != null) {
306
+ permissionRequest.grant(grantedPermissions.toArray(new String[0]));
307
+ permissionRequest = null;
308
+ grantedPermissions = null;
309
+ }
310
+
311
+ if (!pendingPermissions.isEmpty()) {
312
+ requestPermissions(pendingPermissions);
313
+ return false;
314
+ }
315
+
316
+ return true;
317
+ };
318
+
319
+ protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType) {
320
+ this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptType);
321
+ }
322
+
323
+ protected void openFileChooser(ValueCallback<Uri> filePathCallback) {
324
+ this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, "");
325
+ }
326
+
327
+ protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType, String capture) {
328
+ this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptType);
329
+ }
330
+
331
+ @Override
332
+ public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
333
+ String[] acceptTypes = fileChooserParams.getAcceptTypes();
334
+ boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;
335
+
336
+ return this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptTypes, allowMultiple, fileChooserParams.isCaptureEnabled());
337
+ }
338
+
339
+ @Override
340
+ public void onHostResume() {
341
+ if (mVideoView != null && mVideoView.getSystemUiVisibility() != FULLSCREEN_SYSTEM_UI_VISIBILITY) {
342
+ mVideoView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY);
343
+ }
344
+ }
345
+
346
+ @Override
347
+ public void onHostPause() { }
348
+
349
+ @Override
350
+ public void onHostDestroy() { }
351
+
352
+ protected ViewGroup getRootView() {
353
+ return this.mWebView.getThemedReactContext().getCurrentActivity().findViewById(android.R.id.content);
354
+ }
355
+
356
+ public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) {
357
+ progressChangedFilter = filter;
358
+ }
359
+
360
+ /**
361
+ * Set whether or not protected media should be allowed
362
+ * /!\ Setting this to false won't revoke permission already granted to the current webpage.
363
+ * In order to do so, you'd need to reload the page /!\
364
+ */
365
+ public void setAllowsProtectedMedia(boolean enabled) {
366
+ mAllowsProtectedMedia = enabled;
367
+ }
368
+
369
+ public void setHasOnOpenWindowEvent(boolean hasEvent) {
370
+ mHasOnOpenWindowEvent = hasEvent;
371
+ }
372
+ }