You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Expo iOS中react-native-signature-canvas报错:无法打开URL问题求助

解决Expo环境下react-native-signature-canvas的"Unable to open URL"错误

我之前也踩过这个坑!直接用官网的通用示例在Expo里跑确实会触发这个错误,核心原因是Expo的WebView不支持组件默认使用的自定义URL Scheme通信方式——组件内部用ReactABI32_0_0-js-navigation://postMessage这类协议传递签名数据,但Expo对WebView的跳转权限做了限制,导致无法解析这个URL。

下面是亲测有效的修复方案:

1. 替换通信方式,用Expo WebView标准API传递数据

放弃组件默认的自定义URL跳转,改用Expo WebView支持的postMessage/onMessage机制来传递签名数据。具体步骤:

  • 使用expo-webview(而非原生react-native-webview,Expo环境下适配性更好)
  • 给SignatureCanvas的webviewProps注入自定义JS,替换原有的保存/清空逻辑为window.ReactNativeWebView.postMessage
  • 通过onMessage回调接收签名数据

2. 完整可运行代码示例

import React, { useState, useRef } from 'react';
import { View, Button, Text } from 'react-native';
import SignatureCanvas from 'react-native-signature-canvas';
import { WebView } from 'expo-webview';

export default function SignatureDemo() {
  const [signatureBase64, setSignatureBase64] = useState(null);
  const signatureRef = useRef(null);

  // 处理WebView传递的签名数据
  const handleWebViewMessage = (event) => {
    try {
      const messageData = JSON.parse(event.nativeEvent.data);
      if (messageData.type === 'SAVED') {
        // 拿到签名的base64字符串
        setSignatureBase64(messageData.base64);
      } else if (messageData.type === 'CLEARED') {
        setSignatureBase64(null);
      }
    } catch (err) {
      console.error('解析签名数据失败:', err);
    }
  };

  // 自定义签名画布样式
  const customWebStyle = `
    .m-signature-pad--footer { display: flex; gap: 10px; padding: 10px; }
    .m-signature-pad--body { border: 2px solid #2196F3; border-radius: 8px; }
    button { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; }
    #save { background-color: #2196F3; color: white; }
    #clear { background-color: #f44336; color: white; }
  `;

  return (
    <View style={{ flex: 1, padding: 20 }}>
      <SignatureCanvas
        ref={signatureRef}
        webStyle={customWebStyle}
        // 注入JS替换原有的URL跳转逻辑
        webviewProps={{
          onMessage: handleWebViewMessage,
          injectedJavaScript: `
            // 替换保存按钮的点击事件
            document.getElementById('save').addEventListener('click', () => {
              const canvas = document.querySelector('canvas');
              const base64 = canvas.toDataURL('image/png');
              window.ReactNativeWebView.postMessage(JSON.stringify({
                type: 'SAVED',
                base64: base64
              }));
            });
            // 替换清空按钮的点击事件
            document.getElementById('clear').addEventListener('click', () => {
              window.ReactNativeWebView.postMessage(JSON.stringify({
                type: 'CLEARED'
              }));
            });
          `
        }}
      />

      <View style={{ marginTop: 20, alignItems: 'center' }}>
        {signatureBase64 ? (
          <Text style={{ color: '#2E7D32' }}>签名已保存 ✅</Text>
        ) : (
          <Text style={{ color: '#757575' }}>请在上方绘制签名</Text>
        )}
        <Button 
          title="手动清空签名" 
          onPress={() => signatureRef.current?.clearSignature()}
          style={{ marginTop: 10 }}
        />
      </View>
    </View>
  );
}

3. 额外注意事项

  • 确保安装了expo-webview:执行npx expo install expo-webview
  • 测试时使用Expo Go或自定义开发客户端,Web环境下WebView的通信逻辑略有不同
  • 若使用较旧的Expo SDK版本,注意对应react-native-signature-canvas的版本兼容性(建议使用最新稳定版)

内容的提问来源于stack exchange,提问作者Bhushan Patil

火山引擎 最新活动