Skip to content

Commit 0312cd5

Browse files
authored
Merge pull request #4 from CoolBitX-Technology/feat/sync-mm-react-native-webview
feat(android): sync mm react native webview
2 parents f94da97 + 915ce96 commit 0312cd5

File tree

3 files changed

+93
-26
lines changed

3 files changed

+93
-26
lines changed

android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package com.reactnativecommunity.webview;
22

3+
import static android.view.inputmethod.EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING;
4+
35
import android.annotation.SuppressLint;
46
import android.graphics.Rect;
7+
import android.os.Build;
58
import android.net.Uri;
69
import android.text.TextUtils;
710
import android.view.ActionMode;
811
import android.view.Menu;
912
import android.view.MenuItem;
1013
import android.view.MotionEvent;
1114
import android.view.View;
15+
import android.view.inputmethod.BaseInputConnection;
16+
import android.view.inputmethod.EditorInfo;
17+
import android.view.inputmethod.InputConnection;
1218
import android.webkit.JavascriptInterface;
1319
import android.webkit.ValueCallback;
1420
import android.webkit.WebChromeClient;
@@ -79,6 +85,11 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
7985
protected boolean nestedScrollEnabled = false;
8086
protected ProgressChangedFilter progressChangedFilter;
8187

88+
/** Samsung Manufacturer Name */
89+
private static final String SAMSUNG_MANUFACTURER_NAME = "samsung";
90+
/** Samsung Device Check */
91+
private static final Boolean IS_SAMSUNG_DEVICE = Build.MANUFACTURER.equals(SAMSUNG_MANUFACTURER_NAME);
92+
8293
/**
8394
* WebView must be created with an context of the current activity
8495
* <p>
@@ -111,6 +122,25 @@ public void setNestedScrollEnabled(boolean nestedScrollEnabled) {
111122
this.nestedScrollEnabled = nestedScrollEnabled;
112123
}
113124

125+
@Override
126+
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
127+
InputConnection inputConnection;
128+
129+
if (IS_SAMSUNG_DEVICE) {
130+
inputConnection = super.onCreateInputConnection(outAttrs);
131+
} else {
132+
inputConnection = new BaseInputConnection(this, false);
133+
134+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
135+
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING;
136+
} else {
137+
// Cover OS versions below Oreo
138+
outAttrs.imeOptions = IME_FLAG_NO_PERSONALIZED_LEARNING;
139+
}
140+
}
141+
return inputConnection;
142+
}
143+
114144
@Override
115145
public void onHostResume() {
116146
// do nothing

android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import android.webkit.HttpAuthHandler;
1010
import android.webkit.RenderProcessGoneDetail;
1111
import android.webkit.SslErrorHandler;
12+
import android.webkit.WebChromeClient;
1213
import android.webkit.WebResourceRequest;
1314
import android.webkit.WebResourceResponse;
1415
import android.webkit.WebView;
@@ -34,6 +35,7 @@
3435
import android.webkit.CookieManager;
3536
import android.webkit.CookieSyncManager;
3637

38+
import java.util.Objects;
3739
import java.util.concurrent.atomic.AtomicReference;
3840

3941
public class RNCWebViewClient extends WebViewClient {
@@ -68,6 +70,9 @@ public void onPageFinished(WebView webView, String url) {
6870
if (!mLastLoadFailed) {
6971
RNCWebView reactWebView = (RNCWebView) webView;
7072

73+
RNCWebChromeClient webChromeClient = (RNCWebChromeClient) reactWebView.getWebChromeClient();
74+
if(Objects.nonNull(webChromeClient)) webChromeClient.blockJsDuringLoading = false;
75+
7176
reactWebView.callInjectedJavaScript();
7277

7378
emitFinishEvent(webView, url);
@@ -91,12 +96,20 @@ public void onPageStarted(WebView webView, String url, Bitmap favicon) {
9196
mLastLoadFailed = false;
9297

9398
RNCWebView reactWebView = (RNCWebView) webView;
99+
100+
RNCWebChromeClient webChromeClient = (RNCWebChromeClient) reactWebView.getWebChromeClient();
101+
if(Objects.nonNull(webChromeClient)) webChromeClient.blockJsDuringLoading = true;
102+
94103
reactWebView.callInjectedJavaScriptBeforeContentLoaded();
95104
}
96105

97106
@Override
98107
public boolean shouldOverrideUrlLoading(WebView view, String url) {
99108
final RNCWebView rncWebView = (RNCWebView) view;
109+
110+
RNCWebChromeClient webChromeClient = (RNCWebChromeClient) rncWebView.getWebChromeClient();
111+
if(Objects.nonNull(webChromeClient)) webChromeClient.blockJsDuringLoading = true;
112+
100113
final boolean isJsDebugging = rncWebView.getReactApplicationContext().getJavaScriptContextHolder().get() == 0;
101114

102115
if (!isJsDebugging && rncWebView.mMessagingJSModule != null) {

android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.reactnativecommunity.webview
22

3+
import android.app.AlertDialog
34
import android.app.DownloadManager
5+
import android.content.DialogInterface
46
import android.content.pm.ActivityInfo
57
import android.graphics.Bitmap
68
import android.graphics.Color
@@ -15,6 +17,7 @@ import android.webkit.CookieManager
1517
import android.webkit.DownloadListener
1618
import android.webkit.WebSettings
1719
import android.webkit.WebView
20+
import android.widget.Toast
1821
import androidx.webkit.WebSettingsCompat
1922
import androidx.webkit.WebViewFeature
2023
import com.facebook.react.bridge.ReadableArray
@@ -27,6 +30,7 @@ import org.json.JSONObject
2730
import java.io.UnsupportedEncodingException
2831
import java.net.MalformedURLException
2932
import java.net.URL
33+
import java.text.Bidi
3034
import java.util.Locale
3135

3236
val 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

Comments
 (0)