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

Android WebView加载本地网页调用蓝牙API报错的解决方案咨询

可行解决方案:在Android应用中实现本地网页调用蓝牙功能

Android系统WebView默认不支持Web Bluetooth API(navigator.bluetooth),原因有两点:一是该API属于Chrome专属特性,系统WebView未默认启用;二是file://协议不属于Web Bluetooth要求的安全上下文(仅HTTPS、localhost等被允许)。以下是两种可行的解决思路:

方案一:通过JS与原生蓝牙功能桥接(推荐)

直接借助Android原生蓝牙API实现功能,通过@JavascriptInterface暴露给网页JS调用,兼容性和可控性最强。

步骤1:实现原生蓝牙操作类

创建一个处理蓝牙逻辑的类,用@JavascriptInterface注解暴露需要的方法:

public class BluetoothBridge {
    private Context mContext;
    private BluetoothAdapter mBluetoothAdapter;

    public BluetoothBridge(Context context) {
        mContext = context;
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    @JavascriptInterface
    public boolean isBluetoothEnabled() {
        return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
    }

    @JavascriptInterface
    public void requestEnableBluetooth() {
        Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        ((Activity) mContext).startActivityForResult(enableIntent, 1);
    }

    @JavascriptInterface
    public List<String> getPairedDevices() {
        List<String> deviceList = new ArrayList<>();
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            return deviceList;
        }
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
        for (BluetoothDevice device : pairedDevices) {
            deviceList.add(device.getName() + "|" + device.getAddress());
        }
        return deviceList;
    }
}

步骤2:配置WebView并注入桥接对象

在Activity中启用JS支持,并将桥接类注入WebView:

WebView webView = findViewById(R.id.webview);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
// 注入桥接对象,JS中可通过window.bluetoothBridge调用
webView.addJavascriptInterface(new BluetoothBridge(this), "bluetoothBridge");
webView.loadUrl("file:///android_asset/index.html");

步骤3:修改网页JS代码

替换原有的navigator.bluetooth.getDevices()调用,改为调用原生桥接方法:

async function fetchBluetoothDevices() {
    try {
        const isEnabled = window.bluetoothBridge.isBluetoothEnabled();
        if (!isEnabled) {
            window.bluetoothBridge.requestEnableBluetooth();
            // 可结合Android的onActivityResult回调,通过webView.loadUrl("javascript:xxx")通知JS授权结果
            return;
        }
        const pairedDevices = window.bluetoothBridge.getPairedDevices();
        // 转换为模拟Web Bluetooth Device的结构
        const formattedDevices = pairedDevices.map(item => {
            const [name, address] = item.split('|');
            return { name, id: address };
        });
        console.log('已配对设备:', formattedDevices);
        return formattedDevices;
    } catch (err) {
        console.error('蓝牙操作失败:', err);
    }
}

步骤4:添加蓝牙权限

在AndroidManifest.xml中声明所需权限:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ 额外需要 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />

方案二:通过本地HTTP服务器启用Web Bluetooth API

如果坚持使用Web Bluetooth原生API,需将本地网页通过localhost服务暴露(满足安全上下文要求),同时确保WebView版本足够高(Chrome 56+)。

步骤1:集成本地HTTP服务器

添加NanoHTTPD依赖到build.gradle:

implementation 'org.nanohttpd:nanohttpd:2.3.1'

步骤2:实现本地服务器

创建服务器类,将assets目录作为静态资源根目录:

public class LocalAssetServer extends NanoHTTPD {
    private Context mContext;

    public LocalAssetServer(Context context, int port) {
        super(port);
        mContext = context;
    }

    @Override
    public Response serve(IHTTPSession session) {
        String uri = session.getUri().equals("/") ? "/index.html" : session.getUri();
        try {
            InputStream assetStream = mContext.getAssets().open(uri.substring(1));
            String mimeType = getMimeType(uri);
            return newChunkedResponse(Response.Status.OK, mimeType, assetStream);
        } catch (IOException e) {
            return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/plain", "资源不存在");
        }
    }

    private String getMimeType(String uri) {
        if (uri.endsWith(".html")) return "text/html";
        if (uri.endsWith(".js")) return "application/javascript";
        if (uri.endsWith(".css")) return "text/css";
        return "text/plain";
    }
}

步骤3:启动服务器并加载网页

在Activity中启动服务器,让WebView访问localhost地址:

LocalAssetServer server = new LocalAssetServer(this, 8080);
try {
    server.start();
} catch (IOException e) {
    e.printStackTrace();
}

WebView webView = findViewById(R.id.webview);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);

webView.loadUrl("http://localhost:8080/index.html");

注意:该方案受WebView版本和系统限制,部分设备可能无法正常启用Web Bluetooth,仅适合测试或特定场景。

内容的提问来源于stack exchange,提问作者Wolfgang Wieser

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:58:14