Skip to main content
To protect the files and privacy on a user’s device, a plugin must obtain user authorization before it can access the file system or make network requests. This permission check applies at the boundary of “the plugin process accessing the file system/network”: whether the plugin code calls APIs exposed by sn-plugin-lib, or directly uses Android’s official file/network APIs, RN’s official file/network APIs, or the plugin’s own C/C++ code to read/write files or access the network, it will be intercepted by the same permission system as long as it targets the restricted scope (see Default Accessible Scope below). This cannot be bypassed. This chapter covers the overall design of the permission system. See the following API pages for interface details:

Permission Types

How to Declare Permissions

Before calling requestPermission, you must first declare the permission names you intend to use in the uses-permissions field of PluginConfig.json at the plugin’s root (a string array). Calling requestPermission without declaring the permission first will fail (error code 1500). See the uses-permissions row in PluginConfig.json field reference.

How to Request Permissions

Recommended flow:
  1. Call hasPermission(permission) to check the current status: 1 means already granted, so you can call the related APIs directly
  2. If it returns 0 (not granted), call requestPermission(permission, desc?) to trigger the authorization dialog
  3. The user chooses among (the dialog defaults to “Allow this time only”):
    • Allow this time only: returns 1
    • Always allow: returns 2
    • Don’t allow: returns 0
    • Closing the dialog without choosing: treated as “don’t allow”, returns -1
  4. If the user has previously chosen “Don’t allow”, calling requestPermission again shows a dialog that guides the user to the system settings; after that dialog is dismissed, the result is still 0 and the three-option dialog is not shown again
“Allow this time only” is valid only for the current plugin session: it is revoked when the plugin exits or is closed, and must be requested again the next time the plugin opens. Only “Always allow” is persisted and remains valid after restarting the plugin. It’s recommended to make file read/write calls while the plugin is actively running.

Default Accessible Scope

  • The plugin’s private directory (/data/data/com.ratta.supernote.pluginhost/files/plugins/<pluginID>): the only path that is exempt from any permission by default — reading, writing, and deleting are all allowed without requesting anything
  • The Document, EXPORT, INBOX, MyStyle, Note, and SCREENSHOT directories under shared storage (sdcard): none of these permissions are granted by default; reading/writing/deleting each requires explicitly requesting FILE:READ/FILE:WRITE/FILE:DELETE
  • External SD cards, OTG storage, and other removable storage: access is likewise governed by FILE:READ/FILE:WRITE/FILE:DELETE; the plugin calls the same hasPermission/requestPermission APIs and does not need to handle this differently
  • Any other path outside the scope above: cannot be accessed by requesting a permission

Permission Dependencies

The table below lists typical sn-plugin-lib APIs only as examples. If plugin code bypasses sn-plugin-lib and directly uses Android/RN/C++ official APIs to access files outside the directories above or to make network requests, it will still be intercepted by the same permission system — the APIs below are not the only ones affected. deleteElements/deletePageElements and similar “delete element” methods remove note content, which is essentially a file modification, so they are validated against FILE:WRITE. The FILE:DELETE permission is used for file-level deletion and other scenarios.

Common Error Codes

Example

The example below shows the minimal flow: check → request if not granted → retry the business call once granted.