You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求使用GeckoView实现Html页面与Android应用双向交互的完整示例

GeckoView 网页与Android双向通信完整实现方案

核心逻辑说明

  • 以GeckoView官方推荐的Web扩展作为中间桥接层,实现页面和原生应用的消息中转
  • 通信链路:页面 ↔ 扩展内容脚本 ↔ 扩展后台脚本 ↔ Android原生代码

步骤1:创建内置Web扩展

在Android项目的assets目录下新建gecko_extension文件夹,里面新增三个文件:

1.1 扩展配置文件 manifest.json

{
  "manifest_version": 2,
  "name": "GeckoMessageBridge",
  "version": "1.0",
  "content_scripts": [
    {
      "matches": ["http://example.com/*"],
      "js": ["content_script.js"],
      "run_at": "document_start"
    }
  ],
  "background": {
    "scripts": ["background.js"]
  },
  "permissions": [
    "nativeMessaging",
    "http://example.com/*"
  ],
  "gecko_view": {
    "native_messaging": true
  }
}

1.2 内容脚本 content_script.js(注入到目标页面,负责和页面交互)

// 监听页面发来的消息
window.addEventListener("message", event => {
  // 只接收目标域名的消息,避免安全风险
  if (event.origin !== "http://example.com") return;
  if (event.data.type === "PAGE_TO_APP") {
    // 转发消息给扩展后台
    browser.runtime.sendMessage({
      type: "PAGE_TO_APP",
      content: event.data.content
    });
  }
});

// 监听扩展后台发来的消息
browser.runtime.onMessage.addListener(message => {
  if (message.type === "APP_TO_PAGE") {
    // 调用页面暴露的全局方法,wrappedJSObject用于访问页面上下文的全局变量
    window.wrappedJSObject.appToPage(message.content);
  }
});

1.3 后台脚本 background.js(负责和Android原生交互)

// 监听Android原生发来的消息,转发给内容脚本
browser.runtime.onMessage.addListener((message, sender) => {
  if (message.type === "APP_TO_PAGE") {
    browser.tabs.query({active: true, currentWindow: true}).then(tabs => {
      browser.tabs.sendMessage(tabs[0].id, message);
    });
  }
});

// 监听内容脚本发来的消息,转发给Android原生
browser.runtime.onMessage.addListener((message, sender) => {
  if (message.type === "PAGE_TO_APP") {
    browser.runtime.sendNativeMessage("gecko_bridge", message);
  }
});

步骤2:修改前端页面代码

补全原有x.html里的pageToApp方法即可,其余代码不需要改动:

function pageToApp(s) {
  // 发消息给注入的内容脚本
  window.postMessage({
    type: "PAGE_TO_APP",
    content: s
  }, "http://example.com");
  log('sent:' + s);
}

步骤3:补全Android侧代码

直接替换原有MainActivity的对应逻辑即可:

import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoView;
import org.mozilla.geckoview.WebExtension;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private GeckoSession geckoSession;
    private WebExtension messageBridgeExtension;
    // 扩展在assets目录下的路径
    private static final String EXTENSION_LOCATION = "resource://android/assets/gecko_extension/";
    private static final String EXTENSION_ID = "gecko_bridge@example.com";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        GeckoView geckoView = findViewById(R.id.geckoview);
        geckoSession = new GeckoSession();
        geckoView.setSession(geckoSession);

        // 注册消息桥接扩展
        WebExtension.Installer installer = geckoSession.getWebExtensionController()
                .installBuiltIn(EXTENSION_LOCATION, EXTENSION_ID);
        installer.whenComplete(extension -> {
            messageBridgeExtension = extension;
            // 设置扩展消息监听
            messageBridgeExtension.setMessageDelegate(new WebExtension.MessageDelegate() {
                @Override
                public void onMessage(String nativeApp, WebExtension.MessageSender sender, Object message, WebExtension.MessageSender.Response response) {
                    // 接收页面发来的消息
                    if (nativeApp.equals("gecko_bridge") && message instanceof org.json.JSONObject) {
                        try {
                            org.json.JSONObject msgJson = (org.json.JSONObject) message;
                            if (msgJson.getString("type").equals("PAGE_TO_APP")) {
                                String content = msgJson.getString("content");
                                onMessageFromPage(content);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, "gecko_bridge");
            // 扩展加载完成后再加载目标页面
            geckoSession.loadUri("http://example.com/x.html");
        }, throwable -> {
            Log.e("GeckoExtension", "扩展加载失败", throwable);
        });
    }

    // Android按钮点击回调
    public void onSendButtonClick(View view) {
        if (messageBridgeExtension == null) return;
        try {
            // 构造发往页面的消息
            org.json.JSONObject msg = new org.json.JSONObject();
            msg.put("type", "APP_TO_PAGE");
            msg.put("content", "helloFromApp");
            // 发送给扩展后台
            messageBridgeExtension.sendMessage(EXTENSION_ID, msg, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 接收页面消息的回调
    public void onMessageFromPage(String s) {
        Log.d("msgFromPage", s);
        // 此处可自行扩展业务逻辑
    }
}

适配说明

如果你的页面域名不是http://example.com,需要同步修改以下三处配置:

  • manifest.json里的matches规则
  • content_script.js里的origin校验逻辑
  • 页面pageToApp方法中postMessage的目标域名参数

内容的提问来源于stack exchange,提问作者Flavio Lenz Cesar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 01:54:08