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

Every time the plugin opens, and before using any feature that needs the permission, we recommend following the flow below (see Permission Request Guidelines for details):
  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 request it: if the permission has not been set to “don’t allow”, the dialog in step 3 appears; if it has already been set to “don’t allow”, only the prompt in step 4 that guides the user to the system settings appears
  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
    • Tapping Cancel without confirming a choice: nothing is granted this time, and the call returns -1. This is not recorded as “Don’t allow”. Calling requestPermission again shows the three-option dialog
  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
Step 3 shows the three-option dialog. The screenshot is the English UI for read permission (FILE:READ), and it defaults to “Allow this time only”. The line under the title is the system default description for read permission, not desc. desc is not shown on this dialog. Write, delete, and internet permissions use different titles and default descriptions: Three-option authorization dialog Step 4, when the permission is already set to “Don’t allow”, shows only the prompt that guides the user to Settings. This screenshot is also the read-permission prompt. The body is the system default used when desc is omitted; passing desc replaces that body: Prompt that guides the user to Settings
“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

Permission Request Guidelines

Every time the plugin opens, and before every feature that needs a permission, follow “declare → check → request”. Make sure the permission has been declared in PluginConfig.json as described in How to Declare Permissions.
  • Before each entry into the plugin or use of a related feature, call hasPermission first. 1 means the permission is already granted, so call the related APIs directly without requesting again
  • If it returns 0, call requestPermission. For the full flow and return values, see How to Request Permissions
The example below shows the minimal flow: check → request if not granted → retry the business call once granted.
  • Allow this time only: for when it expires, see the note in How to Request Permissions above. If requestPermission is not called again the next time the plugin opens, or the next time the feature is used, no authorization dialog appears: read and write calls fail (error codes 1503, 1501; see Common Error Codes), and network requests fail as well
  • Always allow: this state can only be changed under plugin management in the system settings. Once granted, hasPermission returns 1 and you do not need to call requestPermission again, so checking every time does not trigger the dialog repeatedly (the same applies once “Allow this time only” has been chosen within the current session)
  • Don’t allow: only the prompt that guides the user to the system settings appears, and the three-option dialog is not shown again. See step 4 in How to Request Permissions
If the user chose “Allow this time only” and the plugin requests the permission only once on first run, the authorization dialog does not appear the next time the plugin opens or the feature is used, and the plugin cannot work because it lacks the permission.