android - 从 webview 中获取文本

Posted

技术标签:

【中文标题】android - 从 webview 中获取文本【英文标题】:android - get Text out of webview 【发布时间】:2012-03-23 16:47:25 【问题描述】:

在我的应用程序中,我使用EPUBLIB 在webview 中显示epub html 文件。 我的问题是我想为我的 epub 阅读器使用书签功能。为此,我想从 webview 获取文本,该文本显示我的 epub 的 HTML 文件中的页面,然后在我的书签活动中使用该文本向用户显示他们已添加书签的内容。 我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

从 webview 获取纯文本内容相当困难。基本上,android 类不提供它,但 javascript 提供,并且 Android 提供了一种让 javascript 将信息传递回您的代码的方法。

在我详细介绍之前,请注意,如果您的 html 结构很简单,您最好手动解析数据

也就是说,这就是你要做的:

    Enable javascript Add your own javascript interface class,允许 javascript 与您的 Android 代码进行通信 注册您自己的webviewClient,覆盖onPageFinished 以插入一点javascript 在javascript中,获取标签的element.innerText,并将其传递给您的javascript接口。

为了澄清,我将在下面发布一个工作(但非常粗略)的代码示例。它在顶部显示一个 webview,在底部显示一个带有基于文本的内容的 textview。

package test.android.webview;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;

public class WebviewTest2Activity extends Activity 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        WebView webView = (WebView) findViewById(R.id.webView);
        TextView contentView = (TextView) findViewById(R.id.contentView);

        /* An instance of this class will be registered as a JavaScript interface */ 
        class MyJavaScriptInterface 
         
            private TextView contentView;

            public MyJavaScriptInterface(TextView aContentView)
            
                contentView = aContentView;
            

            @SuppressWarnings("unused") 

            public void processContent(String aContent) 
             
                final String content = aContent;
                contentView.post(new Runnable() 
                    
                    public void run() 
                              
                        contentView.setText(content);        
                         
                );
             
         

        webView.getSettings().setJavaScriptEnabled(true); 
        webView.addJavascriptInterface(new MyJavaScriptInterface(contentView), "INTERFACE"); 
        webView.setWebViewClient(new WebViewClient()  
            @Override 
            public void onPageFinished(WebView view, String url) 
             
                view.loadUrl("javascript:window.INTERFACE.processContent(document.getElementsByTagName('body')[0].innerText);"); 
             
        ); 

        webView.loadUrl("http://shinyhammer.blogspot.com");
    

使用以下 main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="vertical" >

    <WebView
        android:id="@+id/webView"
        android:layout_
        android:layout_
        android:layout_weight="0.5" />

    <TextView
        android:id="@+id/contentView"
        android:layout_
        android:layout_
        android:layout_weight="0.5" />


</LinearLayout>

【讨论】:

你能详细解释一下这条线吗? view.loadUrl("javascript:window.INTERFACE.processContent(document.getElementsByTagName('body')[0].innerText);"); 这是解释中的第 4 步。从左到右,它(a)加载一个 url,(b)简单地注入一些 javascript,(c)调用自定义 javascript 接口类 INTERFACEprocesContent() 方法,从 android 代码注册,传递(d)当前显示的页面正文的innerText 属性。 如果您有具体问题,请尽管提问! 作为旁注,我特意提供了一个示例,您可以将粘贴复制到一个新的 android 项目中进行测试。如果您对这些东西不熟悉,那么简单地通过源代码可能会很有启发性。它相当复杂的东西,因为它是两种不同的技术(android webview 定制、javascript fddling)结合在一起的。 谢谢。 :) 它对我很有帮助,并且示例按照你说的那样工作:) 为了他人的利益:如果您的目标 sdk 版本 >=17,则 Paul-Jan 的答案中指定的方法 processContent(...) 仅在为该方法指定 @JavascriptInterface 注释时才有效根据developer.android.com/guide/webapps/…【参考方案2】:

Java:

    wvbrowser.evaluateJavascript(
        "(function()  return ('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>'); )();",
         new ValueCallback<String>() 
            @Override
            public void onReceiveValue(String html) 
                Log.d("HTML", html); 
                // code here
            
    );

科特林:

web_browser.evaluateJavascript("(function()  return ('<html>'+document.getElementsByTagName('span')[0].innerText+'</html>'); )();")
  html ->
   Toast.makeText(this@Your_activity, html, Toast.LENGTH_SHORT).show()
   // code here
                

【讨论】:

请注意,这两种方法仍然适用于 kitkat+,只是 evaluateJavascript 是首选,因为它有一个回调,所以更容易异步(如果你特别需要返回值)... return 语句后的大括号 return () 为我工作。无论如何,它就像一个魅力!【参考方案3】:

在这种情况下,我唯一想到的就是使用 javascript。快速搜索我找到了android.webkit.WebView.addJavascriptInterface

你想学习“addJavascriptInterface”,它最终会帮助你解决问题

【讨论】:

我对js,html等不太了解。你能告诉我任何我可以遵循的好教程吗:) 看着 Paul-Jan 给出的答案,我发现我走在了正确的轨道上。如果您按照他的指示进行操作,您可能会成功。我建议你做一些研究:互联网上到处都是关于 javascript 和 html 的教程,而今天这些技能对于开发人员来说是必须的。 :D 是的,我已经开始搜索了,非常感谢您指导正确的方向。【参考方案4】:

上面提供的解决方案使用 innerText 属性提供文本,它将返回 webView 中的所有文本。我在下面提出的解决方案将帮助您从屏幕上 webView 的可见部分提取文本。

第1步:需要javaScript的帮助,因此首先启用javascript。

webView.addJavascriptInterface(new IJavascriptHandler(getActivity().getApplicationContext()),     "Android"); //if your class extends a Fragment class

view.addJavascriptInterface(new IJavascriptHandler(this), "Android"); //if your class extends Activity.

第 2 步:创建一个 javaInterface 内部类。

final class IJavascriptHandler 

    Context mContext;
    IJavascriptHandler(Context c) 
    mContext = c;


//API 17 and higher required you to add @JavascriptInterface as mandatory before your method.   
@JavascriptInterface 
public void processContent(String aContent) 
 
   //this method will be called from within the javascript method that you will write.
   final String content = aContent;
   Log.e("The content of the current page is ",content);
 

第 3 步:现在您必须添加 javascript 方法。您将方法编写为字符串,然后加载它。该方法根据提供给它的参数返回文本。所以,你需要2个字符串。一个将加载 javascript 方法,另一个将调用它。

加载javascript方法的方法。

String javaScriptToExtractText = "function getAllTextInColumn(left,top,width,height)"
                +   "if(document.caretRangeFromPoint)"
                +   "var caretRangeStart = document.caretRangeFromPoint(left, top);"
                +   "var caretRangeEnd = document.caretRangeFromPoint(left+width-1, top+height-1);"
                +   " else "
                +   "return null;"
                +   ""
                +   "if(caretRangeStart == null || caretRangeEnd == null) return null;"
                +   "var range = document.createRange();"
                +   "range.setStart(caretRangeStart.startContainer, caretRangeStart.startOffset);"
                +   "range.setEnd(caretRangeEnd.endContainer, caretRangeEnd.endOffset);"
                +   "return range.toString();;";

调用上述函数的方法。

String javaScriptFunctionCall = "getAllTextInColumn(0,0,100,100)";

//I've provided the parameter here as 0,0 i.e the left and top offset and then 100, 100 as width and height. So, it'll extract the text present in that area.

第 4 步:现在,您需要加载上述 2 个 javascript。

webView.loadUrl("javascript:"+ javaScriptToExtractText);
//this will load the method.


view.loadUrl("javascript:window.Android.processContent("+javaScriptFunctionCall+");");
//this will call the loaded javascript method.

享受吧。

【讨论】:

【参考方案5】:

你为什么不直接从书中获取带有 EPUBLIB 的文本?

您在 EPUBLIB 的帮助下获得了该 html,不是吗?你是怎么把它放在webview中的?我没有看到任何例子。

【讨论】:

是的,你是对的,我将 html 文件作为字符串获取,但所有 html 标记都必须传递给 webview。我只想要一部分,意思是让我们只说那个字符串的第三段,我不能用你的方法做到这一点,对吧? 你可以把它解析出来。首先确定第一个

的位置。然后从该标签中创建文本的 substring() 。重复直到找到第 n 个标签。现在确定段落的结尾并获得最终的 substring()。

这就是保罗以不同而简单的方式回答的问题。您的方法对像我这样对 JS 不太了解的开发人员很有帮助,但是如果您知道当今世界上最重要的东西是 HTML、JS、CSS 和 android 提供了如此好的功能来在您的 java 代码中添加 js,我们必须利用它。这是我的个人意见:) 即使你使用 javascript 界面,你也只能得到 innerText() 并且你仍然需要解析段落。那么为什么不马上做呢? 我不知道,但可能 JS 中可能有一些方法可以直接给我

标签中的文本。 .

以上是关于android - 从 webview 中获取文本的主要内容,如果未能解决你的问题,请参考以下文章

(转)完美解决 Android WebView 文本框获取焦点后自动放大有关问题

如何从 webview 隐藏文本选择句柄:android

Android WebView 文本框确认密码第二个获取焦点后设置不能自动放大

从 Android Webview 获取 POST 数据

Android webview - 如何从外部存储中获取文件

androidwebview内部弹框获取不到焦点