有没有一种方法可以使WebView识别用户选择文本的项目?

时间:2019-04-30 21:38:58

标签: android html

我已经开发了一个应用程序,某种文本阅读器,并且需要为其引入新的功能(用户一直在要求它-我一直打算将其整合进来,只是我从来没有想过怎么做它)。我正在从文本生成html并将其显示在webview中。我希望用户能够选择文本的一部分,然后打开上下文菜单。我要确定的是他长单击了哪个部分(html的每一行都包含预格式化的行/节号,行文本,并可能以href链接结尾),以及选择了哪一部分。一旦我弄清楚了第一部分,第二步就是将其整理出来。

我尝试使用<span id='someuniquenumber'>作为行文本,但是webView不能将其识别为锚*。我也尝试了在链接上启用文本选择(但IMHO不是理想的选择,但是如果没有其他选择,则可以使用它)。

这里是文本选择问题的一个示例-我希望能够将选择标识为“第5行,第4到10个单词”,或者至少用户已从标记为5的行中选择了文本。 / p>

image

任何帮助将不胜感激-请记住我会影响webView行为和显示的HTML代码。提前致谢。 :)

  • 事件处理程序在extra=0中返回get type='null'

如果使用标签,我不知道允许在该链接中选择文本的方法,但是如果没有标签,我将无法识别用户单击的元素(并且所选文本肯定不是唯一的,因此可能不是唯一的)在HTML中搜索)。

编辑

这是我关于webView的代码(MainActivity中的onCreate):

mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                int temp = url.lastIndexOf("/") + 1;
                String link = url.substring(temp);
                if (link.charAt(0) == 'L') {
                    link = link.substring(1);
                    LinksFragment mLinksFragment = LinksFragment.newInstance(Integer.valueOf(link),textZoom,zoomAll,sans,fragNo);
                    mLinksFragment.show(fm,"fragment_links");
                } else if (link.charAt(0) == 'C') {
                    // show or add comment
                } else {
                    // follow link
                    // append link to clipboard
                    ClipData tmp = myCB.getPrimaryClip();
                    if (!myCB.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
                        tmp = ClipData.newPlainText("text","");
                        myCB.setPrimaryClip(tmp);
                    }
                    ClipData.Item tmpI = tmp.getItemAt(0);
                    String ts = tmpI.getText().toString();
                    ts += link + " ";
                    tmp = ClipData.newPlainText("text",ts);
                    myCB.setPrimaryClip(tmp);
                }
                return true;
            }
        });

        // detect clicked element
        mWebView.setOnTouchListener(new View.OnTouchListener() {

            public boolean onTouch(View view, MotionEvent event) {
                WebView.HitTestResult hr = ((WebView)view).getHitTestResult();
                Toast.makeText(MainActivity.this, "getExtra = "+ hr.getExtra() + "Type= " + hr.getType(),
                        Toast.LENGTH_LONG).show();
                //return true;
                return false;
            }
        });
        mWebView.getSettings().setDefaultFontSize(14);
        mWebView.setBackgroundColor(0x00000000);
        mWebView.getSettings().setBuiltInZoomControls(true);
        mWebView.getSettings().setDisplayZoomControls(false);
        updateFields(); // applies custom fontface and fontsize to elements incl. mWebView
        mWebView.loadDataWithBaseURL("file:///android_asset/",wV,"text/html; charset=utf-8","utf-8",null);

这是用于生成插入到webView中的html的代码(一个单独的函数,用于获取文本,添加标题和章节标题,格式化文本)-实际文本存储在tmpStr变量中:

public String fetchText(Bible mB, boolean append, boolean filter, String wV) {

        BibleInfo.Error mE;
        String tN;
        char tT;
        int[] Lines;
        String[] Lttrs;
        int[] noVerses = new int[3];
        String fS1 = "<p class='ps'>";
        String Psalm = getResources().getString(R.string.Psalm);
        String Chapter = getResources().getString(R.string.Chapter);
        boolean estExc = false;
        char lttr = 'a'-1;

        mE = mB.mBI.mE;
        int tmp = 0;
        for (int i=0; i<3; i++) {
            tmp += mB.mBI.noBooks(i);
            noVerses[i] = mB.mBI.getLine(tmp,1,1);
        }

        // separating link data
        int cnt = 0;
        Lines = new int[mB.mLink.getLines().length];
        Lttrs = new String[mB.mLink.getLines().length];
        for (String tS:mB.mLink.getLines()) {
            tN = "";
            Lttrs[cnt] = "";
            for (tmp=0; tmp<tS.length(); tmp++) {
                tT = tS.charAt(tmp);
                if (tT>='0' && tT<='9') {
                    tN += tT;
                } else {
                    Lttrs[cnt] += tT;
                }
            }
            Lines[cnt++] = Integer.valueOf(tN);
        }
        if (!append) {
            wV = "";
        }
        noVerses = mB.mBI.getTriLink(Lines[0],mE);
        if ((noVerses[1] == 0 || (noVerses[1] == 1 && noVerses[0] != mB.mBI.getSirach())) && mB.mLink.isLong()) {
            if (mB.mBI.getTitles() != null) {
                wV += "<h1>" + mB.mBI.getTitles()[noVerses[0]] + "</h1>";
            }
        }
        for (int i=0; i<Lines.length; i++) {
            int tX = Lines[i];
            int[] temp = mB.mBI.getTriLink(tX, mE);
            if (temp[2] == 1 && mB.mLink.isLong() && temp[1] != 0) {
                if (temp[0] == mB.mBI.getPsalms()) {
                    wV += "<h2>" + Psalm + " " + temp[1] + "</h2>";
                } else {
                    wV += "<h2>" + Chapter + " " + temp[1] + "</h2>";
                }
            }
            String tmpStr = mB.getLineText(tX - 1,filter);
            if (noVerses[0] == mB.mBI.getPsalms()) {
                wV += fS1;
                if (Lttrs[i] != "") {
                    tmpStr = parseVerse(tmpStr,Lttrs[i]);
                }
                tmpStr = tmpStr.replace(mB.mBI.mSeparator, "<br>");
            } else {
                wV += "<p>";
                if (noVerses[0] == mB.mBI.getEsther()) {
                    int noBrks = 0;
                    int lastOccurrence = 0;
                    if ((temp[1]==1) & (temp[2]==1)) {
                        estExc = true;
                        while (lastOccurrence != -1){
                            lastOccurrence = tmpStr.indexOf(mB.mBI.mSeparator,lastOccurrence);
                            String tStr = "<br><sup>" + temp[2] + (char)(98+noBrks) + "</sup>&#x2005;";
                            if (lastOccurrence != -1) {
                                if (noBrks == 0) {
                                    tmpStr = "<span id='apoch'>" + tmpStr;
                                }
                                tmpStr = tmpStr.replaceFirst("\\|", tStr);
                                noBrks +=1;
                            }
                        }
                        if (tmpStr.lastIndexOf(mB.mBI.mSeparator) != -1) {
                            tmpStr += "</span>";
                        }
                        // remove character before last </sup>

                    } else {
                        estExc = false;
                        while (lastOccurrence != -1){
                            lastOccurrence = tmpStr.indexOf(mB.mBI.mSeparator,lastOccurrence);
                            String tStr =  "<br><sup>" + temp[2] + (char)(97+noBrks) + "</sup>&#x2005;";
                            if (lastOccurrence != -1) {
                                if (noBrks == 0) {
                                    tmpStr = "<span id='apoch'>" + tmpStr;
                                }
                                tmpStr = tmpStr.replaceFirst("\\|", tStr);
                                noBrks +=1;
                            }
                        }
                        if (noBrks != 0) {
                            tmpStr += "</span>";
                        }
                        tmpStr = tmpStr.replaceFirst("<span id='apoch'>","");
                        tmpStr = tmpStr.replaceFirst("<br>","<br><span id='apoch'>");
                    }
                }
            }
            // add hyperlink for links
            if (!TextUtils.isEmpty(mB.getLinks()[tX-1])) {
                lttr++;
                if (lttr>'z') { lttr = 'a'; }
                String ts= "<sup><span id='links'><a href='L" + (tX-1) + "'>" + lttr;
                ts +=  "</a></span></sup>";
                tmpStr += ts;

            }
            if (estExc) {
                wV += "<sup>" + temp[2] + "a</sup>&#x2005;" + tmpStr + "</p>";
            } else {
                wV += "<sup>" + temp[2] + "</sup>&#x2005;" + tmpStr + "</p>";
            }
        }
        wV = fS2 + wV;

        return wV;
    }

1 个答案:

答案 0 :(得分:0)

从WebView内部触发的记录事件或设置用户属性的调用必须转发到本机代码,然后才能发送到Google Analytics for Firebase。

实施JavaScript处理程序

在WebView中使用Google Analytics for Firebase的第一步是创建JavaScript函数,以将事件和用户属性转发到本机代码。以下示例显示了如何以与Android和iOS本机代码兼容的方式执行此操作

 function logEvent(name, params) {
  if (!name) {
    return;
  }

  if (window.AnalyticsWebInterface) {
    // Call Android interface
    window.AnalyticsWebInterface.logEvent(name, JSON.stringify(params));
  } else if (window.webkit
      && window.webkit.messageHandlers
      && window.webkit.messageHandlers.firebase) {
    // Call iOS interface
    var message = {
      command: 'logEvent',
      name: name,
      parameters: params
    };
    window.webkit.messageHandlers.firebase.postMessage(message);
  } else {
    // No Android or iOS interface found
    console.log("No native APIs found.");
  }
}

function setUserProperty(name, value) {
  if (!name || !value) {
    return;
  }

  if (window.AnalyticsWebInterface) {
    // Call Android interface
    window.AnalyticsWebInterface.setUserProperty(name, value);
  } else if (window.webkit
      && window.webkit.messageHandlers
      && window.webkit.messageHandlers.firebase) {
    // Call iOS interface
    var message = {
      command: 'setUserProperty',
      name: name,
      value: value
   };
    window.webkit.messageHandlers.firebase.postMessage(message);
  } else {
    // No Android or iOS interface found
    console.log("No native APIs found.");
  }
}

实现本机界面

public class AnalyticsWebInterface {

    public static final String TAG = "AnalyticsWebInterface";
    private FirebaseAnalytics mAnalytics;

    public AnalyticsWebInterface(Context context) {
        mAnalytics = FirebaseAnalytics.getInstance(context);
    }

    @JavascriptInterface
    public void logEvent(String name, String jsonParams) {
        LOGD("logEvent:" + name);
        mAnalytics.logEvent(name, bundleFromJson(jsonParams));
    }

    @JavascriptInterface
    public void setUserProperty(String name, String value) {
        LOGD("setUserProperty:" + name);
        mAnalytics.setUserProperty(name, value);
    }

    private void LOGD(String message) {
        // Only log on debug builds, for privacy
        if (BuildConfig.DEBUG) {
            Log.d(TAG, message);
        }
    }

    private Bundle bundleFromJson(String json) {
        // ...
    }

}

一旦创建了本机接口,请在WebView中注册它,以便对在WebView中运行的Javascript代码可见:

// Only add the JavaScriptInterface on API version JELLY_BEAN_MR1 and above, due to
// security concerns, see link below for more information:
// https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object,%20java.lang.String)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    mWebView.addJavascriptInterface(
            new AnalyticsWebInterface(this), AnalyticsWebInterface.TAG);
} else {
    Log.w(TAG, "Not adding JavaScriptInterface, API Version: " + Build.VERSION.SDK_INT);
}

来源:Firebase