sn-plugin-lib 提供的接口,还是直接使用 Android 官方文件/网络接口、RN 官方文件/网络接口,或插件自带的 C/C++ 代码做文件读写/网络访问,只要访问的是受限范围(见下方默认可访问范围),都会被同一套权限体系拦截,无法绕过。
本章介绍权限体系的整体设计,具体接口请参考:
- 查询权限状态:
hasPermission - 申请权限:
requestPermission
权限类型
如何声明权限
调用requestPermission 前,必须先在插件根目录的 PluginConfig.json 里,通过 uses-permissions 字段声明要使用的权限名(字符串数组)。未声明就直接调用会失败(错误码 1500)。
字段格式参见 PluginConfig.json 字段说明 中的 uses-permissions 一行。
如何申请权限
每次进入插件,或在使用需要该权限的功能之前,都建议按下面的流程走一遍(详见权限申请规范):- 调用
hasPermission(permission)查询当前状态:返回1表示已授权,可直接调用相关接口 - 若返回
0(未授权),调用requestPermission(permission, desc?)发起申请:该权限还没有被设为”不允许”时,会弹出第 3 步的授权对话框;已经被设为”不允许”时,只会弹出第 4 步的前往设置提示 - 用户在弹框中选择(默认选中”仅本次允许”):
- 仅本次允许:返回
1 - 始终允许:返回
2 - 不允许:返回
0 - 点击 Cancel(未做选择):本次没有任何授权,返回
-1,不会记成「不允许」。下次调用requestPermission会重新弹出三选一授权对话框
- 仅本次允许:返回
- 如果用户此前已经选择过”不允许”,再次调用
requestPermission会弹出提示框,引导用户前往系统设置修改;该提示框关闭后仍返回0,不会重新触发三选一的授权流程
FILE:READ)的英文界面,三个选项依次对应「仅本次允许」「始终允许」「不允许」,默认选中第一项。标题下方的说明是读取权限的系统默认文案,不是 desc;desc 不会出现在这张对话框上。写入、删除、网络权限的标题和默认说明不同:

desc 时的系统默认说明;传入 desc 时,这句说明会换成 desc:

“仅本次允许”只在本次插件会话内有效:插件退出或关闭后会失效,下次重新打开插件需要重新申请;只有”始终允许”会被持久化保存,重启插件后依然有效。建议在插件正常运行期间发起文件读写等调用。
默认可访问范围
- 插件私有目录(
/data/data/com.ratta.supernote.pluginhost/files/plugins/<pluginID>):唯一默认免申请的路径,读取、写入、删除都不需要申请权限 sdcard下Document/EXPORT/INBOX/MyStyle/Note/SCREENSHOT这 6 个目录:默认不具备任何权限,读/写/删要分别申请FILE:READ/FILE:WRITE/FILE:DELETE后才能使用- 外接 SD 卡、OTG 等外部存储设备:访问同样受
FILE:READ/FILE:WRITE/FILE:DELETE权限管控,插件侧调用的是同一套hasPermission/requestPermission接口,不需要额外区分 - 除上述范围外的其他路径:无法通过申请权限获得访问能力
权限依赖一览
下表只列出sn-plugin-lib 提供的典型接口作为例子;如果插件代码绕开 sn-plugin-lib,直接使用 Android/RN/C++ 官方接口访问上述目录之外的文件或发起网络请求,同样会被这套权限体系拦截,不是只有下表列出的接口才受影响。
deleteElements/deletePageElements 等删除元素类方法删除的是笔记内容,本质是对文件的修改,因此按 FILE:WRITE 校验;FILE:DELETE 权限用于文件级删除等其他场景。
常见错误码
权限申请规范
每次进入插件,以及每次使用需要权限的功能之前,都要按”声明 → 检查 → 申请”走一遍。前提是已按如何声明权限在PluginConfig.json 中声明了该权限。
- 每次进入插件或使用相关功能前,先调用
hasPermission。返回1表示已授予,直接调用相关接口,不需要再申请 - 返回
0再调用requestPermission,具体流程和返回值见如何申请权限