☰
RichEditor-Android 2.0.0 版本演进全解析:CHANGELOG 逐项拆解与源码验证
2026/10/15 1:49:38 网站建设 项目流程
  • 移动开发
  • UI组件

【免费下载链接】richeditor-android

RichEditor for Android is a beautiful Rich Text WYSIWYG Editor for Android.

项目地址:https://gitcode.com/gh_mirrors/ri/richeditor-android
点击查看免费下载

本文以richeditor-android仓库根目录下的 CHANGELOG.md 为主线,逐条拆解从 1.0.0 到 2.0.0 的版本变更记录,并结合仓库内 RichEditor.java、rich_editor.js 等核心源码,验证每一项 Feature、Update 与 Bugfix 的实际落点。读完本文,你将能够理解 2.0.0 版本为图片、视频、音频等富媒体能力带来的 API 变化,掌握 URL 编解码、只读模式、占位符等关键机制的底层实现,并能在自己的 Android 项目中正确升级与调用这些接口。

版本演进全景:从 1.0.0 到 2.0.0

CHANGELOG.md完整记录了该开源项目的六个正式版本,时间跨度从 2015 年 11 月的产品发布到 2020 年 9 月的 2.0.0 大版本。整理如下:

版本发布日期核心内容
2.0.02020-09-16图片尺寸参数、Youtube/Video/Audio 标签、SDK 25→30、Normalize.css 8.0.1、5 项 Bugfix
1.2.22017-03-21新增只读模式、SDK 23→25、Support Library 升级、removeFormat 文档修复
1.2.12016-08-04修复类型缺失、更新样例工程
1.2.02016-01-07新增字号(fontSize)功能
1.1.02016-01-07合并 PR #37(CHANGELOG 未详述具体内容)
1.0.02015-11-10正式产品发布

可以看到,2.0.0 是该项目功能与工程化改动最为集中的一次发布:它同时带来了富媒体能力扩充、SDK 目标升级和一批与 WebView 通信机制相关的关键修复。下面以 2.0.0 为重点,逐项深入。

2.0.0 Feature 一:图片插入支持尺寸参数

CHANGELOG.md记录的第一项新特性是 "Supported Image can set size params",对应 PR #176。它解决的核心问题是:在 2.0.0 之前,插入图片只能使用图片原始尺寸,在手机屏幕上经常出现图片过大或过小的问题。

Java 侧 API 的变化

在 RichEditor.java 中,2.0.0 为图片插入提供了三个重载方法:

// 原始尺寸插入 public void insertImage(String url, String alt) { exec("javascript:RE.prepareInsert();"); exec("javascript:RE.insertImage('" + url + "', '" + alt + "');"); } // 仅指定宽度(高度按比例自适应) public void insertImage(String url, String alt, int width) { exec("javascript:RE.prepareInsert();"); exec("javascript:RE.insertImageW('" + url + "', '" + alt + "','" + width + "');"); } // 同时指定宽度与高度 public void insertImage(String url, String alt, int width, int height) { exec("javascript:RE.prepareInsert();"); exec("javascript:RE.insertImageWH('" + url + "', '" + alt + "','" + width + "', '" + height + "');"); }

源码注释明确说明了这一设计意图:insertImage(String, String)会按图片原始尺寸展示,而带宽高参数的重载方法可以让开发者手动控制尺寸,使图片适配不同的手机屏幕。width与height均以像素(px)为单位。

JS 侧的对应实现

这三个 Java 方法分别调用 rich_editor.js 中的insertImage、insertImageW、insertImageWH:

RE.insertImage = function(url, alt) { var html = '<img src="' + url + '" alt="' + alt + '" />'; RE.insertHTML(html); } RE.insertImageW = function(url, alt, width) { var html = '<img src="' + url + '" alt="' + alt + '" width="' + width + '"/>'; RE.insertHTML(html); } RE.insertImageWH = function(url, alt, width, height) { var html = '<img src="' + url + '" alt="' + alt + '" width="' + width + '" height="' + height +'"/>'; RE.insertHTML(html); }

三者的差异直观可见:不传尺寸时不写width/height属性;传宽度时写入width属性;传宽高时同时写入两者。最终通过document.execCommand('insertHTML', ...)插入编辑器选区。

实践建议

在真实项目中,推荐至少传入width,避免大图撑破编辑区:

mEditor.insertImage("https://example.com/path/to/image.jpg", "图片描述", 320);

alt属性会被写入<img>标签,建议填写有意义的描述文本,便于无障碍访问与 SEO 语义化。

2.0.0 Feature 二:Youtube / Video / Audio 富媒体标签

CHANGELOG.md记录的第二项新特性是 "Supported Youtube, Video, Audio tag",对应 PR #189。这是 2.0.0 最显著的功能扩充,让编辑器从纯图文升级为可插入音视频的富媒体编辑器。

视频(Video)

Java API 同样提供三个重载:

mEditor.insertVideo("https://example.com/video.mp4"); mEditor.insertVideo("https://example.com/video.mp4", 360); mEditor.insertVideo("https://example.com/video.mp4", 360, 240);

对应 rich_editor.js 生成原生 HTML5<video>标签,并默认带上controls属性以便用户控制播放:

RE.insertVideo = function(url, alt) { var html = '<video src="' + url + '" controls></video><br>'; RE.insertHTML(html); } RE.insertVideoW = function(url, width) { var html = '<video src="' + url + '" width="' + width + '" controls></video><br>'; RE.insertHTML(html); } RE.insertVideoWH = function(url, width, height) { var html = '<video src="' + url + '" width="' + width + '" height="' + height + '" controls></video><br>'; RE.insertHTML(html); }

音频(Audio)

Java API 目前只提供单一入参版本:

mEditor.insertAudio("https://example.com/audio.mp3");

对应 rich_editor.js 生成带controls的<audio>标签,同样在末尾追加<br>换行:

RE.insertAudio = function(url, alt) { var html = '<audio src="' + url + '" controls></audio><br>'; RE.insertHTML(html); }

Youtube 嵌入

Java API 提供三个重载,内部生成<iframe>嵌入播放器:

mEditor.insertYoutubeVideo("https://www.youtube.com/embed/pS5peqApgUA"); mEditor.insertYoutubeVideo("https://www.youtube.com/embed/pS5peqApgUA", 640); mEditor.insertYoutubeVideo("https://www.youtube.com/embed/pS5peqApgUA", 640, 360);

注意这里传入的 URL 应当是 YouTube 的embed形式的嵌入链接,而不是普通分享页。对应 rich_editor.js 生成的 iframe 携带了较为完整的播放器参数:

RE.insertYoutubeVideo = function(url) { var html = '<iframe width="100%" height="100%" src="' + url + '" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><br>' RE.insertHTML(html); }

allow属性覆盖了自动播放、剪贴板写入、加密媒体、陀螺仪、画中画等常见能力,allowfullscreen保证可全屏播放。默认(无参)时宽高为 100%,可通过带宽高参数的重载固定播放器尺寸。

样例工程中的调用示范

MainActivity.java 中可以看到这些新 API 的完整接线方式,例如:

mEditor.insertImage("https://raw.githubusercontent.com/wasabeef/art/master/chip.jpg", "dachshund", 320); mEditor.insertYoutubeVideo("https://www.youtube.com/embed/pS5peqApgUA"); mEditor.insertAudio("https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_5MG.mp3"); mEditor.insertVideo("https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_10MB.mp4", 360);

工具栏按钮与这些方法一一对应,完整布局可参考 activity_main.xml。

2.0.0 Update:compile / target SDK 25 → 30 与 Normalize.css 8.0.1

CHANGELOG.md记录了 2.0.0 的两项工程化升级:

SDK 版本升级

"Compile / Target SDK Version 25 -> 30"。在 gradle.properties 中可以看到当前版本的实际取值:

VERSION_NAME=2.0.0 VERSION_CODE=200 COMPILE_SDK_VERSION=30 TARGET_SDK_VERSION=30 MIN_SDK_VERSION=14

即 2.0.0 的编译与目标 SDK 均为 30(Android 11),而最低支持版本仍是 API 14(Android 4.0),与 README 中 "Android 4+" 的要求一致。这一升级使得WebView的evaluateJavascript路径(API 19+)成为默认执行方式,详见 RichEditor.java:

private void load(String trigger) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { evaluateJavascript(trigger, null); } else { loadUrl(trigger); } }

SDK 30 下绝大多数设备走evaluateJavascript,loadUrl("javascript:...")仅作为 API 19 以下设备的降级方案保留。

Normalize.css 升级

"Normalize.css to 8.0.1"。仓库内的 normalize.css 文件头注释明确标注为 "normalize.css v8.0.1",与 CHANGELOG 记录一致。Normalize.css 的作用是抹平不同浏览器/WebView 内核间的默认样式差异,保证contenteditable编辑区域在各 Android WebView 上呈现一致的排版。该文件与 style.css、editor.html 一起打包进 APK 的 assets 目录,由RichEditor构造时通过file:///android_asset/editor.html加载(见 RichEditor.java)。

2.0.0 Bugfix 源码级解读

CHANGELOG.md的 Bugfix 列表共五项,全部与编辑器的 JavaScript 桥接机制相关,值得逐一深入。

修复一:placeholder(PR #240)

占位符功能通过setPlaceholder(String)设置,Java 侧调用 rich_editor.js 的setPlaceholder,把占位文本写到编辑区 DOM 的placeholder属性上:

RE.setPlaceholder = function(placeholder) { RE.editor.setAttribute("placeholder", placeholder); }

而占位符的显示逻辑在 style.css 中:

#editor[placeholder]:empty:not(:focus):before { content: attr(placeholder); opacity: .5; }

该 CSS 选择器的三个条件是:编辑区带有placeholder属性、内容为空(:empty)、且未处于聚焦状态(:not(:focus))。PR #240 修复的正是这条显示链路上的问题——例如空内容但存在空白字符、聚焦状态判断等导致占位符不显示或显示时机错误的场景。修复后占位符以半透明(opacity: .5)方式显示,一旦用户开始输入或获得焦点便自动隐藏。

修复二:typo(PR #194)

CHANGELOG 记录 "Fixed typp",即修复了一处拼写错误。这类修复通常涉及方法名、变量名或注释中的拼写问题,虽然不改变功能行为,但会直接影响调用方能否正确编译。从当前源码看,编辑器所有对外方法命名规范一致(如setStrikeThrough、setUnderline等),说明命名已在修复后趋于稳定。

修复三与五:URL 解码与 encodeURIComponent(PR #123、PR #145)

这两项修复共同保证了编辑器内容从 JS 到 Java 的传输不被破坏,是整个桥接机制中最核心的部分。

JS 侧的回调在 rich_editor.js:

RE.callback = function() { window.location.href = "re-callback://" + encodeURIComponent(RE.getHtml()); }

编辑器内容(HTML 字符串)先经encodeURIComponent()编码,再拼接到re-callback://自定义 scheme 上,通过window.location.href触发 WebView 的 URL 拦截。Java 侧在 RichEditor.java 的shouldOverrideUrlLoading中接收并解码:

String decode = Uri.decode(url); if (TextUtils.indexOf(url, CALLBACK_SCHEME) == 0) { callback(decode); return true; } else if (TextUtils.indexOf(url, STATE_SCHEME) == 0) { stateCheck(decode); return true; }

RE.getHtml()返回的是innerHTML,其中可能包含引号、空格、中文、HTML 实体乃至多语言字符,如果不编码直接拼进 URL,会破坏 URL 结构或导致解码错乱。encodeURIComponent()(PR #145)保证编码完整性,Uri.decode()(PR #123)则负责在 Java 侧还原原始 HTML。

仓库内 UrlDecoderTest.java 用 Robolectric 对这一链路做了针对性测试:测试字符串同时包含空格、<div>/<font>标签、引号、HTML 实体&nbsp;、连续加号、中文"下"、日文"ぁ"以及阿拉伯文"ص",编码后经Uri.decode能完整还原,验证了多语言与特殊字符场景下的解码正确性。

修复四:shouldOverrideUrlLoading(PR #133)

shouldOverrideUrlLoading在 Android 版本间存在签名差异,RichEditor.java 中实现了两个重载:

// API 21 之前的旧签名 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { ... } // API 21+ 的新签名(带 WebResourceRequest) @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { final String url = request.getUrl().toString(); ... }

PR #133 修复的正是这个兼容性问题:在 Android 5.0(API 21)引入新签名后,旧签名在新设备上不再被调用,导致re-callback://与re-state://拦截失效、文本变更回调丢失。两个重载采用相同的拦截逻辑,内部都先做Uri.decode,再判断 scheme 前缀,命中后消费该 URL 并返回true,避免 WebView 真正去加载自定义 scheme。

历史版本亮点回顾

2.0.0 之外的早期版本同样留下了延续至今的核心能力,结合源码可以一一印证。

1.2.2:只读模式(PR #101)

"Add ability to disable input on editor making it readonly" 是 1.2.2 引入的能力,对应今天的setInputEnabled(Boolean):

public void setInputEnabled(Boolean inputEnabled) { exec("javascript:RE.setInputEnabled(" + inputEnabled + ")"); }

JS 侧实现 rich_editor.js 直接控制contentEditable属性:

RE.setInputEnabled = function(inputEnabled) { RE.editor.contentEditable = String(inputEnabled); }

传入false时编辑器变为只读,内容不可编辑但仍可展示、滚动与复制;传入true恢复可编辑。这在"预览模式""表单确认页"等场景非常实用。

同期 1.2.2 还记录了 compile/target SDK 23→25、Build Tools 24.0.2→25.0.2、Support Library 23.4.0→25.3.0 的工程升级,以及两项 Bugfix:修复removeFormat缺失的文档(该 API 存在于 RichEditor.java 与 JS 的RE.removeFormat中),以及外部 RSBlur 项目的资源清理。

1.2.0:字号功能(PR #42)

字号功能对应 Java APIsetFontSize(int),RichEditor.java 对参数范围有明确约束:

public void setFontSize(int fontSize) { if (fontSize > 7 || fontSize < 1) { Log.e("RichEditor", "Font size should have a value between 1-7"); } exec("javascript:RE.setFontSize('" + fontSize + "');"); }

取值限制在 1~7 之间,超出范围会输出Log.e错误日志(注意:仍会照常执行命令)。JS 侧通过document.execCommand('fontSize', false, fontSize)应用字号。

1.2.1 / 1.1.0 / 1.0.0

  • 1.2.1(2016-08-04):修复部分类型缺失(对应 PR #63),并更新了样例工程。从源码结构看,格式化类型统一收拢在 RichEditor.java 的Type枚举中(BOLD、ITALIC、H1~H6、ORDEREDLIST、UNORDEREDLIST、JUSTIFYCENTER/JUSTIFYFULL/JUSTIFYLEFT/JUSTIFYRIGHT 等)。
  • 1.1.0(2016-01-07):合并 PR #37,具体变更内容未在 CHANGELOG 中详述。
  • 1.0.0(2015-11-10):产品正式发布,宣告该项目进入可用状态。

从 CHANGELOG 到源码:三个值得留意的实现细节

在对照 CHANGELOG 与源码的过程中,有三个细节能帮助你更准确地使用 2.0.0:

第一,命令执行有"就绪队列"机制。RichEditor.java 中的exec()会先检查isReady(由onPageFinished在editor.html加载完成后置为 true)。如果 WebView 尚未就绪,命令会以 100ms 间隔延迟重试,直到页面加载完成。因此onCreate中立即调用setBold()等命令也是安全的,不必担心 JS 尚未初始化。

第二,内容回传走自定义 scheme。除了re-callback://(内容变更回调),还有re-state://(光标处格式状态回调)。RichEditor.java 的stateCheck会把 JS 上报的格式状态与Type枚举做匹配,供OnDecorationStateListener使用——这正是工具栏按钮高亮"当前光标处是加粗还是斜体"这一交互的底层来源。

第三,setHtml 需要保持编码一致。RichEditor.java 的setHtml使用URLEncoder.encode(contents, "UTF-8")编码后再传给 JS,JS 端则用decodeURIComponent(contents.replace(/\+/g, '%20'))还原(rich_editor.js)。其中+会被替换回空格,与回调方向的encodeURIComponent+Uri.decode形成完整的双向编解码闭环。

如何在项目中落地 2.0.0

依赖引入

2.0.0 已发布到 Maven Central,按 README.md 说明配置:

repositories { mavenCentral() } dependencies { implementation 'jp.wasabeef:richeditor-android:2.0.0' }

若需自行编译验证,可在仓库根目录执行./gradlew :sample:assembleDebug(当前仓库 build.gradle 使用 AGP 4.2.0-beta04,样例工程通过 sample/build.gradle 的implementation project(':richeditor')依赖本地模块)。

新增 API 使用清单

升级到 2.0.0 后,与旧版最大的差异集中在富媒体插入:

能力2.0.0 API生成的 HTML 标签
图片(原尺寸)insertImage(url, alt)<img>
图片(指定宽度)insertImage(url, alt, width)<img width="...">
图片(指定宽高)insertImage(url, alt, width, height)<img width height>
视频insertVideo(url[, width[, height]])<video controls>
音频insertAudio(url)<audio controls>
YoutubeinsertYoutubeVideo(url[, width[, height]])<iframe>

测试验证

仓库在 richeditor/src/test 下提供了基于 Robolectric 的单元测试,其中 UrlDecoderTest.java 覆盖了多语言、特殊字符的 URL 解码链路,是验证"内容回传不丢字"这一 2.0.0 修复成果的直接手段,可在本机运行验证。

总结

CHANGELOG.md虽然只有短短几十行,却完整勾勒了 richeditor-android 从 1.0.0 到 2.0.0 的能力演进主线:2015 年完成产品化,2016 年补齐字号与类型修复,2017 年引入只读模式,最终在 2020 年的 2.0.0 上集中兑现了图片尺寸可控与 Youtube/Video/Audio 三类富媒体标签,同时将工程基线推进到 SDK 30,并借助encodeURIComponent+Uri.decode的编解码闭环与双版本shouldOverrideUrlLoading兼容修复,从根本上加固了 WebView 与 Java 层之间的通信可靠性。对照 RichEditor.java 与 rich_editor.js 阅读 CHANGELOG,每一项记录都能找到确切的代码落点,这既是一份版本历史,更是一份浓缩的架构设计说明书。

  • 移动开发
  • UI组件

【免费下载链接】richeditor-android

RichEditor for Android is a beautiful Rich Text WYSIWYG Editor for Android.

项目地址:https://gitcode.com/gh_mirrors/ri/richeditor-android
点击查看免费下载
上一篇:探索 `kinit`:一个简洁高效的 Kubernetes 凭证管理工具
下一篇:daisyUI表单组件宝典:从基础到高级应用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询