11package com.reactnativecommunity.webview
22
3+ import android.app.AlertDialog
34import android.app.DownloadManager
5+ import android.content.DialogInterface
46import android.content.pm.ActivityInfo
57import android.graphics.Bitmap
68import android.graphics.Color
@@ -15,6 +17,7 @@ import android.webkit.CookieManager
1517import android.webkit.DownloadListener
1618import android.webkit.WebSettings
1719import android.webkit.WebView
20+ import android.widget.Toast
1821import androidx.webkit.WebSettingsCompat
1922import androidx.webkit.WebViewFeature
2023import com.facebook.react.bridge.ReadableArray
@@ -27,6 +30,7 @@ import org.json.JSONObject
2730import java.io.UnsupportedEncodingException
2831import java.net.MalformedURLException
2932import java.net.URL
33+ import java.text.Bidi
3034import java.util.Locale
3135
3236val invalidCharRegex = " [\\\\ /%\" ]" .toRegex()
@@ -81,6 +85,9 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
8185 settings.allowContentAccess = false
8286 settings.allowFileAccessFromFileURLs = false
8387 settings.allowUniversalAccessFromFileURLs = false
88+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
89+ settings.safeBrowsingEnabled = true
90+ }
8491 settings.mixedContentMode = WebSettings .MIXED_CONTENT_NEVER_ALLOW
8592
8693 // Fixes broken full-screen modals/galleries due to body height being 0.
@@ -91,6 +98,10 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
9198 if (ReactBuildConfig .DEBUG ) {
9299 WebView .setWebContentsDebuggingEnabled(true )
93100 }
101+ // Remove google autofill for Android > 8
102+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
103+ webView.setImportantForAutofill(View .IMPORTANT_FOR_AUTOFILL_NO );
104+ }
94105 webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
95106 webView.setIgnoreErrFailedForThisURL(url)
96107 val module = webView.reactApplicationContext.getNativeModule(RNCWebViewModule ::class .java) ? : return @DownloadListener
@@ -107,33 +118,46 @@ class RNCWebViewManagerImpl(private val newArch: Boolean = false) {
107118
108119 val downloadMessage = " Downloading $fileName "
109120
110- // Attempt to add cookie, if it exists
111- var urlObj: URL ? = null
112- try {
113- urlObj = URL (url)
114- val baseUrl = urlObj.protocol + " ://" + urlObj.host
115- val cookie = CookieManager .getInstance().getCookie(baseUrl)
116- request.addRequestHeader(" Cookie" , cookie)
117- } catch (e: MalformedURLException ) {
118- Log .w(TAG , " Error getting cookie for DownloadManager" , e)
119- }
121+ // Filename validation checking for files that use RTL characters and do not allow those types
122+ if (Bidi (fileName, Bidi .DIRECTION_DEFAULT_LEFT_TO_RIGHT ).isMixed) {
123+ Toast .makeText(webView.context, " Invalid filename or type" , Toast .LENGTH_LONG ).show()
124+ } else {
125+ val builder = AlertDialog .Builder (webView.context)
126+ builder.setMessage(" Do you want to download \n $fileName ?" )
127+ builder.setCancelable(false )
128+ builder.setPositiveButton(" Download" ) { _, _ ->
129+ // Attempt to add cookie, if it exists
130+ var urlObj: URL ? = null
131+ try {
132+ urlObj = URL (url)
133+ val baseUrl = urlObj.protocol + " ://" + urlObj.host
134+ val cookie = CookieManager .getInstance().getCookie(baseUrl)
135+ request.addRequestHeader(" Cookie" , cookie)
136+ } catch (e: MalformedURLException ) {
137+ Log .w(TAG , " Error getting cookie for DownloadManager" , e)
138+ }
120139
121- // Finish setting up request
122- request.addRequestHeader(" User-Agent" , userAgent)
123- request.setTitle(fileName)
124- request.setDescription(downloadMessage)
125- request.allowScanningByMediaScanner()
126- request.setNotificationVisibility(DownloadManager .Request .VISIBILITY_VISIBLE_NOTIFY_COMPLETED )
127- request.setDestinationInExternalPublicDir(Environment .DIRECTORY_DOWNLOADS , fileName)
128- module.setDownloadRequest(request)
129- if (module.grantFileDownloaderPermissions(
130- getDownloadingMessageOrDefault(),
131- getLackPermissionToDownloadMessageOrDefault()
132- )
133- ) {
134- module.downloadFile(
135- getDownloadingMessageOrDefault()
136- )
140+ // Finish setting up request
141+ request.addRequestHeader(" User-Agent" , userAgent)
142+ request.setTitle(fileName)
143+ request.setDescription(downloadMessage)
144+ request.allowScanningByMediaScanner()
145+ request.setNotificationVisibility(DownloadManager .Request .VISIBILITY_VISIBLE_NOTIFY_COMPLETED )
146+ request.setDestinationInExternalPublicDir(Environment .DIRECTORY_DOWNLOADS , fileName)
147+ module.setDownloadRequest(request)
148+ if (module.grantFileDownloaderPermissions(
149+ getDownloadingMessageOrDefault(),
150+ getLackPermissionToDownloadMessageOrDefault()
151+ )
152+ ) {
153+ module.downloadFile(
154+ getDownloadingMessageOrDefault()
155+ )
156+ }
157+ }
158+ builder.setNegativeButton(" Cancel" ) { _: DialogInterface ? , _: Int -> }
159+ val alertDialog = builder.create()
160+ alertDialog.show()
137161 }
138162 })
139163 return RNCWebViewWrapper (context, webView)
0 commit comments