原生App WebView能否仅为宿主开放unsafe-eval,同时禁止其他内容使用?
关于CSP规则的疑问解答
首先明确:unsafe-eval是CSP针对全局JS执行上下文的控制规则,不支持针对特定调用源(比如原生端)单独加白名单,只要开启就会对所有页面内的JS执行生效,不符合你的安全需求。
无需放宽CSP的通信方案(推荐)
你完全不需要借助动态eval就能实现App到JS的运行时通信,核心思路是提前在页面加载阶段注入固定的通信桥接代码,原生端仅调用预定义的固定桥接方法即可,这类调用不会触发CSP的unsafe-eval限制。
具体实现步骤如下:
- 页面加载阶段(你已经可以实现脚本注入的阶段)注入固定的桥接JS代码:
// 注入的全局桥接对象,固定代码无动态逻辑 window.AppCommunicationBridge = { // 存储业务方注册的消息处理回调 messageHandler: null, // 业务层调用该方法注册消息回调 registerHandler: function(handler) { this.messageHandler = handler }, // 供原生端调用的固定接收方法 receiveNativeMessage: function(messageStr) { if (typeof this.messageHandler === 'function') { try { const message = JSON.parse(messageStr) this.messageHandler(message) } catch (e) { console.error('Native message parse error', e) } } } }
- 原生端需要向JS发送消息时,直接调用上述预定义的固定方法即可:
- iOS WKWebView:调用
evaluateJavaScript执行的代码为固定格式:window.AppCommunicationBridge.receiveNativeMessage('<序列化后的消息JSON字符串>') - Android WebView:调用
evaluateJavascript执行上述相同格式的代码即可,4.4以下系统可以用loadUrl("javascript:" + 上述代码)
- iOS WKWebView:调用
注意:序列化消息时需要对JSON字符串中的单引号、反斜杠、换行符等特殊字符做转义,避免破坏JS字符串语法。
- 如果需要实现带返回值的异步调用,可以在消息中携带唯一的
requestId,JS处理完成后通过你已经实现的JS到原生桥(WKScriptMessageHandler/JavascriptInterface)将requestId和处理结果回传给原生端即可。
备选轻量方案(无需预先注入代码)
如果不想注入桥接代码,还可以通过浏览器原生事件实现通信:
- 原生端修改当前页面的
location.hash,将消息编码后放在hash中,JS监听hashchange事件即可拿到消息,hash修改不会触发页面重载,也没有CSP限制。 - 原生端可以通过修改
document.title传递短消息,JS监听DOMAttrModified或者轮询title变化获取消息,适合短消息场景。
内容的提问来源于stack exchange,提问作者jlew
相关产品推荐
相关产品推荐

