Android 中任何第三方软件都可访问剪切板内容,虽然高版本对剪切板做了访问限制,但是还是需要照顾一下低版本的,解决方法就是要禁用复制剪切选项。下边来看具体实现吧。
1、自定义NoMenuEditText 继承自AppCompatEditText
2、重写isSuggestionsEnabled方法
并返回false
创建canPaste()
方法并返回false。该方法是一个隐藏方法
3、实现ActionMode.Callback回调
private class ActionModeCallbackInterceptor implements ActionMode.Callback {
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
//删除复制选项
MenuItem itemCopy = menu.findItem(android.R.id.copy);
if (itemCopy != null) {
menu.removeItem(android.R.id.copy);
}
//删除剪切选项
MenuItem itemCut = menu.findItem(android.R.id.cut);
if (itemCut != null) {
menu.removeItem(android.R.id.cut);
}
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
}
4、设置回调
this.setLongClickable(false);
//this.setTextIsSelectable(false);
this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
//使用该方式基本可以实现禁用粘贴复制功能,6.0以上可用
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.setCustomInsertionActionModeCallback(new ActionModeCallbackInterceptor());
}
使用以上方式即可禁用掉EditText的复制粘贴功能,但是长按EditTeit控件中的文本时光标会有变化,并且该方式只能在6.0以上版本中使用。如果以上方式不能满足你的需求,请看以下方式:
1、2、3步同上,修改第4步不再用 this.setCustomInsertionActionModeCallback(new ActionModeCallbackInterceptor())方法。
使用以下方式(反射)代替:
this.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
NoMenuEditText.this.clearFocus();
return false;
}
});
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// setInsertionDisabled when user touches the view
this.setInsertionDisabled();
}
return super.onTouchEvent(event);
}
private void setInsertionDisabled() {
try {
Field editorField = TextView.class.getDeclaredField("mEditor");
editorField.setAccessible(true);
Object editorObject = editorField.get(this);
@SuppressLint("PrivateApi") Class editorClass = Class.forName("android.widget.Editor");
Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
mInsertionControllerEnabledField.setAccessible(true);
mInsertionControllerEnabledField.set(editorObject, false);
} catch (Exception ignored) {
}
}
使用这种方式即可解决第一种方式的版本兼容问题,并且长按EditText控件中的文本光标也不会有任何变化,完美解决剪切板敏感信息泄露问题。希望以上方案对你有所帮助。
完整代码(别忘了点个赞哦):
@SuppressLint("NewApi")
public class NoMenuEditText extends AppCompatEditText {
private final Context context;
/**
* 该方法为隐藏方法
*/
boolean canPaste() {
return false;
}
@Override
public boolean isSuggestionsEnabled() {
return false;
}
public NoMenuEditText(Context context) {
super(context);
this.context = context;
init();
}
public NoMenuEditText(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public NoMenuEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
init();
}
@SuppressLint("ClickableViewAccessibility")
private void init() {
this.setLongClickable(false);
//this.setTextIsSelectable(false);
this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
//使用该方式基本可以实现禁用粘贴复制功能,6.0以上可用
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// this.setCustomInsertionActionModeCallback(new ActionModeCallbackInterceptor());
// }
this.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
NoMenuEditText.this.clearFocus();
return false;
}
});
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// setInsertionDisabled when user touches the view
this.setInsertionDisabled();
}
return super.onTouchEvent(event);
}
private void setInsertionDisabled() {
try {
Field editorField = TextView.class.getDeclaredField("mEditor");
editorField.setAccessible(true);
Object editorObject = editorField.get(this);
@SuppressLint("PrivateApi") Class editorClass = Class.forName("android.widget.Editor");
Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
mInsertionControllerEnabledField.setAccessible(true);
mInsertionControllerEnabledField.set(editorObject, false);
} catch (Exception ignored) {
}
}
/**
* Prevents the action bar (top horizontal bar with cut,copy,paste,etc.)
* from appearing by intercepting the callback that would cause it to be
* created,and returning false.
*/
private class ActionModeCallbackInterceptor implements ActionMode.Callback {
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
//删除复制选项
MenuItem itemCopy = menu.findItem(android.R.id.copy);
if (itemCopy != null) {
menu.removeItem(android.R.id.copy);
}
//删除剪切选项
MenuItem itemCut = menu.findItem(android.R.id.cut);
if (itemCut != null) {
menu.removeItem(android.R.id.cut);
}
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
}
}
参考:https://stackoverflow.com/questions/41673185/disable-edittext-context-menu