cw-omnibus 示例解读:在 Android 编辑器中阻止 ACTION_PROCESS_TEXT 文本处理入口的 ProcessTextBlocker 安全方案
示例工程教程【免费下载链接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_项目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus点击查看免费下载本文围绕 cw-omnibus 仓库中 Introspection/ProcessTextBlocker 示例展开讲解如何在一个 Android 文本编辑器应用中屏蔽ACTION_PROCESS_TEXT“处理文本”入口防止编辑中的内容被其他应用读取。文章以该示例的源码实现为证据从协议背景、核心技巧、工程配置到对照实验逐层拆解读完你可以掌握一套不侵入 Intent 体系、仅在控件层面完成防护的可复用方案。一、为什么要“阻止” ACTION_PROCESS_TEXTACTION_PROCESS_TEXT是 Android 6.0API 23引入的文本处理协议。当用户在可编辑文本上长按并选中内容时系统会弹出一个“Process text / 处理文本”菜单列出所有声明了该 action 的第三方应用用户点击其中某一项后被选中的文本会作为Intent.EXTRA_PROCESS_TEXT附带数据发送给目标应用。从安全角度看这意味着一个普通的文本编辑器存在隐患用户选中的内容——可能是邮件正文、配置文件、密码笔记等敏感数据——会被“顺理成章”地投递给翻译、搜索、分享之类的任意第三方应用而用户未必意识到文本被完整传出去了。本示例的 README.markdown 对此给出了明确动机This sample Android app demonstrates blockingACTION_PROCESS_TEXTfrom your Android app, for security reasons.即出于安全原因主动屏蔽该入口。仓库中与其成对存在的 Introspection/ProcessText 示例则演示了“接收端”如何实现ACTION_PROCESS_TEXT处理两者对照阅读可以完整理解这套协议的攻防两面。二、示例工程结构一览ProcessTextBlocker 是典型的单模块 Android Studio 工程源码位于 app/src/main 下Introspection/ProcessTextBlocker/ ├── app/ │ ├── build.gradle │ └── src/main/ │ ├── AndroidManifest.xml │ ├── java/com/commonsware/android/fileseditor/ │ │ ├── AbstractPermissionActivity.java // 运行时权限模板 │ │ ├── EditorFragment.java // 编辑器 阻止 PROCESS_TEXT 的核心 │ │ ├── MainActivity.java // 入口 Activity │ │ └── SampleAdapter.java // 三个存储位置的 Tab 适配器 │ └── res/ │ ├── layout/ // main.xml、editor.xml │ └── values/ // strings.xml、styles.xml、colors.xml ├── build.gradle // 顶层构建脚本 └── settings.gradle值得注意的第一点这个工程的 Java 包名是com.commonsware.android.fileseditor类结构与仓库中 Files/FilesEditor 示例几乎一致——它本质上是“文件编辑器”示例加上了阻止文本处理入口的能力为验证防护效果提供了一个真实的文本编辑场景。值得注意的第二点AndroidManifest.xml 中只有MAIN/LAUNCHER的 intent-filter没有任何与ACTION_PROCESS_TEXT相关的声明。这一点很关键它说明“阻止”发生在 UI 控件层面而不是 Intent 过滤层面下文会展开解释。三、核心实现用 PasswordTransformationMethod 子类屏蔽“处理文本”菜单3.1 关键代码位置整个方案的落点在 EditorFragment.java 的onCreateView()中Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View resultinflater.inflate(R.layout.editor, container, false); editorresult.findViewById(R.id.editor); editor.setTransformationMethod(new DummyTransformationMethod()); return(result); }第 67 行的setTransformationMethod(new DummyTransformationMethod())就是全部“机关”。编辑器布局 editor.xml 本身只是一个普通的EditTextandroid:inputTypetextMultiLine并没有设置密码输入类型。3.2 DummyTransformationMethod 源码解读同文件末尾定义了DummyTransformationMethod第 178210 行private static class DummyTransformationMethod extends PasswordTransformationMethod { Override public CharSequence getTransformation(CharSequence source, View view) { return(source); } Override public void onTextChanged(CharSequence s, int start, int before, int count) { // no-op } Override public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect) { // no-op } Override public void afterTextChanged(Editable s) { // no-op } Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // no-op } }它做了两件事继承PasswordTransformationMethod让系统把该EditText当作“密码输入”处理。Android 框架的公开行为是密码输入框不会向用户提供ACTION_PROCESS_TEXT菜单入口从而切断了选中文本被投递给第三方应用的通道。覆写getTransformation()原样返回 sourcePasswordTransformationMethod的默认行为是把输入字符全部替换成圆点密码掩码。这里重写为直接返回原文因此界面仍然以明文显示用户看起来就是一个普通多行文本框既保留了编辑体验又拿到了“无 Process text 菜单”的副作用。其余四个回调全部写成 no-op是为了避免密码变换逻辑在文本变化、焦点变化时产生任何额外副作用。需要说明的是这一技巧依赖的是 Android 框架“密码输入不提供文本处理菜单”的既定行为并非官方提供的显式开关 API本示例正是利用该行为实现“阻止”的目的。若未来框架行为发生变化方案也需要随之调整。四、为什么“阻止”不在 Intent 层做对比接收端示例 Introspection/ProcessText/app/src/main/AndroidManifest.xml 可见要实现ACTION_PROCESS_TEXT的应用是这样声明的intent-filter action android:nameandroid.intent.action.PROCESS_TEXT/ category android:nameandroid.intent.category.DEFAULT / data android:mimeTypetext/plain / /intent-filter而 ProcessTextBlocker 的 Manifest 完全没有这样的过滤器。原因在于PROCESS_TEXT 菜单是系统按“当前编辑控件”动态生成的即使你的应用自身不声明任何 intent-filter只要界面上存在可编辑文本框系统就会在长按菜单中列出其他应用注册的文本处理服务。因此单纯不在自己应用里注册过滤器并不能阻止用户选中内容被发往第三方必须在控件层面让系统认为该输入框“不可处理文本”——这正是PasswordTransformationMethod子类方案的价值所在。五、工程配置与运行验证5.1 Gradle 配置app/build.gradle 中与本主题相关的关键配置apply plugin: com.android.application dependencies { implementation com.android.support:support-fragment:27.1.1 } android { compileSdkVersion 27 buildToolsVersion 27.0.3 defaultConfig { minSdkVersion 15 targetSdkVersion 27 applicationId com.commonsware.android.fileseditor.ptb } }minSdkVersion 15ACTION_PROCESS_TEXT自 API 23 才有但工程仍可运行在更老设备上老版本没有该菜单天然不受影响applicationId com.commonsware.android.fileseditor.ptb与 Manifest 中的package属性分离便于与原始 FilesEditor 示例共存安装依赖support-fragment提供FragmentActivity、FragmentPagerAdapter等兼容层组件。仓库根目录 README.markdown 同时提醒所有示例项目均可直接导入 Android Studio 构建但导入前务必检查gradle-wrapper.properties若用命令行构建本仓库未附带gradlew需要自行准备本地 Gradle 3.3 以上环境。5.2 界面与编辑场景MainActivity.java 继承自AbstractPermissionActivity在onReady()中加载 main.xmlViewPagerPagerTabStrip并由 SampleAdapter.java 提供三个编辑 Tab字符串资源见 strings.xmlTab文件位置InternalgetFilesDir()/test.txtExternalgetExternalFilesDir(null)/test.txtPublicEnvironment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS)/test.txt由于涉及外部存储写入工程在 AndroidManifest.xml 声明了WRITE_EXTERNAL_STORAGE并通过 AbstractPermissionActivity.java 走标准的运行时权限流程onCreate中检查权限齐全则直接onReady()否则requestPermissions()申请回调中再次校验不通过则触发onPermissionDenied()提示并finish()。这个权限模板与主题无直接关系仅作为示例在 Android 6.0 上顺利运行的支撑。编辑器本身EditorFragment.java是完整的文件读写实现LoadTextTask在后台线程用BufferedReader读取文件SaveThread在onPause()时把文本写回并用fos.getFD().sync()落盘setRetainInstance(true)保证旋转后保留编辑状态。5.3 运行与验证步骤用 Android Studio 导入Introspection/ProcessTextBlocker目录或命令行gradle assembleDebug构建在设备/模拟器上安装运行Android 6.0 及以上系统进入任一 Tab输入或加载一段文本长按并选中文本观察弹出的上下文菜单不会出现“Process text / 处理文本”条目对照安装仓库中未加防护的文件编辑器示例相同操作下菜单会列出第三方文本处理应用即可直观确认防护生效。六、对照如何正确“实现” ACTION_PROCESS_TEXT为了理解协议全貌再看接收端示例 Introspection/ProcessText。其 MainActivity.java 展示了接收与回传的标准写法if (Build.VERSION.SDK_INT Build.VERSION_CODES.M) { if (Intent.ACTION_PROCESS_TEXT.equals(getIntent().getAction())) { search getIntent().getStringExtra(Intent.EXTRA_PROCESS_TEXT); if (search null) { search getIntent() .getStringExtra(Intent.EXTRA_PROCESS_TEXT_READONLY); } } }先判断Build.VERSION.SDK_INT M因为该协议只在 Android 6.0 存在用getStringExtra(Intent.EXTRA_PROCESS_TEXT)取到被选中的文本若为 null回退读取EXTRA_PROCESS_TEXT_READONLY只读文本场景处理完成后通过setResult(Activity.RESULT_OK, new Intent().putExtra(Intent.EXTRA_PROCESS_TEXT, ...))把结果文本回传并finish()即可让原输入框原地替换为处理结果。把两个示例放在一起ProcessText 展示了“如果不加防护选中文本会以EXTRA_PROCESS_TEXT被交给谁、怎么被消费”ProcessTextBlocker 则展示了“如何让这类菜单根本不出现”。两者的 Manifest 差异是否有PROCESS_TEXTintent-filter与控件层差异是否设置PasswordTransformationMethod子类正是理解整套机制的两条主线。七、总结与参考文件在 cw-omnibus 的 ProcessTextBlocker 示例中阻止ACTION_PROCESS_TEXT的核心是一条轻量技巧让编辑器EditText使用继承自PasswordTransformationMethod的“假密码”变换器原样返回明文的同时利用框架对密码输入框不提供文本处理菜单的行为从控件层面彻底切断选中文本外发的通道。它不依赖 Intent 过滤、不修改 Manifest、不影响明文编辑体验适用于文件编辑器、笔记类、凭证类等对内容外泄敏感的输入场景。示例说明文档Introspection/ProcessTextBlocker/README.markdown核心实现EditorFragment.javasetTransformationMethod与DummyTransformationMethod工程配置app/build.gradle、AndroidManifest.xml编辑场景支撑SampleAdapter.java、AbstractPermissionActivity.java协议接收端对照Introspection/ProcessText/app/src/main/java/com/commonsware/android/processtext/MainActivity.java赞分享示例工程教程【免费下载链接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_项目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus点击查看免费下载相关推荐cw-omnibus 实战基于 ACTION_PROCESS_TEXT 实现 Android 文本处理集成cw omnibus 实战基于 ACTION_PROCESS_TEXT 实现 Android 文本处理集成 本指南以 cw omnibus 仓库中的 Proc示例工程教程cw-omnibus AFClient 示例剖析在 Android 8.0 的 Activity 中接入 Autofill 支持cw omnibus AFClient 示例剖析在 Android 8.0 的 Activity 中接入 Autofill 支持 导读 本文以 cw omn示例工程教程深入 Android 7.0 的 AlarmManager.OnAlarmListener 回调式闹钟cw-omnibus Listener 示例全解深入 Android 7.0 的 AlarmManager.OnAlarmListener 回调式闹钟cw omnibus Listener 示例全解 cw示例工程教程上一篇如何3秒破解百度网盘提取码免费智能工具完整使用指南下一篇百度网盘提取码终极破解指南3秒快速获取资源密码的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考