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

Android WebView如何在Firebase onNewToken时刷新页面并注入JS传Token

实现方案

FirebaseMessagingService 属于后台运行的Android组件,没有权限直接操作主线程的WebView UI,因此无法在Service内直接调用loadUrl刷新页面、注入JS。你之前考虑用Intent做跨组件传值的思路是完全可行的,具体落地逻辑如下:

核心流程

  • 在MyFirebaseMessagingService收到新Token时,通过App内部的本地广播将Token值传递给正在运行的MainActivity
  • 在MainActivity内注册广播接收器,收到Token值后,在主线程操作WebView执行JS注入、页面刷新操作
  • 现有MyWebViewClient的URL拦截、外链跳转逻辑不需要做任何调整,和本次Token传递的流程完全独立

代码修改示例

1. 调整MyFirebaseMessagingService

移除直接操作WebView的逻辑,收到新Token后发送本地广播:

package com.example.app;

import android.content.Intent;
import android.util.Log;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.firebase.messaging.FirebaseMessagingService;

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMessagingService";
    // 广播标识,需和接收端保持一致
    public static final String ACTION_TOKEN_REFRESH = "com.example.app.ACTION_TOKEN_REFRESH";
    public static final String EXTRA_NEW_TOKEN = "fcm_refreshed_token";

    @Override
    public void onNewToken(String token) {
        Log.d(TAG, "Refreshed token: " + token);
        // 构建携带Token的广播意图
        Intent refreshIntent = new Intent(ACTION_TOKEN_REFRESH);
        refreshIntent.putExtra(EXTRA_NEW_TOKEN, token);
        // 发送内部广播
        LocalBroadcastManager.getInstance(this).sendBroadcast(refreshIntent);
    }
}

说明:选用LocalBroadcastManager传递内部数据,相比全局广播更安全、传输效率更高,不会造成App外的应用接收到敏感的Token信息。

2. 调整MainActivity

  • 注册广播接收器,监听Token刷新事件
  • 收到Token后在主线程操作WebView,完成JS注入和页面刷新
package com.example.app;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

public class MainActivity extends Activity {

    public WebView mWebView;

    // 定义Token刷新的广播接收器
    private BroadcastReceiver tokenRefreshReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 从广播中取出新的FCM Token
            String newToken = intent.getStringExtra(MyFirebaseMessagingService.EXTRA_NEW_TOKEN);
            // 操作WebView注入JS,将Token传递给Web应用
            String injectJs = String.format(
                "window.postMessage({type: 'fcmTokenRefresh', token: '%s'}, '*')",
                newToken
            );
            // 适配不同安卓版本的JS执行方式
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                mWebView.evaluateJavascript(injectJs, null);
            } else {
                mWebView.loadUrl("javascript:" + injectJs);
            }
            // 如需刷新WebView当前页面,取消下面这行的注释即可
            // mWebView.reload();
        }
    };

    @Override
    @SuppressLint("SetJavaScriptEnabled")
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = findViewById(R.id.activity_main_webview);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setDatabaseEnabled(true);
        mWebView.setWebViewClient(new MyWebViewClient());

        // 加载远程Web资源
        mWebView.loadUrl("http://192.168.0.11:3000/");

        // 注册本地广播接收器
        IntentFilter filter = new IntentFilter(MyFirebaseMessagingService.ACTION_TOKEN_REFRESH);
        LocalBroadcastManager.getInstance(this).registerReceiver(tokenRefreshReceiver, filter);
    }

    @Override
    protected void onDestroy() {
        // 页面销毁时注销广播,避免内存泄漏
        LocalBroadcastManager.getInstance(this).unregisterReceiver(tokenRefreshReceiver);
        super.onDestroy();
    }

    @Override
    public void onBackPressed() {
        if(mWebView.canGoBack()) {
            mWebView.goBack();
        } else {
            super.onBackPressed();
        }
    }
}

落地注意事项

  • 如果App被切到后台、MainActivity被系统回收,收到Token刷新事件时,可直接将最新Token存入本地SharedPreferences。待用户下次打开App进入MainActivity时,自动读取存储的最新Token注入WebView,避免Token丢失。
  • 不要在Service中持有WebView的强引用,否则会导致Activity销毁时WebView无法正常释放,引发内存泄漏。
  • JS注入的逻辑可根据Web应用的实际约定调整,比如直接调用前端暴露的全局接口给后端上报Token即可。

内容的提问来源于stack exchange,提问作者Rodrigo Schneider

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.30 04:24:04