概述
开发一个可以安装屏幕/相机取词插件的词典程序,有多难?
将开源的 Tesseract-Android 插件化,开启openmp多线程模式,配合安卓的icu分词。用于相机取词还是很快的。
插件原理前文已有解释。关键词: contentProvider + createPackageContext
调用者无需集成Tesseract的Java/c++代码即可拥有高大上的OCR光学识别能力。
插件化实例:
图文之心支持三个常见架构(android { defaultConfig { ndk{ abiFilters 'x86', 'armeabi-v7a', 'arm64-v8a'),内含两个模型文件,总共也才12MB。
通过 contentProvider 共享资源的方法和限制:
- 在清单.xml中注册,就可以接管 content://authority/path 这样的uri请求,其中 authority 是注册的类似于域名的东西,一般是包名吧。path是uri.getPath()的返回值,以斜杠/开头。
- 在自定义类中,可以提供位于asset包中的资源,或插件私有目录的文件使用权,调用的时候,先经过
AssetFileDescriptor openAssetFile方法,再经过ParcelFileDescriptor openFile方法。 - 提供asset资源的时候,资源不能被压缩,否则
AssetManager.openFd打开失败。或可提供raw资源:AssetFileDescriptor fd = getResources().openRawResouceFd(R.raw.raw_asset);(麻烦,没试)
本例通过解压asset资源至插件私有目录提供Tesseract的模型文件。
- 限制:contentProvider 内容提供者需被保活,或动态启动。
本例通过检测宿主权限判断是否需要 contentProvider,当有存储权限之时,直接去读。否则, 检测contentProvider是否存在(访问测试文件),如不存在,则启动插件中的空Activity并立即返回,以拉起内容提供者。
编辑器要太闪了!
通过 createPackageContext 共享Java和c++代码的方法和限制:
- 优点:分模块后,编译速度提升(Tesseract-Android本身增量编译就很快,即使是修改cpp文件)、安装包体积减小,用户按需下载功能模块。宿主与插件可独立更新,节省了流量和更新代价。
- 缺点:项目分离,不好调试,需考虑版本兼容性。
本例先将插件应用独立写出Activity来,基本功能调试完毕后,再分离出宿主层、桥接层、插件层。其中桥接层由两个项目里的同名类组成:Tesseraction.java,宿主侧通过反射调用插件侧的代码。
Tesseraction.java (插件侧):github.com/KnIfER/Tess… (宿主侧):gitee.com/knziha/plai… 。宿主层包含功能代码、业务逻辑,包括相机、界面、取词逻辑等等,也是开源的,相机主循环源于zxing-demo扫码项目,取景框控件代码源于其他人的博客,魔改七八后复归于开源。
- 限制:需要在宿主应用的清单文件中预先申明想要调用的插件包名。但是反过来怎么办?似乎难以发展出桌面平台那样的插件体制。
- 需注意本地库版本,一般是64位(arm64-v8a),需一致才能调用。
- 卸载插件apk、划掉插件任务会导致宿主程序终结。