Android: how to select texts from webview

2019-01-03 15:24发布

i want allow user to select some texts from webview and it need to be send as a text message. pls find way to select text and copy to clipboard and extracting from clipboard. i saw many example but nothing helped me really...TIA

Edit
using the code provided in the link from @orangmoney52. with following changes

getmethod's second parameter and invoke method second parameter. if i give null there warning will come.. which one is correct?

 public void selectAndCopyText() {
     try {
         Method m = WebView.class.getMethod("emulateShiftHeld", Boolean.TYPE); 
            m.invoke(BookView.mWebView, false); 
        } catch (Exception e) {
            e.printStackTrace();
            // fallback
            KeyEvent shiftPressEvent = new KeyEvent(0,0,
                 KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT,0,0);
            shiftPressEvent.dispatch(this);
        }

}

Getting this error:

 05-26 16:41:01.121: WARN/System.err(1096): java.lang.NoSuchMethodException: emulateShiftHeld  

4条回答
Root(大扎)
2楼-- · 2019-01-03 15:51

The easiest way, although not as pretty as what seems like a per manufacturer implemented copy/paste feature, is the following:

https://bugzilla.wikimedia.org/show_bug.cgi?id=31484

Basically, if you're setting your own WebChromeClient via webview.setWebChromeClient(...) then text selection is disabled by default. To enable it your WebChromeClient needs to have to following method implemented:

//@Override
/**
* Tell the client that the selection has been initiated.
*/
public void onSelectionStart(WebView view) {
    // Parent class aborts the selection, which seems like a terrible default.
    //Log.i("DroidGap", "onSelectionStart called");
}
查看更多
混吃等死
3楼-- · 2019-01-03 15:56

Step: 1 Create custom WebView class. This class will override the native action bar on long press on the webview text. Also it handles the the selection case for different version of android (tested on 4.0 onwards) This code takes the selected text using javascript.

public class CustomWebView extends WebView {
private Context context;
// override all other constructor to avoid crash
public CustomWebView(Context context) {
    super(context);
    this.context = context;
    WebSettings webviewSettings = getSettings();
    webviewSettings.setJavaScriptEnabled(true);
    // add JavaScript interface for copy
    addJavascriptInterface(new WebAppInterface(context), "JSInterface");
}

// setting custom action bar
private ActionMode mActionMode;
private ActionMode.Callback mSelectActionModeCallback;
private GestureDetector mDetector;

// this will over ride the default action bar on long press
@Override
public ActionMode startActionMode(Callback callback) {
    ViewParent parent = getParent();
    if (parent == null) {
        return null;
    }
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
        String name = callback.getClass().toString();
        if (name.contains("SelectActionModeCallback")) {
            mSelectActionModeCallback = callback;
            mDetector = new GestureDetector(context,
                    new CustomGestureListener());
        }
    }
    CustomActionModeCallback mActionModeCallback = new CustomActionModeCallback();
    return parent.startActionModeForChild(this, mActionModeCallback);
}

private class CustomActionModeCallback implements ActionMode.Callback {

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        mActionMode = mode;
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false; 
    }

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {

        switch (item.getItemId()) {
        case R.id.copy:
            getSelectedData();
            mode.finish(); 
            return true;
        case R.id.share:
            mode.finish();
            return true;
        default:
            mode.finish();
            return false;
        }
    }
    @Override
    public void onDestroyActionMode(ActionMode mode) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            clearFocus();
        }else{
             if (mSelectActionModeCallback != null) {
                 mSelectActionModeCallback.onDestroyActionMode(mode);
             }
             mActionMode = null;
        }
    }
}
private void getSelectedData(){

    String js= "(function getSelectedText() {"+
            "var txt;"+
            "if (window.getSelection) {"+
                "txt = window.getSelection().toString();"+
            "} else if (window.document.getSelection) {"+
                "txt = window.document.getSelection().toString();"+
            "} else if (window.document.selection) {"+
                "txt = window.document.selection.createRange().text;"+
            "}"+
            "JSInterface.getText(txt);"+
          "})()";
    // calling the js function
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        evaluateJavascript("javascript:"+js, null);
    }else{
        loadUrl("javascript:"+js);
    }
}

private class CustomGestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        if (mActionMode != null) {
            mActionMode.finish();
            return true;
        }
        return false;
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    // Send the event to our gesture detector
    // If it is implemented, there will be a return value
    if(mDetector !=null)
        mDetector.onTouchEvent(event);
    // If the detected gesture is unimplemented, send it to the superclass
    return super.onTouchEvent(event);
}

}

Step 2: create separate class for WebView interface. This class listnes for event from once javascript code is getting executed

public class WebAppInterface {
Context mContext;

WebAppInterface(Context c) {
    mContext = c;
}

@JavascriptInterface
public void getText(String text) {
    // put selected text into clipdata
    ClipboardManager clipboard = (ClipboardManager)
            mContext.getSystemService(Context.CLIPBOARD_SERVICE);
    ClipData clip = ClipData.newPlainText("simple text",text);
    clipboard.setPrimaryClip(clip);
    // gives the toast for selected text
    Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
}
}

Step 3: Add menu.xml for custom menu in res > menu folder

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
    android:id="@+id/copy"
    android:icon="@drawable/ic_action_copy"
    android:showAsAction="always" 
    android:title="copy">
</item>
<item
    android:id="@+id/share"
    android:icon="@drawable/ic_action_share"
    android:showAsAction="always" 
    android:title="share">
</item>

I took help of several links listed below to achieve this: Thanks to you guys.

how to use javascript on webview http://developer.android.com/guide/webapps/webview.html#UsingJavaScript

for injecting javascript Why can't I inject this javascript in the webview on android?

for overriding default action bar How to override default text selection of android webview os 4.1+?

for version 4.0. to 4.3 text selection Webview text selection not clearing

查看更多
Summer. ? 凉城
4楼-- · 2019-01-03 15:57

@vnshetty, using the code provided in the link from @orangmoney52, I was able to complete this problem a few months ago. You can create a button in your menu that allows you to copy text. Then, in onOptionsItemSelected, you can have a clause like this:

    case R.id.select_and_copy: {
        Toast.makeText(getApplicationContext(), "Select Text", Toast.LENGTH_SHORT).show();
        selectAndCopyText();
        return true;
    }
查看更多
我只想做你的唯一
5楼-- · 2019-01-03 16:02

The above answers looks perfectly fine and it seems you're missing something while selecting text. So you need to double check the code and find your overridden any TouchEvent of webview.

i Tried below code it works fine...

Function is

 private void emulateShiftHeld(WebView view)
    {
        try
        {
            KeyEvent shiftPressEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
                                                    KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0);
            shiftPressEvent.dispatch(view);
            Toast.makeText(this, "select_text_now", Toast.LENGTH_SHORT).show();
        }
        catch (Exception e)
        {
            Log.e("dd", "Exception in emulateShiftHeld()", e);
        }
    }

Call Above method wherever you want (You can put a button and call this method in its click event): emulateShiftHeld(mWebView);

查看更多
登录 后发表回答