我已经开发了一个应用程序,某种文本阅读器,并且需要为其引入新的功能(用户一直在要求它-我一直打算将其整合进来,只是我从来没有想过怎么做它)。我正在从文本生成html并将其显示在webview中。我希望用户能够选择文本的一部分,然后打开上下文菜单。我要确定的是他长单击了哪个部分(html的每一行都包含预格式化的行/节号,行文本,并可能以href链接结尾),以及选择了哪一部分。一旦我弄清楚了第一部分,第二步就是将其整理出来。
我尝试使用<span id='someuniquenumber'>
作为行文本,但是webView不能将其识别为锚*。我也尝试了在链接上启用文本选择(但IMHO不是理想的选择,但是如果没有其他选择,则可以使用它)。
这里是文本选择问题的一个示例-我希望能够将选择标识为“第5行,第4到10个单词”,或者至少用户已从标记为5的行中选择了文本。 / p>
任何帮助将不胜感激-请记住我会影响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> ";
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> ";
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> " + tmpStr + "</p>";
} else {
wV += "<sup>" + temp[2] + "</sup> " + tmpStr + "</p>";
}
}
wV = fS2 + wV;
return wV;
}
答案 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