Browse Source

upgrade: 6.2.1 with geckoview

ryanemax 2 weeks ago
parent
commit
e6f2c0cc4d

+ 2 - 1
.gitignore

@@ -1 +1,2 @@
-node_modules
+node_modules/
+dist/

+ 8 - 0
6.2.1/capacitor/build.gradle

@@ -20,6 +20,9 @@ buildscript {
         maven {
             url "https://plugins.gradle.org/m2/"
         }
+        maven{
+            url "https://maven.mozilla.org/maven2/"
+        }
     }
     dependencies {
         classpath 'com.android.tools.build:gradle:8.2.1'
@@ -75,6 +78,9 @@ android {
 repositories {
     google()
     mavenCentral()
+    maven{
+            url "https://maven.mozilla.org/maven2/"
+    }
 }
 
 dependencies {
@@ -92,5 +98,7 @@ dependencies {
     implementation "org.apache.cordova:framework:$cordovaAndroidVersion"
     testImplementation 'org.json:json:20231013'
     testImplementation 'org.mockito:mockito-inline:5.2.0'
+    api "org.mozilla.geckoview:geckoview-arm64-v8a:123.0.20240213221259"
+    implementation 'org.nanohttpd:nanohttpd-webserver:2.3.1'
 }
 

+ 74 - 43
6.2.1/capacitor/src/main/assets/native-bridge.js

@@ -1,7 +1,11 @@
 
 /*! Capacitor: https://capacitorjs.com/ - MIT License */
 /* Generated File. Do not edit. */
+window.readyList = [];
 
+setTimeout(() => {
+    if (!window.androidBridge) location.reload();
+}, 5000)
 var nativeBridge = (function (exports) {
     'use strict';
 
@@ -272,7 +276,13 @@ var nativeBridge = (function (exports) {
                     const eventName = args[0];
                     const handler = args[1];
                     if (eventName === 'deviceready' && handler) {
-                        Promise.resolve().then(handler);
+                        if (!window.androidBridge) {
+                            window.readyList.push(() => {
+                                Promise.resolve().then(handler);
+                            });
+                        } else {
+                            Promise.resolve().then(handler);
+                        }
                     }
                     else if (eventName === 'backbutton' && cap.Plugins.App) {
                         // Add a dummy listener so Capacitor doesn't do the default
@@ -439,24 +449,26 @@ var nativeBridge = (function (exports) {
                         },
                         set: function (val) {
                             const cookiePairs = val.split(';');
-                            const domainSection = val.toLowerCase().split('domain=')[1];
-                            const domain = cookiePairs.length > 1 &&
-                                domainSection != null &&
-                                domainSection.length > 0
-                                ? domainSection.split(';')[0].trim()
-                                : '';
-                            if (platform === 'ios') {
-                                // Use prompt to synchronously set cookies.
-                                // https://stackoverflow.com/questions/29249132/wkwebview-complex-communication-between-javascript-native-code/49474323#49474323
-                                const payload = {
-                                    type: 'CapacitorCookies.set',
-                                    action: val,
-                                    domain,
-                                };
-                                prompt(JSON.stringify(payload));
-                            }
-                            else if (typeof win.CapacitorCookiesAndroidInterface !== 'undefined') {
-                                win.CapacitorCookiesAndroidInterface.setCookie(domain, val);
+                            
+                            for (const cookiePair of cookiePairs) {
+                                const cookieKey = cookiePair.split('=')[0];
+                                const cookieValue = cookiePair.split('=')[1];
+                                if (null == cookieValue) {
+                                    continue;
+                                }
+                                if (platform === 'ios') {
+                                    // Use prompt to synchronously set cookies.
+                                    // https://stackoverflow.com/questions/29249132/wkwebview-complex-communication-between-javascript-native-code/49474323#49474323
+                                    const payload = {
+                                        type: 'CapacitorCookies.set',
+                                        key: cookieKey,
+                                        value: cookieValue,
+                                    };
+                                    prompt(JSON.stringify(payload));
+                                }
+                                else if (typeof win.CapacitorCookiesAndroidInterface !== 'undefined') {
+                                    win.CapacitorCookiesAndroidInterface.setCookie(cookieKey, cookieValue);
+                                }
                             }
                         },
                     });
@@ -835,31 +847,31 @@ var nativeBridge = (function (exports) {
             cap.isPluginAvailable = name => Object.prototype.hasOwnProperty.call(cap.Plugins, name);
             cap.isNativePlatform = isNativePlatform;
             // create the postToNative() fn if needed
-            if (getPlatformId(win) === 'android') {
-                // android platform
-                postToNative = data => {
-                    var _a;
-                    try {
-                        win.androidBridge.postMessage(JSON.stringify(data));
-                    }
-                    catch (e) {
-                        (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.error(e);
-                    }
-                };
-            }
-            else if (getPlatformId(win) === 'ios') {
-                // ios platform
-                postToNative = data => {
-                    var _a;
-                    try {
-                        data.type = data.type ? data.type : 'message';
-                        win.webkit.messageHandlers.bridge.postMessage(data);
-                    }
-                    catch (e) {
-                        (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.error(e);
+            
+            // android platform
+            postToNative = data => {
+                var _a;
+                try {
+                    // win.androidBridge.postMessage(JSON.stringify(data));
+                    if (!window.androidBridge) {
+                        window.readyList.push(() => {
+                            window.postMessage({
+                                direction: 'page',
+                                message: JSON.stringify(data),
+                            }, '*');
+                        });
+                    } else {
+                        window.postMessage({
+                            direction: 'page',
+                            message: JSON.stringify(data),
+                        }, '*');
                     }
-                };
-            }
+                }
+                catch (e) {
+                    (_a = win === null || win === void 0 ? void 0 : win.console) === null || _a === void 0 ? void 0 : _a.error(e);
+                }
+            };
+
             cap.handleWindowError = (msg, url, lineNo, columnNo, err) => {
                 const str = msg.toLowerCase();
                 if (str.indexOf('script error') > -1) ;
@@ -926,6 +938,25 @@ var nativeBridge = (function (exports) {
                 win.androidBridge.onmessage = function (event) {
                     returnResult(JSON.parse(event.data));
                 };
+                window.addEventListener('message', (event) => {
+                    if (
+                        event.source === window
+                        && event.data.direction
+                        && event.data.direction === 'messaging'
+                        && event.data.message.type !== 'eval'
+                    ) {
+                        try {
+                            if (event.data.message.payload) {
+                                returnResult(JSON.parse(event.data.message.payload));
+                                console.log('[MESSAGEING]', 'cap done', event);
+                            } else {
+                                throw new Error('payload is empty');
+                            }
+                        } catch (error) {
+                            console.error('[MESSAGEING]', 'cap error', error, event);
+                        }
+                    }
+                });
             }
             /**
              * Process a response from the native layer.

+ 235 - 48
6.2.1/capacitor/src/main/java/com/getcapacitor/Bridge.java

@@ -15,6 +15,9 @@ import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.ViewTreeObserver;
 import android.webkit.ValueCallback;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
@@ -31,13 +34,16 @@ import androidx.webkit.WebViewFeature;
 import com.getcapacitor.android.R;
 import com.getcapacitor.annotation.CapacitorPlugin;
 import com.getcapacitor.annotation.Permission;
+import com.getcapacitor.cordova.MockCordovaGeckoviewImpl;
 import com.getcapacitor.cordova.MockCordovaInterfaceImpl;
 import com.getcapacitor.cordova.MockCordovaWebViewImpl;
+import com.getcapacitor.httpserver.SimpleHttpServer;
 import com.getcapacitor.util.HostMask;
 import com.getcapacitor.util.InternalUtils;
 import com.getcapacitor.util.PermissionHelper;
 import com.getcapacitor.util.WebColor;
 import java.io.File;
+import java.io.IOException;
 import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.util.ArrayList;
@@ -48,6 +54,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -58,6 +65,14 @@ import org.apache.cordova.PluginEntry;
 import org.apache.cordova.PluginManager;
 import org.json.JSONException;
 
+import org.mozilla.geckoview.GeckoRuntime;
+import org.mozilla.geckoview.GeckoRuntimeSettings;
+import org.mozilla.geckoview.GeckoSession;
+import org.mozilla.geckoview.GeckoSessionSettings;
+import org.mozilla.geckoview.GeckoView;
+import org.mozilla.geckoview.WebExtension;
+
+import fi.iki.elonen.NanoHTTPD;
 /**
  * The Bridge class is the main engine of Capacitor. It manages
  * loading and communicating with all Plugins,
@@ -73,7 +88,7 @@ import org.json.JSONException;
  * <a href="https://github.com/ionic-team/capacitor/blob/HEAD/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java">
  *   BridgeActivity.java</a>
  */
-public class Bridge {
+public class Bridge implements IPostMessage {
 
     private static final String PREFS_NAME = "CapacitorSettings";
     private static final String PERMISSION_PREFS_NAME = "PluginPermStates";
@@ -81,6 +96,7 @@ public class Bridge {
     private static final String BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY = "capacitorLastActivityPluginMethod";
     private static final String BUNDLE_PLUGIN_CALL_OPTIONS_SAVED_KEY = "capacitorLastPluginCallOptions";
     private static final String BUNDLE_PLUGIN_CALL_BUNDLE_KEY = "capacitorLastPluginCallBundle";
+    private static final String BUNDLE_SESSION_PARCELABLE_BUNDLE_KEY = "geckoviewSessionState";
     private static final String LAST_BINARY_VERSION_CODE = "lastBinaryVersionCode";
     private static final String LAST_BINARY_VERSION_NAME = "lastBinaryVersionName";
     private static final String MINIMUM_ANDROID_WEBVIEW_ERROR = "System WebView is not supported";
@@ -119,8 +135,8 @@ public class Bridge {
     private Set<String> allowedOriginRules = new HashSet<String>();
     private ArrayList<String> authorities = new ArrayList<>();
     // A reference to the main WebView for the app
-    private final WebView webView;
-    public final MockCordovaInterfaceImpl cordovaInterface;
+    // private final WebView webView;
+    // public final MockCordovaInterfaceImpl cordovaInterface;
     private CordovaWebView cordovaWebView;
     private CordovaPreferences preferences;
     private BridgeWebViewClient webViewClient;
@@ -164,9 +180,16 @@ public class Bridge {
     // A pre-determined path to load the bridge
     private ServerPath serverPath;
 
+    private WebExtensionPortProxy webExtensionPortProxy;
+    public final MockCordovaInterfaceImpl cordovaInterface;
+    private WebviewExtension webviewExtension;
+    private final static String BUILD_INSTALL = "resource://android/assets/";
+    private NanoHTTPD server;
+
+    private GeckoSession.SessionState mSessionState;
     /**
      * Create the Bridge with a reference to the main {@link Activity} for the
-     * app, and a reference to the {@link WebView} our app will use.
+     * app, and a reference to the {@link GeckoView} our app will use.
      * @param context
      * @param webView
      * @deprecated Use {@link Bridge.Builder} to create Bridge instances
@@ -174,7 +197,7 @@ public class Bridge {
     @Deprecated
     public Bridge(
         AppCompatActivity context,
-        WebView webView,
+        GeckoView webView,
         List<Class<? extends Plugin>> initialPlugins,
         MockCordovaInterfaceImpl cordovaInterface,
         PluginManager pluginManager,
@@ -200,7 +223,8 @@ public class Bridge {
         this.serverPath = serverPath;
         this.context = context;
         this.fragment = fragment;
-        this.webView = webView;
+        // this.webView = webView;
+        this.webviewExtension = new WebviewExtension(webView);
         this.webViewClient = new BridgeWebViewClient(this);
         this.initialPlugins = initialPlugins;
         this.pluginInstances = pluginInstances;
@@ -252,8 +276,74 @@ public class Bridge {
     public App getApp() {
         return app;
     }
-
+    private void startRandomPort() {
+        //        bind port retry 3 times
+        for (int retry = 0; retry < 3 && server == null; retry++) {
+            try {
+                int port = 1024 + new Random().nextInt(64511);
+                config.setPort(port);
+                server = new SimpleHttpServer(context, this);
+                server.start();
+            } catch (IOException e) {
+                e.printStackTrace();
+                server = null;
+            }
+        }
+    }
     private void loadWebView() {
+
+        startRandomPort();
+        String overriddenUserAgentString = TextUtils.isEmpty(config.getOverriddenUserAgentString()) ? "" : config.getOverriddenUserAgentString();
+        String appendedUserAgentString = TextUtils.isEmpty(config.getAppendedUserAgentString()) ? "" : config.getAppendedUserAgentString();
+        GeckoSessionSettings sessionSettings = new GeckoSessionSettings.Builder()
+                .allowJavascript(true)
+                .userAgentOverride("random_port/" + config.getPort() + ";" + overriddenUserAgentString + appendedUserAgentString)
+                .build();
+        GeckoSession session = new GeckoSession(sessionSettings);
+        session.setContentDelegate(new GeckoSession.ContentDelegate() {
+
+        });
+
+        webviewExtension.setSession(session);
+
+        appUrlConfig = this.getServerUrl();
+        String[] appAllowNavigationConfig = this.config.getAllowNavigation();
+
+        ArrayList<String> authorities = new ArrayList<>();
+
+        if (appAllowNavigationConfig != null) {
+            authorities.addAll(Arrays.asList(appAllowNavigationConfig));
+        }
+        this.appAllowNavigationMask = HostMask.Parser.parse(appAllowNavigationConfig);
+        String authority = this.getHost();
+        authorities.add(authority);
+        String scheme = this.getScheme();
+
+        localUrl = scheme + "://" + authority;
+
+        if (appUrlConfig != null) {
+            try {
+                URL appUrlObject = new URL(appUrlConfig);
+                authorities.add(appUrlObject.getAuthority());
+            } catch (Exception ex) {
+                Logger.error("Provided server url is invalid: " + ex.getMessage());
+                return;
+            }
+            localUrl = appUrlConfig;
+            appUrl = appUrlConfig;
+        } else {
+            appUrl = localUrl;
+            // custom URL schemes requires path ending with /
+            if (!scheme.equals(Bridge.CAPACITOR_HTTP_SCHEME) && !scheme.equals(CAPACITOR_HTTPS_SCHEME)) {
+                appUrl += "/";
+            }
+        }
+
+        String appUrlPath = this.config.getStartPath();
+        if (appUrlPath != null && !appUrlPath.trim().isEmpty()) {
+            appUrl += appUrlPath;
+        }
+
         final boolean html5mode = this.config.isHTML5Mode();
 
         // Start the local web server
@@ -272,8 +362,8 @@ public class Bridge {
 
         Logger.debug("Loading app at " + appUrl);
 
-        webView.setWebChromeClient(new BridgeWebChromeClient(this));
-        webView.setWebViewClient(this.webViewClient);
+        // webView.setWebChromeClient(new BridgeWebChromeClient(this));
+        // webView.setWebViewClient(this.webViewClient);
 
         if (!isDeployDisabled() && !isNewBinary()) {
             SharedPreferences prefs = getContext()
@@ -286,7 +376,7 @@ public class Bridge {
         if (!this.isMinimumWebViewInstalled()) {
             String errorUrl = this.getErrorUrl();
             if (errorUrl != null) {
-                webView.loadUrl(errorUrl);
+                // webView.loadUrl(errorUrl);
                 return;
             } else {
                 Logger.error(MINIMUM_ANDROID_WEBVIEW_ERROR);
@@ -302,8 +392,23 @@ public class Bridge {
             }
         } else {
             // Get to work
-            webView.loadUrl(appUrl);
+            // webView.loadUrl(appUrl);
         }
+        listener = new ViewTreeObserver.OnGlobalLayoutListener() {
+            @Override
+            public void onGlobalLayout() {
+                webviewExtension.getSession().loadUri(appUrl);
+                removeListener();
+            }
+        };
+        this.webviewExtension.getWebview().getViewTreeObserver().addOnGlobalLayoutListener(listener);
+    }
+
+
+    ViewTreeObserver.OnGlobalLayoutListener listener = null;
+
+    private void removeListener() {
+        this.webviewExtension.getWebview().getViewTreeObserver().removeOnGlobalLayoutListener(listener);
     }
 
     @SuppressLint("WebViewApiAvailability")
@@ -488,11 +593,11 @@ public class Bridge {
     }
 
     /**
-     * Get the core WebView under Capacitor's control
+     * Get the core GeckoView under Capacitor's control
      * @return
      */
-    public WebView getWebView() {
-        return this.webView;
+    public WebviewExtension getWebView() {
+        return this.webviewExtension;
     }
 
     /**
@@ -559,31 +664,32 @@ public class Bridge {
      */
     @SuppressLint("SetJavaScriptEnabled")
     private void initWebView() {
-        WebSettings settings = webView.getSettings();
-        settings.setJavaScriptEnabled(true);
-        settings.setDomStorageEnabled(true);
-        settings.setGeolocationEnabled(true);
-        settings.setDatabaseEnabled(true);
-        settings.setMediaPlaybackRequiresUserGesture(false);
-        settings.setJavaScriptCanOpenWindowsAutomatically(true);
-        if (this.config.isMixedContentAllowed()) {
-            settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
-        }
-
-        String appendUserAgent = this.config.getAppendedUserAgentString();
-        if (appendUserAgent != null) {
-            String defaultUserAgent = settings.getUserAgentString();
-            settings.setUserAgentString(defaultUserAgent + " " + appendUserAgent);
-        }
-        String overrideUserAgent = this.config.getOverriddenUserAgentString();
-        if (overrideUserAgent != null) {
-            settings.setUserAgentString(overrideUserAgent);
-        }
+        // WebSettings settings = webView.getSettings();
+        // settings.setJavaScriptEnabled(true);
+        // settings.setDomStorageEnabled(true);
+        // settings.setGeolocationEnabled(true);
+        // settings.setDatabaseEnabled(true);
+        // settings.setMediaPlaybackRequiresUserGesture(false);
+        // settings.setJavaScriptCanOpenWindowsAutomatically(true);
+        // if (this.config.isMixedContentAllowed()) {
+        //     settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
+        // }
+
+        // String appendUserAgent = this.config.getAppendedUserAgentString();
+        // if (appendUserAgent != null) {
+        //     String defaultUserAgent = settings.getUserAgentString();
+        //     settings.setUserAgentString(defaultUserAgent + " " + appendUserAgent);
+        // }
+        // String overrideUserAgent = this.config.getOverriddenUserAgentString();
+        // if (overrideUserAgent != null) {
+        //     settings.setUserAgentString(overrideUserAgent);
+        // }
 
         String backgroundColor = this.config.getBackgroundColor();
         try {
             if (backgroundColor != null) {
-                webView.setBackgroundColor(WebColor.parseColor(backgroundColor));
+                // webView.setBackgroundColor(WebColor.parseColor(backgroundColor));
+                webviewExtension.getWebview().setBackgroundColor(WebColor.parseColor(backgroundColor));
             }
         } catch (IllegalArgumentException ex) {
             Logger.debug("WebView background color not applied");
@@ -593,7 +699,9 @@ public class Bridge {
         settings.setBuiltInZoomControls(this.config.isZoomableWebView());
 
         if (config.isInitialFocus()) {
-            webView.requestFocusFromTouch();
+            // webView.requestFocusFromTouch();
+            webviewExtension.getWebview().requestFocusFromTouch();
+
         }
 
         WebView.setWebContentsDebuggingEnabled(this.config.isWebContentsDebuggingEnabled());
@@ -847,7 +955,8 @@ public class Bridge {
      */
     public void eval(final String js, final ValueCallback<String> callback) {
         Handler mainHandler = new Handler(context.getMainLooper());
-        mainHandler.post(() -> webView.evaluateJavascript(js, callback));
+        // mainHandler.post(() -> webView.evaluateJavascript(js, callback));
+        mainHandler.post(() -> webExtensionPortProxy.eval(js));
     }
 
     public void logToJs(final String message, final String level) {
@@ -1020,6 +1129,12 @@ public class Bridge {
         String lastPluginCallMethod = savedInstanceState.getString(BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY);
         String lastOptionsJson = savedInstanceState.getString(BUNDLE_PLUGIN_CALL_OPTIONS_SAVED_KEY);
 
+        GeckoSession.SessionState sessionState = savedInstanceState.getParcelable(BUNDLE_SESSION_PARCELABLE_BUNDLE_KEY);
+        if (sessionState != null) {
+            this.setSessionState(sessionState);
+            this.getWebView().getSession().restoreState(sessionState);
+        }
+
         if (lastPluginId != null) {
             // If we have JSON blob saved, create a new plugin call with the original options
             if (lastOptionsJson != null) {
@@ -1060,6 +1175,9 @@ public class Bridge {
                     outState.putString(BUNDLE_LAST_PLUGIN_CALL_METHOD_NAME_KEY, call.getMethodName());
                     outState.putString(BUNDLE_PLUGIN_CALL_OPTIONS_SAVED_KEY, call.getData().toString());
                     outState.putBundle(BUNDLE_PLUGIN_CALL_BUNDLE_KEY, bundle);
+                    if (mSessionState != null) {
+                        outState.putParcelable(BUNDLE_SESSION_PARCELABLE_BUNDLE_KEY, mSessionState);
+                    }
                 } else {
                     Logger.error("Couldn't save last " + call.getPluginId() + "'s Plugin " + call.getMethodName() + " call");
                 }
@@ -1359,8 +1477,10 @@ public class Bridge {
      * Handle onDetachedFromWindow lifecycle event
      */
     public void onDetachedFromWindow() {
-        webView.removeAllViews();
-        webView.destroy();
+        // webView.removeAllViews();
+        // webView.destroy();
+        this.getWebView().getWebview().onDetachedFromWindow();
+        this.getWebView().getWebview().removeAllViews();
     }
 
     public String getServerBasePath() {
@@ -1384,14 +1504,16 @@ public class Bridge {
      */
     public void setServerAssetPath(String path) {
         localServer.hostAssets(path);
-        webView.post(() -> webView.loadUrl(appUrl));
+        // webView.post(() -> webView.loadUrl(appUrl));
+        webviewExtension.getWebview().post(() -> this.webviewExtension.getSession().loadUri(appUrl));
     }
 
     /**
      * Reload the WebView
      */
     public void reload() {
-        webView.post(() -> webView.loadUrl(appUrl));
+        // webView.post(() -> webView.loadUrl(appUrl));
+        webviewExtension.getWebview().post(() -> this.webviewExtension.getSession().loadUri(appUrl));
     }
 
     public String getLocalUrl() {
@@ -1416,7 +1538,7 @@ public class Bridge {
 
     public void setWebViewClient(BridgeWebViewClient client) {
         this.webViewClient = client;
-        webView.setWebViewClient(client);
+        // webView.setWebViewClient(client);
     }
 
     List<WebViewListener> getWebViewListeners() {
@@ -1537,6 +1659,7 @@ public class Bridge {
             return this;
         }
 
+        @SuppressLint({"WrongThread", "SetJavaScriptEnabled"})
         public Bridge create() {
             // Cordova initialization
             ConfigXmlParser parser = new ConfigXmlParser();
@@ -1550,12 +1673,28 @@ public class Bridge {
                 cordovaInterface.restoreInstanceState(instanceState);
             }
 
-            WebView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview);
-            MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(activity.getApplicationContext());
+            // WebView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview);
+            // MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(activity.getApplicationContext());
+            GeckoView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview);
+            MockCordovaGeckoviewImpl mockWebView = new MockCordovaGeckoviewImpl(activity.getApplicationContext());
             mockWebView.init(cordovaInterface, pluginEntries, preferences, webView);
             PluginManager pluginManager = mockWebView.getPluginManager();
             cordovaInterface.onCordovaInit(pluginManager);
 
+            if (config == null)
+                config = CapConfig.loadDefault(activity.getApplicationContext());
+            GeckoRuntimeSettings runTimeSettings = new GeckoRuntimeSettings.Builder()
+                    .configFilePath("")
+                    .javaScriptEnabled(true)
+                    .loginAutofillEnabled(true)
+                    .webManifest(false)
+                    .aboutConfigEnabled(false)
+                    .remoteDebuggingEnabled(true)
+                    .build();
+
+            GeckoRuntime sRuntime = GeckoRuntime
+                    .create(activity, runTimeSettings);
+
             // Bridge initialization
             Bridge bridge = new Bridge(
                 activity,
@@ -1570,10 +1709,25 @@ public class Bridge {
                 config
             );
 
-            if (webView instanceof CapacitorWebView) {
-                CapacitorWebView capacitorWebView = (CapacitorWebView) webView;
-                capacitorWebView.setBridge(bridge);
-            }
+            // if (webView instanceof CapacitorWebView) {
+            //     CapacitorWebView capacitorWebView = (CapacitorWebView) webView;
+            //     capacitorWebView.setBridge(bridge);
+            // }
+
+            webView.setSession(bridge.getWebView().getSession());
+            webView.getSession().setProgressDelegate(new GeckoSession.ProgressDelegate() {
+                @Override
+                public void onSessionStateChange(@NonNull GeckoSession session, @NonNull GeckoSession.SessionState sessionState) {
+//                    GeckoSession.ProgressDelegate.super.onSessionStateChange(session, sessionState);
+                    String value = "";
+                    if (sessionState != null) {
+                        value = sessionState.toString();
+                    }
+                    Log.i("geckoview", "onSessionStateChange when " + System.currentTimeMillis() + "ms " + value);
+                    bridge.setSessionState(sessionState);
+                }
+            });
+            webView.getSession().open(sRuntime);
 
             bridge.setCordovaWebView(mockWebView);
             bridge.setWebViewListeners(webViewListeners);
@@ -1583,7 +1737,40 @@ public class Bridge {
                 bridge.restoreInstanceState(instanceState);
             }
 
+            WebExtensionPortProxy webExtensionProxy = new WebExtensionPortProxy(bridge);
+            WebExtension.PortDelegate portDelegate = new PortDelegate(webExtensionProxy);
+            WebExtension.MessageDelegate messageDelegate = new MessageDelegate(webExtensionProxy, portDelegate);
+            sRuntime
+                    .getWebExtensionController()
+                    .ensureBuiltIn(BUILD_INSTALL, "messaging@example.com")
+                    .accept(
+                            // Set delegate that will receive messages coming from this extension.
+                            extension ->
+                                    extension
+                                            .setMessageDelegate(messageDelegate, "browser"),
+                            // Something bad happened, let's log an error
+                            e -> Log.e("MessageDelegate", "Error registering extension", e));
+            mockWebView.setProxy(webExtensionProxy);
+            mockWebView.setHttpServer(bridge.server);
+            bridge.setWebExtensionPortProxy(webExtensionProxy);
+
             return bridge;
         }
     }
+    @Override
+    public void postMessage(Object message) {
+        this.msgHandler.postMessage(message.toString());
+    }
+
+    public void setWebExtensionPortProxy(WebExtensionPortProxy proxy) {
+        this.webExtensionPortProxy = proxy;
+    }
+
+    public WebExtensionPortProxy getWebExtensionPortProxy() {
+        return this.webExtensionPortProxy;
+    }
+
+    public void setSessionState(GeckoSession.SessionState sessionState) {
+        this.mSessionState = sessionState;
+    }
 }

+ 10 - 1
6.2.1/capacitor/src/main/java/com/getcapacitor/CapConfig.java

@@ -63,6 +63,8 @@ public class CapConfig {
     // Config Object JSON (legacy)
     private JSONObject configJSON = new JSONObject();
 
+    private int port;
+
     /**
      * Constructs an empty config file.
      */
@@ -89,6 +91,13 @@ public class CapConfig {
         deserializeConfig(null);
     }
 
+    public int getPort() {
+        return port;
+    }
+    public void setPort(int port){
+        this.port=port;
+    }
+
     /**
      * Constructs a Capacitor Configuration from config.json file.
      *
@@ -327,7 +336,7 @@ public class CapConfig {
     }
 
     public String getHostname() {
-        return hostname;
+        return hostname+":"+port;
     }
 
     public String getStartPath() {

+ 16 - 10
6.2.1/capacitor/src/main/java/com/getcapacitor/MessageHandler.java

@@ -6,6 +6,7 @@ import androidx.webkit.JavaScriptReplyProxy;
 import androidx.webkit.WebViewCompat;
 import androidx.webkit.WebViewFeature;
 import org.apache.cordova.PluginManager;
+import org.mozilla.geckoview.GeckoView;
 
 /**
  * MessageHandler handles messages from the WebView, dispatching them
@@ -14,11 +15,15 @@ import org.apache.cordova.PluginManager;
 public class MessageHandler {
 
     private Bridge bridge;
-    private WebView webView;
+    // private WebView webView;
+    private GeckoView webView;
+
     private PluginManager cordovaPluginManager;
     private JavaScriptReplyProxy javaScriptReplyProxy;
 
-    public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) {
+    // public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) {
+    public MessageHandler(Bridge bridge, GeckoView webView, PluginManager cordovaPluginManager) {
+
         this.bridge = bridge;
         this.webView = webView;
         this.cordovaPluginManager = cordovaPluginManager;
@@ -32,13 +37,13 @@ public class MessageHandler {
                     Logger.warn("Plugin execution is allowed in Main Frame only");
                 }
             };
-            try {
-                WebViewCompat.addWebMessageListener(webView, "androidBridge", bridge.getAllowedOriginRules(), capListener);
-            } catch (Exception ex) {
-                webView.addJavascriptInterface(this, "androidBridge");
-            }
+            // try {
+            //     WebViewCompat.addWebMessageListener(webView, "androidBridge", bridge.getAllowedOriginRules(), capListener);
+            // } catch (Exception ex) {
+            //     webView.addJavascriptInterface(this, "androidBridge");
+            // }
         } else {
-            webView.addJavascriptInterface(this, "androidBridge");
+            // webView.addJavascriptInterface(this, "androidBridge");
         }
     }
 
@@ -140,8 +145,9 @@ public class MessageHandler {
 
     private void legacySendResponseMessage(PluginResult data) {
         final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")";
-        final WebView webView = this.webView;
-        webView.post(() -> webView.evaluateJavascript(runScript, null));
+        // final WebView webView = this.webView;
+        // webView.post(() -> webView.evaluateJavascript(runScript, null));
+        this.webView.post(()->  this.bridge.getWebExtensionPortProxy().eval(runScript));
     }
 
     private void callPluginMethod(String callbackId, String pluginId, String methodName, JSObject methodData) {

+ 1 - 1
6.2.1/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java

@@ -26,7 +26,7 @@ public class MockCordovaInterfaceImpl extends CordovaInterfaceImpl {
      * @param grantResults
      * @return true if Cordova handled the permission request, false if not
      */
-    @SuppressWarnings("deprecation")
+    // @SuppressWarnings("deprecation")
     public boolean handlePermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
         Pair<CordovaPlugin, Integer> callback = permissionResultCallbacks.getAndRemoveCallback(requestCode);
         if (callback != null) {

+ 5 - 5
6.2.1/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java

@@ -112,7 +112,7 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
     @Override
     public void clearCache() {}
 
-    @Deprecated
+    // @Deprecated
     @Override
     public void clearCache(boolean b) {}
 
@@ -182,7 +182,7 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
         this.pluginManager.onDestroy();
     }
 
-    @Deprecated
+    // @Deprecated
     @Override
     public void sendJavascript(String statememt) {
         nativeToJsMessageQueue.addJavaScript(statememt);
@@ -200,17 +200,17 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
     @Override
     public void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params) {}
 
-    @Deprecated
+    // @Deprecated
     @Override
     public boolean isCustomViewShowing() {
         return false;
     }
 
-    @Deprecated
+    // @Deprecated
     @Override
     public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {}
 
-    @Deprecated
+    // @Deprecated
     @Override
     public void hideCustomView() {}
 

+ 1 - 1
6.2.1/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookies.java

@@ -20,7 +20,7 @@ public class CapacitorCookies extends Plugin {
 
     @Override
     public void load() {
-        this.bridge.getWebView().addJavascriptInterface(this, "CapacitorCookiesAndroidInterface");
+        // this.bridge.getWebView().addJavascriptInterface(this, "CapacitorCookiesAndroidInterface");
         this.cookieManager = new CapacitorCookieManager(null, java.net.CookiePolicy.ACCEPT_ALL, this.bridge);
         this.cookieManager.removeSessionCookies();
         CookieHandler.setDefault(this.cookieManager);

+ 1 - 1
6.2.1/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorHttp.java

@@ -29,7 +29,7 @@ public class CapacitorHttp extends Plugin {
 
     @Override
     public void load() {
-        this.bridge.getWebView().addJavascriptInterface(this, "CapacitorHttpAndroidInterface");
+        // this.bridge.getWebView().addJavascriptInterface(this, "CapacitorHttpAndroidInterface");
         super.load();
     }
 

+ 4 - 3
6.2.1/capacitor/src/main/res/layout/bridge_layout_main.xml

@@ -7,9 +7,10 @@
     tools:context="com.getcapacitor.BridgeActivity"
     >
 
-    <com.getcapacitor.CapacitorWebView
+    <!-- <com.getcapacitor.CapacitorWebView -->
+    <org.mozilla.geckoview.GeckoView
         android:id="@+id/webview"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent" />
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
 
 </androidx.coordinatorlayout.widget.CoordinatorLayout>

+ 4 - 3
6.2.1/capacitor/src/main/res/layout/fragment_bridge.xml

@@ -5,9 +5,10 @@
     android:background="#F0FF1414"
     tools:context="com.getcapacitor.BridgeFragment">
 
-  <com.getcapacitor.CapacitorWebView
+  <!-- <com.getcapacitor.CapacitorWebView -->
+  <org.mozilla.geckoview.GeckoView
       android:id="@+id/webview"
-      android:layout_width="fill_parent"
-      android:layout_height="fill_parent" />
+      android:layout_width="match_parent"
+      android:layout_height="match_parent" />
 
 </FrameLayout>

+ 49 - 0
README.md

@@ -0,0 +1,49 @@
+# Capacitor Geckoview浏览器支持插件
+
+
+# 变更记录
+## Upgrade to 6.2.1
+- 将web-media项目,覆盖官方5.7.0,查看变化。
+- 在6.2.1文件中逐个修改差异文件
+
+### 复制新文件
+``` bash
+mkdir -p 6.2.1/capacitor/src/main/java/com/getcapacitor/httpserver/
+
+cp node_modules/@web-media/capacitor-geckoview/capacitor/src/main/java/com/getcapacitor/Delegates.java 6.2.1/capacitor/src/main/java/com/getcapacitor/Delegates.java
+cp node_modules/@web-media/capacitor-geckoview/capacitor/src/main/java/com/getcapacitor/IPostMessage.java 6.2.1/capacitor/src/main/java/com/getcapacitor/IPostMessage.java
+cp node_modules/@web-media/capacitor-geckoview/capacitor/src/main/java/com/getcapacitor/WebExtensionPortProxy.java 6.2.1/capacitor/src/main/java/com/getcapacitor/WebExtensionPortProxy.java
+cp node_modules/@web-media/capacitor-geckoview/capacitor/src/main/java/com/getcapacitor/WebviewExtension.java 6.2.1/capacitor/src/main/java/com/getcapacitor/WebviewExtension.java
+cp node_modules/@web-media/capacitor-geckoview/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaGeckoViewCookieManager.java 6.2.1/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaGeckoViewCookieManager.java
+cp node_modules/@web-media/capacitor-geckoview/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaGeckoviewImpl.java 6.2.1/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaGeckoviewImpl.java
+cp node_modules/@web-media/capacitor-geckoview/capacitor/src/main/java/com/getcapacitor/httpserver/SimpleHttpServer.java 6.2.1/capacitor/src/main/java/com/getcapacitor/httpserver/SimpleHttpServer.java
+```
+### 修改差异文件
+
+
+## Changed Files 5.7.0
+- 修改文件
+``` bash
+modified:   5.7.0/capacitor/build.gradle
+modified:   5.7.0/capacitor/src/main/assets/native-bridge.js
+modified:   5.7.0/capacitor/src/main/java/com/getcapacitor/Bridge.java
+modified:   5.7.0/capacitor/src/main/java/com/getcapacitor/CapConfig.java
+modified:   5.7.0/capacitor/src/main/java/com/getcapacitor/MessageHandler.java
+modified:   5.7.0/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java
+modified:   5.7.0/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java
+modified:   5.7.0/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookies.java
+modified:   5.7.0/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorHttp.java
+modified:   5.7.0/capacitor/src/main/res/layout/bridge_layout_main.xml
+modified:   5.7.0/capacitor/src/main/res/layout/fragment_bridge.xml
+```
+
+- 新增文件
+``` bash
+new file:   5.7.0/capacitor/src/main/java/com/getcapacitor/Delegates.java
+new file:   5.7.0/capacitor/src/main/java/com/getcapacitor/IPostMessage.java
+new file:   5.7.0/capacitor/src/main/java/com/getcapacitor/WebExtensionPortProxy.java
+new file:   5.7.0/capacitor/src/main/java/com/getcapacitor/WebviewExtension.java
+new file:   5.7.0/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaGeckoViewCookieManager.java
+new file:   5.7.0/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaGeckoviewImpl.java
+new file:   5.7.0/capacitor/src/main/java/com/getcapacitor/httpserver/SimpleHttpServer.java
+```