mirror of
https://github.com/apache/cordova-android.git
synced 2026-04-04 00:02:03 +08:00
Compare commits
1 Commits
pr-add-pre
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9064bc0792 |
@@ -48,10 +48,6 @@ import androidx.core.splashscreen.SplashScreen;
|
|||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.core.view.WindowCompat;
|
import androidx.core.view.WindowCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
import androidx.webkit.WebViewCompat;
|
|
||||||
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is the main Android activity that represents the Cordova
|
* This class is the main Android activity that represents the Cordova
|
||||||
@@ -111,11 +107,6 @@ public class CordovaActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private boolean canEdgeToEdge = false;
|
private boolean canEdgeToEdge = false;
|
||||||
private boolean isFullScreen = false;
|
private boolean isFullScreen = false;
|
||||||
/**
|
|
||||||
* Flag set in {@link #checkWebViewVersion} indicating whether the WebView version
|
|
||||||
* is below the minimum required version specified in config.xml.
|
|
||||||
*/
|
|
||||||
private boolean isWebViewVersionBlocked = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the activity is first created.
|
* Called when the activity is first created.
|
||||||
@@ -130,9 +121,6 @@ public class CordovaActivity extends AppCompatActivity {
|
|||||||
// need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
|
// need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
// Check WebView version requirement
|
|
||||||
checkWebViewVersion();
|
|
||||||
|
|
||||||
canEdgeToEdge = preferences.getBoolean("AndroidEdgeToEdge", false)
|
canEdgeToEdge = preferences.getBoolean("AndroidEdgeToEdge", false)
|
||||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM;
|
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM;
|
||||||
|
|
||||||
@@ -177,10 +165,6 @@ public class CordovaActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void init() {
|
protected void init() {
|
||||||
if (isWebViewVersionBlocked) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
appView = makeWebView();
|
appView = makeWebView();
|
||||||
createViews();
|
createViews();
|
||||||
if (!appView.isInitialized()) {
|
if (!appView.isInitialized()) {
|
||||||
@@ -295,10 +279,6 @@ public class CordovaActivity extends AppCompatActivity {
|
|||||||
* Load the url into the WebView.
|
* Load the url into the WebView.
|
||||||
*/
|
*/
|
||||||
public void loadUrl(String url) {
|
public void loadUrl(String url) {
|
||||||
if (isWebViewVersionBlocked) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appView == null) {
|
if (appView == null) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@@ -608,124 +588,6 @@ public class CordovaActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the WebView version meets the minimum required version specified by
|
|
||||||
* preference `AndroidMinimumWebViewVersion` in config.xml.
|
|
||||||
* If not, display an error dialog and block the app from loading further.
|
|
||||||
*/
|
|
||||||
private void checkWebViewVersion() {
|
|
||||||
String minimumWebViewVersion = preferences.getString("AndroidMinimumWebViewVersion", null);
|
|
||||||
if (minimumWebViewVersion == null || minimumWebViewVersion.isEmpty()) {
|
|
||||||
return; // No minimum version requirement set
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String currentWebViewVersion = getWebViewVersion();
|
|
||||||
if (currentWebViewVersion != null && !isWebViewVersionSufficient(currentWebViewVersion, minimumWebViewVersion)) {
|
|
||||||
isWebViewVersionBlocked = true;
|
|
||||||
String title = getWebViewVersionTitle();
|
|
||||||
String message = getWebViewVersionMessage();
|
|
||||||
String button = getWebViewVersionButtonText();
|
|
||||||
displayError(title, message, button, true);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.e(TAG, "Error checking WebView version: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the WebView version check dialog title from string resources.
|
|
||||||
*/
|
|
||||||
private String getWebViewVersionTitle() {
|
|
||||||
int resId = getResources().getIdentifier("webview_version_too_old_title", "string", getPackageName());
|
|
||||||
return resId != 0 ? getString(resId) : "WebView Update Required";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the WebView version check dialog message from string resources.
|
|
||||||
*/
|
|
||||||
private String getWebViewVersionMessage() {
|
|
||||||
int resId = getResources().getIdentifier("webview_version_too_old_message", "string", getPackageName());
|
|
||||||
return resId != 0 ? getString(resId) : "Your Android System WebView version is too old. Please update it through the Google Play Store.";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the WebView version check dialog button text from string resources.
|
|
||||||
*/
|
|
||||||
private String getWebViewVersionButtonText() {
|
|
||||||
int resId = getResources().getIdentifier("webview_version_ok_button", "string", getPackageName());
|
|
||||||
return resId != 0 ? getString(resId) : "OK";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current WebView version string.
|
|
||||||
* @return Version string (e.g., "80.0.1234.56") or null if unable to determine
|
|
||||||
*/
|
|
||||||
private String getWebViewVersion() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
try {
|
|
||||||
PackageInfo webViewPackage = WebViewCompat.getCurrentWebViewPackage(this);
|
|
||||||
if (webViewPackage != null) {
|
|
||||||
return webViewPackage.versionName;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.d(TAG, "Could not get WebView version using WebViewCompat: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback for older API levels
|
|
||||||
PackageManager pm = getPackageManager();
|
|
||||||
String[] fallbackPackages = new String[] {
|
|
||||||
"com.google.android.webview",
|
|
||||||
"com.android.webview",
|
|
||||||
"com.android.chrome"
|
|
||||||
};
|
|
||||||
|
|
||||||
for (String packageName : fallbackPackages) {
|
|
||||||
try {
|
|
||||||
PackageInfo pi = pm.getPackageInfo(packageName, 0);
|
|
||||||
return pi.versionName;
|
|
||||||
} catch (PackageManager.NameNotFoundException ignored) {
|
|
||||||
// Try next package
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.d(TAG, "Could not find WebView package");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare two version strings and determine if current version is >= minimum version.
|
|
||||||
* @param currentVersion Current version string (e.g., "80.0.1234.56")
|
|
||||||
* @param minimumVersion Minimum required version string (e.g., "80.0")
|
|
||||||
* @return true if currentVersion >= minimumVersion
|
|
||||||
*/
|
|
||||||
private boolean isWebViewVersionSufficient(String currentVersion, String minimumVersion) {
|
|
||||||
try {
|
|
||||||
String[] currentParts = currentVersion.split("\\.");
|
|
||||||
String[] minimumParts = minimumVersion.split("\\.");
|
|
||||||
|
|
||||||
int maxLength = Math.max(currentParts.length, minimumParts.length);
|
|
||||||
|
|
||||||
for (int i = 0; i < maxLength; i++) {
|
|
||||||
int currentPart = i < currentParts.length ? Integer.parseInt(currentParts[i]) : 0;
|
|
||||||
int minimumPart = i < minimumParts.length ? Integer.parseInt(minimumParts[i]) : 0;
|
|
||||||
|
|
||||||
if (currentPart > minimumPart) {
|
|
||||||
return true;
|
|
||||||
} else if (currentPart < minimumPart) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // Versions are equal
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
LOG.e(TAG, "Error parsing version strings: " + e.getMessage());
|
|
||||||
return true; // If we can't parse, assume it's OK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether to show the splash screen while the WebView is initially loading.
|
* Indicates whether to show the splash screen while the WebView is initially loading.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -32,11 +32,12 @@ import android.os.Build;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.window.OnBackInvokedCallback;
|
|
||||||
import android.window.OnBackInvokedDispatcher;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import androidx.activity.OnBackPressedCallback;
|
||||||
|
import androidx.activity.OnBackPressedDispatcherOwner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class exposes methods in Cordova that can be called from JavaScript.
|
* This class exposes methods in Cordova that can be called from JavaScript.
|
||||||
*/
|
*/
|
||||||
@@ -48,7 +49,7 @@ public class CoreAndroid extends CordovaPlugin {
|
|||||||
private CallbackContext messageChannel;
|
private CallbackContext messageChannel;
|
||||||
private PluginResult pendingResume;
|
private PluginResult pendingResume;
|
||||||
private PluginResult pendingPause;
|
private PluginResult pendingPause;
|
||||||
private OnBackInvokedCallback backCallback;
|
private OnBackPressedCallback backCallback;
|
||||||
private final Object messageChannelLock = new Object();
|
private final Object messageChannelLock = new Object();
|
||||||
private final Object backButtonHandlerLock = new Object();
|
private final Object backButtonHandlerLock = new Object();
|
||||||
|
|
||||||
@@ -253,30 +254,56 @@ public class CoreAndroid extends CordovaPlugin {
|
|||||||
*/
|
*/
|
||||||
public void overrideBackbutton(boolean override) {
|
public void overrideBackbutton(boolean override) {
|
||||||
LOG.i("App", "WARNING: Back Button Default Behavior will be overridden. The backbutton event will be fired!");
|
LOG.i("App", "WARNING: Back Button Default Behavior will be overridden. The backbutton event will be fired!");
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
|
if (cordova.getActivity() == null) {
|
||||||
if (override) {
|
return;
|
||||||
synchronized (backButtonHandlerLock) {
|
|
||||||
if (backCallback == null) {
|
|
||||||
// The callback is intentionally empty. Since API 36, intercepting the back button is ignored, which means
|
|
||||||
// the onDispatchKeyEvent boolean result won't actually stop native from consuming the back button and doing
|
|
||||||
// it's own logic, UNLESS if there is an OnBackInvokedCallback registered on the dispatcher.
|
|
||||||
// The key dispatch events will still fire, which still handles propagating back button events to the webview.
|
|
||||||
// See https://developer.android.com/about/versions/16/behavior-changes-16#predictive-back for more info on the caveat.
|
|
||||||
backCallback = () -> {};
|
|
||||||
this.cordova.getActivity().getOnBackInvokedDispatcher().registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT, backCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
synchronized (backButtonHandlerLock) {
|
|
||||||
if (backCallback != null) {
|
|
||||||
this.cordova.getActivity().getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(backCallback);
|
|
||||||
backCallback = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
|
final boolean shouldOverride = override;
|
||||||
|
cordova.getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (shouldOverride) {
|
||||||
|
synchronized (backButtonHandlerLock) {
|
||||||
|
if (backCallback == null) {
|
||||||
|
registerBackPressedCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
synchronized (backButtonHandlerLock) {
|
||||||
|
if (backCallback != null) {
|
||||||
|
unregisterBackPressedCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, shouldOverride);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an AndroidX back callback so Cordova can keep routing back presses through its
|
||||||
|
* existing key dispatch path across Android versions without directly referencing newer
|
||||||
|
* platform-only back APIs.
|
||||||
|
*/
|
||||||
|
private void registerBackPressedCallback() {
|
||||||
|
final OnBackPressedDispatcherOwner backPressedDispatcherOwner = this.cordova.getActivity();
|
||||||
|
|
||||||
|
backCallback = new OnBackPressedCallback(true) {
|
||||||
|
@Override
|
||||||
|
public void handleOnBackPressed() {
|
||||||
|
// Intentionally empty.
|
||||||
|
// On modern Android versions, registering a callback keeps back handling
|
||||||
|
// routed through Cordova's existing key dispatch path.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
backPressedDispatcherOwner.getOnBackPressedDispatcher().addCallback(backPressedDispatcherOwner, backCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterBackPressedCallback() {
|
||||||
|
backCallback.remove();
|
||||||
|
backCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,8 +24,4 @@
|
|||||||
<string name="launcher_name">@string/app_name</string>
|
<string name="launcher_name">@string/app_name</string>
|
||||||
<!-- App label shown on the task switcher. -->
|
<!-- App label shown on the task switcher. -->
|
||||||
<string name="activity_name">@string/launcher_name</string>
|
<string name="activity_name">@string/launcher_name</string>
|
||||||
<!-- WebView version check messages -->
|
|
||||||
<string name="webview_version_too_old_title">WebView Update Required</string>
|
|
||||||
<string name="webview_version_too_old_message">Your Android System WebView version is too old. Please update it through the Google Play Store.</string>
|
|
||||||
<string name="webview_version_ok_button">OK</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user