跳转到内容
搜索文档

移动端实施

最后更新 查看 MarkdownAgent 设置

Turnstile 需要浏览器环境,因为它是在访问者的浏览器中运行 JavaScript 质询的。在移动设备上,Turnstile 在移动端浏览器中工作而无需额外配置。

对于原生移动端应用程序,Turnstile 无法原生运行。相反,您需要使用 WebView(一种嵌入在原生应用程序内部的浏览器组件)来加载包含 Turnstile 小组件的网页。


WebView 集成

WebView 在您的原生应用程序中嵌入了一个浏览器引擎,使您能够显示网页、表单和由 JavaScript 驱动的内容(如 Turnstile 小组件)。

要求

为了让 Turnstile 在 WebView 中正常工作,必须满足以下要求。

JavaScript 支持

  • 必须启用 JavaScript 执行。
  • DOM 存储 API 必须可用。
  • 标准 Web API 必须可供访问。

网络访问

  • challenges.cloudflare.com 的访问。
  • 支持 HTTP 和 HTTPS 连接。
  • 允许连接到 about:blankabout:srcdoc

环境一致性

  • 整个会话中保持一致的 User Agent。
  • 稳定的设备和浏览器特征。
  • 不对核心浏览器行为进行修改。

特定平台的实施

Android WebView

WebView webView = findViewById(R.id.webview);
WebSettings webSettings = webView.getSettings();

// 必要项:启用 JavaScript
webSettings.setJavaScriptEnabled(true);

// 必要项:启用 DOM 存储
webSettings.setDomStorageEnabled(true);

// 推荐项:启用其他 Web 功能
webSettings.setLoadWithOverviewMode(true);
webSettings.setUseWideViewPort(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowContentAccess(true);

// 加载带有 Turnstile 的 Web 内容
webView.loadUrl("https://yoursite.com/protected-form");

iOS WKWebView (Swift)

import WebKit

class ViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 配置 WebView
        let configuration = WKWebViewConfiguration()
        configuration.preferences.javaScriptEnabled = true

        // 加载带有 Turnstile 的 Web 内容
        if let url = URL(string: "https://yoursite.com/protected-form") {
            webView.load(URLRequest(url: url))
        }
    }
}

React Native WebView

import { WebView } from "react-native-webview";

export default function App() {
	return (
		<WebView
			source={{ uri: "https://yoursite.com/protected-form" }}
			javaScriptEnabled={true}
			domStorageEnabled={true}
			allowsInlineMediaPlayback={true}
			mediaPlaybackRequiresUserAction={false}
		/>
	);
}

Flutter WebView

import 'package:flutter_inappwebview/flutter_inappwebview.dart';

class WebViewScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return InAppWebView(
      initialUrlRequest: URLRequest(
        url: Uri.parse('https://yoursite.com/protected-form')
      ),
      initialOptions: InAppWebViewGroupOptions(
        crossPlatform: InAppWebViewOptions(
          javaScriptEnabled: true,
          useShouldOverrideUrlLoading: false,
        ),
        android: AndroidInAppWebViewOptions(
          domStorageEnabled: true,
        ),
        ios: IOSInAppWebViewOptions(
          allowsInlineMediaPlayback: true,
        ),
      ),
    );
  }
}

常见实施问题

User Agent 一致性

在会话期间更改 User Agent 会导致 Turnstile 质询失败,因为系统依赖一致的浏览器特征来验证访问者的真实性。当 User Agent 在会话中期发生改变时,Turnstile 会将其视为潜在的安全风险并拒绝质询。

// Android - 设置一致的 User Agent
webSettings.setUserAgentString(webSettings.getUserAgentString());
// iOS - 保持默认的 User Agent
webView.customUserAgent = webView.value(forKey: "userAgent") as? String

内容安全策略 (CSP)

严格的内容安全策略 (Content Security Policy) 设置可能会阻止 Turnstile 加载必要的脚本并进行所需的网络连接。当 CSP 响应头或 meta 标签阻止访问 Turnstile 正常运行所需的域名和资源时,就会发生这种情况。

<meta
	http-equiv="Content-Security-Policy"
	content="
  default-src 'self'; 
  script-src 'self' challenges.cloudflare.com 'unsafe-inline'; 
  connect-src 'self' challenges.cloudflare.com;
  frame-src 'self' challenges.cloudflare.com;
"
/>

域名配置

WebView 安全限制可能会阻止访问 Turnstile 正常运行所需的域名。某些 WebView 被配置为仅允许特定的域名或阻止某些类型的连接,这可能会干扰 Turnstile 加载质询和与 Cloudflare 服务器进行通信的能力。

要解决此问题,请将您的 WebView 允许的源配置为包含 Turnstile 需要的所有域名:

  • challenges.cloudflare.com
  • about:blank
  • about:srcdoc
  • 您自己的域名

具体的配置方法因平台而异,但原则是显式允许这些域名的网络访问。

Cookie 和本地存储在会话之间未持久化可能会导致 Turnstile 失败,因为它依赖这些机制来维持状态并跟踪访问者行为。当 WebView 存储设置过于严格或应用程序在会话之间清除存储时,通常会发生这种情况。确保您的 WebView 配置为可以正确处理 cookie 和本地存储。

// Android - 启用 cookie
CookieManager.getInstance().setAcceptCookie(true);
CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
// iOS - 配置 cookie 存储
webView.configuration.websiteDataStore = WKWebsiteDataStore.default()

这篇文档对您有帮助吗?