Android 3.x ONLY WebView Text Selection + JavaScript
Asked Answered
O

2

10

Problem domain: Android WebView based ePub format reader --

We need text highlights which are accessible via JavaScript methods (ie turn em on, turn em off, save them email them, etc)

Anyone in the know, please correct me if I'm wrong: During text selection on a WebView --

Basically we are handed a TextView overlay (WebTextView) which is IN NO WAY attached to the underlying html other than visually (nice job on lining it all up and making it seamless, btw), on which we perform the TextSelectionActionMode and the ClipboardManager is supplied with the results... to make that clear, the actual HTML with the WebView IS NOT actually selected at any time during this stock process, which is why the JavaScript cannot access the results of the action.

So in order to make this behavior work in 3.1+, I have a few possible plans going forward to implement my own selection on a WebView -- this is the part where I'm wondering if I cannot see out of my corner :) --

1) capture MOTION_DOWN of the long click which initiates selection mode, override the built in TextSelection ActionMode( to provde the clients branding -- the way I found to do so is so hackish it hurts) watch the drag, capture MOTION_UP position, map these coords onto the WebView, and make my selection based on the coords (while comparing the text to that captured by the ClipboardManager)

2) create my own "WebTextView" (whole lotta work lol) and not-so- hackishly create my own ActionMode and do all of the above.

3) use the MotionEvents generated by the stock selection process and somehow override the stock TextSelection ActionMode triggered by this.

These are the options I see, hopefully my proximity and frustration with this have blinded me to a simpler (read that as built-in) solution or two.

Thanks again for your time.

Orten answered 4/8, 2011 at 21:0 Comment(0)
R
12

I got this working in 2.2 - 4.0.3. I used a javascript interface and passed all touches to it. The solution seems to work pretty well and I've put an example project on github. The github project includes the necessary js in the assets folder as well as a test page and web view that loads the test page and implements all necessary methods to handle the selection. The link to the github project is https://github.com/btate/BTAndroidWebViewSelection. Have at it.

Roter answered 6/7, 2012 at 18:46 Comment(2)
Nice, I couldn't use the various JS libraries due to the speed hit when loading large HTML pages (specific to our apps), so I ended up writing the js from scratch.Orten
@btate above github project is not working for OS version 4.1 +.Fadden
R
2

I'm not 100% sure what methods/properties give you the Range and Selection. I didn't see any in the documentation. But I was able to get the selected range in pixels using reflection. Not sure if this helps anybody, but thought it was worth posting here.

Region result = null;
try {
     Object[] params = null;

     Method nativeGetSelectionRegion = WebView.class.getDeclaredMethod("nativeGetSelectionRegion");
     nativeGetSelectionRegion.setAccessible(true);     
     result = (Region)nativeGetSelectionRegion.invoke(this, params);


     Log.i(TAG, "res: region " + result.getBounds().toShortString());

 } catch (Exception e) {
     e.printStackTrace();
 }

Hopefully that helps somebody

EDIT: This doesn't work on 3.1+

Roter answered 9/4, 2012 at 14:57 Comment(8)
trusting reflection is painful, to say the least... trusting javascript is equally painful (as I now know, my solution is broken in 4.0's WebView, working on the "how" as I type) in Javascript, document.getSelection() returns the Selection object, from which you can gather the actual location in Document terms developer.mozilla.org/en/DOM/window.getSelection (it applies to document or window interface) I would not trust anything derived via reflection in the Android world; quite simply, they will break it. All that being said, that is a nice backup plan should javascript fail!Orten
How are you triggering that document.getSelection()? We tried that originally and found that loading javascript via loadUrl("javascript: document.getSelection()"); caused the selection to clear so there was nothing there.Roter
you need to do the heavy lifting inside the webview with javascript, and return a (in my case) pipe-delimited String with the pertinent data that you're after. ie, use the JavaScriptInterface as a receiver for the "flattened" Selection Object that is generated within javascript. Also, depending on what you're doing with that data (I used mine for real-time selection), keep in mind that delivery to the UI thread will be necessary (as this most likely will NOT be on the UI thread), so a Handler pattern can be, well, handy...Orten
Ahhh, just reread your post -- here's a link that may help your understanding of the process : #6240639Orten
We've tried in the past binding a mouse up event in the javascript that sends a range to the javascript interface. That event fires fine until there is a selection on the screen. At that point it looks like the webTextView immediately takes over and the mouse up event is never registered in the webView. We have to support back to 2.2, so that could be why.Roter
I have run this code on 2.2 and 2.3 devices for the inevitable "we need it for Kindle Fire" to see what breaks, and it's not the selection... (unlike ICS) Their webview is a major relic, that until ICS probably got zero love... Capturing the motion event in Java, generating the Range/Selection manually within Javascript, and not allowing the webview to process the event internally is what allowed me to do this.Orten
I understand capturing the motion event in java. But I don't understand what I'm supposed to do from there. I understand how to get the range from javascript, but the javascript doesn't seem to actually have access to it, since the selection is occurring in the WebTextView that android throws up in the middle. What event are you stopping in the web view and how are you stopping it?Roter
let us continue this discussion in chatOrten

© 2022 - 2024 — McMap. All rights reserved.