【问题标题】:Accessing JS code from an android Native app从 android Native 应用程序访问 JS 代码
【发布时间】:2013-07-28 23:45:38
【问题描述】:

这似乎是一个奇怪的问题,但我很想知道它是否可行。我正在研究 POC,因此必须证明或反驳它是否有效。

Android 应用程序中的 UI 将是原生的(Java + XML 布局)+ 一些其他设备功能访问,例如(相机/文件系统等)。

我已经构建了一个 JS 库,其中包含一些执行 Ajax 发布和获取请求的函数。

在应用程序中,我有一个不可见的 Webview,我在其中加载了一个空白 HTML(引用这个 JS 库)。在那个 WebView 中,我注入了一个 JavascripInterface。所以,本质上,UI 是原生的,你永远不会看到 Webview。这只是一个主机,它提供对我的 JS 库对本机代码的访问。

现在,在我的 UI 上执行某些操作时,我调用 Webview 上的 JS 函数,该函数又尝试进行 ajax 调用(loadUrl 调用 ex.javascipt:functionName())。但是,这些调用失败了,没有任何可见的错误。

注意:如果我将它加载到我的桌​​面浏览器上,同样的 HTML 文件也可以工作。 AJAX 调用成功。

但是,当我通过 JavascriptInterface(或 webview.loadUrl() 调用)发起 Ajax 调用时,它们会失败,响应状态为 0。

除了 AJAX 之外的东西,比如简单的函数调用、警报和通过 javascript 接口进行的回调都可以正常工作。

问:我知道这是一种奇怪且不切实际的做事方式。但是,它/应该起作用吗

更新:即使设置了

setBlockNetworkLoads(false)
,还是不行。

我尝试记录 JS 调用和错误,得到了这个错误。

请求头域 X-Requested-With 不被允许 访问控制允许标头。

知道如何解决这个问题吗?

【问题讨论】:

  • 1.你有android.permission.INTERNET 的权限吗? 2. 将链接粘贴到您请求的页面或.html 文件的开头或WebView 中加载的任何内容。 3. 您在使用:developer.android.com/reference/android/webkit/…
  • 可能是线程问题 - UI 线程(视图的)和用于 ajax 请求的线程之间的问题
  • 我有权限。为什么我需要在这里使用 WebViewClient?
  • @uriz 不太明白你提到的问题。你能详细说明一下吗?
  • UI 在 UI 线程上运行。而且我假设您的回调在另一个线程上。从回调线程中,您需要显式使用 runOnUiThread 来“返回”到 UI。只是想确保问题确实与 ajax 失败有关,而不是其响应的呈现。

标签: android ajax webview cross-domain


【解决方案1】:

您似乎正在尝试执行跨域 ajax 请求。

同源策略不允许跨域请求,因此请求将被阻止。如果您在 webView 中加载本地文件,然后将 ajax 请求从它发送到其他域,就会出现这种情况。

如果是这种情况,并且是同源策略给您带来麻烦,那么您可能需要查看跨域资源共享 (CORS) 或 JSONP 来解决它。

鉴于您收到的错误,您的问题似乎与此处讨论的问题类似: Cross-Domain AJAX doesn't send X-Requested-With header

您可能希望更改服务器设置以允许 X-Requested-With 标头。

似乎从 API 级别 16 开始,webSettings 添加了一个方法 setAllowFileAccessFromFileURLs()。将 webView 设置为 true 也可以解决问题。

【讨论】:

  • CORS 或 JSONP 是否也适用于 POST 请求?我想我在某处读到 JSONP 不适用于 POST
  • 似乎是 CORS 问题。目前,我没有办法修复服务器端来检查这一点。但是,我已经在浏览器端调试了 Javascript 控制台以及服务器日志。
【解决方案2】:

我有一个类似的问题,我在本地将“网络应用”加载到 WebView,只是远程执行 Ajax。我观察到一个类似的问题,其中 Javascript 警报等工作正常,但 AJAX 调用没有。事实证明,默认情况下WebView 会阻止"network loads"

确保你这样做:

webView.getSettings().setBlockNetworkLoads(false);

这对我有用。澄清一下,我没有使用 Javascript 接口 - 只是使用 webView.loadDataWithBaseUrl() 按原样加载 Web 应用程序 - 传递给此方法的 baseUrl 参数是我执行所有 AJAX 调用的地方(因为此方法尊重相同的来源策略)

【讨论】:

  • 文档说如果你有 INTERNET 权限,默认值为 false。我有互联网许可。结果还是一样。这里必须使用什么作为 baseURL?
  • 我有 INTERNET 权限,如果是 IIRC,该值仍然是 true。为什么不在日志语句中打印getBlockNetworkLoads() 的值并找出答案?关于 baseUrl - 这应该是提供 AJAX 请求的域或 IP 地址。您在 AJAX 请求中使用的相对路径会附加到 baseUrl 以形成完整的 URL。您的 AJAX 调用将仅限于该域 - 您将无法对其他域进行 AJAX 调用(这符合同源策略)
  • 对于我的请求,我会发布请求,并且只有一个 URL。没有 url 路径。
  • 我们以 Github API 为例:POST https://api.github.com/user/repos 将创建一个新的 repo。在 JS 中,您只需将 /user/repos 传递给 XHR 的 open 方法。那就是路径。 https://api.github.com 部分是 baseUrl。您只能在该域中调用 API。例如,您不会被允许调用 StackOverflow API。
  • 另外,您是否尝试记录getBlockNetworkLoads() 方法的值?我记得为此收到了true。我必须将其显式设置为 false 才能正常工作。
猜你喜欢
  • 2017-09-23
  • 1970-01-01
  • 2017-08-24
  • 1970-01-01
  • 2014-03-08
  • 2015-05-04
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
相关资源
最近更新 更多