Manifest, Configuration & Core APIs
Note
AI-Ready Quick Fact (Manifest Schema & Core APIs)
- Unique ID:
identifier(e.g.com.author.plugin) must be unique to prevent system overwrites. - Action Isolation: Standard Actions (background
script.jssandbox) vs Web App Actions (physically isolatedui/index.htmlfrontend sandbox). - Native Bridges:
SwiftBiu.beginFileTask(options)for Progress Panel,SwiftBiu.showAIResponseBubble(...)for Streaming AI panel,window.swiftBiufor Web UI async data bindings.
Two Types of Plugin Actions
To meet different complexity requirements, SwiftBiu supports two distinct plugin architectures. To intuitively understand their differences, let's compare two implementations of a "Currency Converter" feature:
1. Standard Action (Logic-Only)
Example: CurrencyConverterLite (Minimalist Converter)
Suitable for scenarios that only need background logic execution (API calls, text extraction, data calculation) and absolutely no custom user interface. All interactions are completed using native system components (like system notifications, native input fields, or pasting directly to the clipboard).
manifest.json Configuration
Define the action in the actions array. No ui node is needed:
"actions": [
{
"title": "Lite: Convert Currency",
"script": "script.js"
}
]
script.js Core Logic
Running in a global background sandbox, you must implement two hook functions:
isAvailable(context): The action trigger. You can analyzecontext.selectedText(e.g., using regex to check if "100 USD" is selected) to determine whether the action should be highlighted at the very front of the toolbar (isContextMatch: true).performAction(context): The core functionality. After making a network request for the latest rates and calculating "720 CNY", since there is no custom UI, you must use native APIs to feed the result back to the user:function performAction(context) { // ... (API calculation logic) ... const result = "720 CNY"; // Use native Clipboard API to return the result SwiftBiu.copyText(result); // Use native Notification API to alert the user SwiftBiu.showNotification("Success", `Copied: ${result}`); }
2. Web App Action (Custom UI)
Example: CurrencyConverter (Advanced Converter Panel)
This is the most powerful and flexible mode. Suitable for scenarios requiring complex interactions, form inputs, animations, or full visual presentations. This mode turns your plugin into a complete mini Web App packaged with HTML/CSS/JS.
manifest.json Configuration
In addition to the script configuration used in Standard Actions, you must declare the entry point for your Web UI via a root-level ui attribute:
"actions": [
{
"title": "Pro: Currency Panel",
"script": "script.js" // Receives the click event and launches the UI
}
],
"ui": {
"main": "ui/index.html" // The Web App's entry page
}
Launch Flow & Architecture Isolation (Core Difference)
In Web App mode, the background script (script.js) no longer handles business calculations; it acts solely as a "Launcher". The flow is divided into two clear steps, and the frontend and backend run in two physically isolated sandboxes:
Step 1: Background Trigger
You must explicitly call SwiftBiu.displayUI() within performAction in script.js:
function performAction(context) {
const screenSize = SwiftBiu.screenSize;
// Launch the custom web window hosting index.html
SwiftBiu.displayUI({
htmlPath: "ui/index.html",
width: 320,
height: 480,
// ... other configs
});
}
Step 2: Frontend Takeover & Context Injection
Once displayUI() is called, the user-facing interface is completely taken over by the frontend code in index.html. Furthermore, you do not need to manually pass data between these two isolated sandboxes.
SwiftBiu automatically injects the identical context (like the selected text) directly into the page's global window object. You simply need to define a swiftBiu_initialize hook in your ui/index.html to receive it:
// In ui/index.html
window.swiftBiu_initialize = async function (context) {
// The UI receives the context directly!
const text = context.selectedText || "";
const selectedFiles = context.selectedFiles || [];
console.log("User selected:", text);
// You can now proceed to use window.swiftBiu.fetch for API calls
// and update the DOM with the results...
};
Manifest & Configuration
manifest.json Explained
This file is the "ID card" for your plugin. Here are the most important keys:
| Key | Type | Required | Description |
|---|---|---|---|
identifier |
String | Yes | A unique ID for your plugin, e.g., com.yourname.plugin. Must be globally unique, as a plugin with a duplicate identifier will overwrite any existing one. |
name |
String | Yes | The display name of your plugin. |
author |
String | Yes | Author of the plugin. |
description |
String | Yes | Short introduction to the plugin. |
version |
String | Yes | The plugin's version, e.g., 1.0. |
actions |
Array | Yes | An array defining the actions the plugin provides. |
icon |
String | No | (Root Level) The default icon for the entire plugin. Supports SF Symbols, packaged image files, text icons, Iconify icons, or a data: URI payload. |
iconType |
String | No | (Root Level) Defines how icon should be interpreted. Supported values: "sfSymbol", "file", "text", "iconify", and "data". |
configuration |
Array | No | Defines a user-configurable settings UI for your plugin. |
permissions |
Array | No | Declares system permissions required by the plugin. |
Plugin Icon Formats
SwiftBiu now supports multiple icon source types for the root-level plugin icon.
1. SF Symbol
Use any valid SF Symbol name:
{
"icon": "sparkles",
"iconType": "sfSymbol"
}
If iconType is omitted and the value does not look like an image file, SwiftBiu treats it as an SF Symbol by default.
2. Packaged Image File
Use an image file bundled inside your plugin package. Common formats such as .png, .jpg, .jpeg, .webp, .gif, .bmp, .tif, .tiff, .heic, .icns, .pdf, and .svg are supported.
{
"icon": "icon.png",
"iconType": "file"
}
If iconType is omitted and the file name ends in a supported image extension, SwiftBiu will also infer it as a file icon automatically.
3. Text Icon
Use short text such as initials or a compact label:
{
"icon": "AI",
"iconType": "text"
}
You can also use the explicit prefix form:
{
"icon": "text:AI"
}
Notes:
- Up to 2 visible characters are rendered.
- Alphanumeric text is automatically uppercased.
- Text icons are best for compact labels like
AI,EN, or123.
4. Iconify Icon
Use any Iconify icon name, for example solar:flag-bold or mdi:robot-happy:
{
"icon": "solar:flag-bold",
"iconType": "iconify"
}
You can also use the explicit prefix form:
{
"icon": "iconify:solar:flag-bold"
}
If you omit the iconify: prefix, make sure iconType is set to "iconify".
5. Data URI Icon
Use an inline data: URL when you want to embed the icon content directly in manifest.json:
{
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"iconType": "data"
}
This is useful when your icon is generated dynamically or you want to avoid shipping a separate file.
Parsing Rules and Recommendations
- Explicit prefixes take priority over
iconType. For example,text:AI,iconify:solar:flag-bold, anddata:image/png;base64,...are recognized even ificonTypeis omitted or mismatched. - For
Iconify, prefer storing the clean icon name plusiconType: "iconify"in released plugins. The prefixed form is also valid and convenient for quick testing. - For
fileicons, keep the asset inside the plugin package and reference it by file name. - For
texticons, keep the text short so it stays visually balanced in toolbars and lists.
Icon Design Best Practices
To ensure your plugin feels native and premium within the macOS environment:
- Prioritize Vectors: Use SF Symbols or Iconify icons whenever possible. They scale perfectly and automatically adapt to system theme changes (Light/Dark mode) and user accent colors.
- Transparency is Key: For custom image files, always use PNG or WebP with alpha transparency. Avoid solid backgrounds, as they won't blend seamlessly with the toolbar's vibrant materials.
- Optical Padding: Leave approximately 10-15% empty padding around the main shape of your icon. This "breathing room" ensures the icon doesn't look cramped in the toolbar or menu bar rows.
- Design for Small Sizes: Toolbar icons are typically rendered between 18px and 24px. Avoid complex details, fine textures, or small text that might become illegible or blurry.
- High Contrast: Ensure your icon remains recognizable against both light and dark translucent backgrounds.
Plugin Configuration (configuration)
If your plugin needs user-provided settings (like an API key), define them in the configuration array. SwiftBiu will automatically generate a settings UI.
Example of a text input field:
"configuration": [
{
"key": "api_key",
"label": "API Key",
"description": "Your secret API key.",
"type": "secure",
"placeholder": "Enter your key here"
}
]
Supported type values include: string, secure (for passwords), boolean (for switches), option (for dropdowns), and fileExtensionAppRules (for suffix-to-app rule editors).
Legacy radioList configurations are no longer supported. Migrate those cases to a normal string field or duplicate the extension for each fixed prompt variant.
Common optional fields:
group(String): Groups related settings into the same section in the native settings UI.placeholder(String): Placeholder text forstring/securestyle inputs.description(String): Long-form explanatory copy shown under the label.
Configuration UI Layout
Settings are rendered in a vertical stack. This design ensures that long labels and detailed descriptions are fully visible.
- Label: Displayed at the top in a medium font.
- Description: Displayed immediately below the label in a smaller, secondary font. This is the recommended place for detailed instructions or model-specific notes.
- Control: The interactive element (text field, switch, etc.) is placed at the bottom.
⚠️ Important: All configuration values are returned as strings.
When you read a configuration value via
SwiftBiu.getConfig(key)(background) orswiftBiu.storage.get(key)(UI), the result is always a string, regardless of the configuration type. This is by design — all settings are stored uniformly as strings inUserDefaults(or Keychain forsecuretype). You must convert them in your JavaScript code:
Type Returns How to Use string/secureThe stored string Use directly boolean"true"or"false"SwiftBiu.getConfig("key") === "true"optionThe valueof the selected optionUse directly fileExtensionAppRulesJSON string like {"rules":[{"fileExtension":"pdf","appBundleID":"com.apple.Preview"}]}Parse with JSON.parse(...)and passappBundleIDtoSwiftBiu.openFileWithApp(...)
option
- UI: A dropdown selection menu.
- Functionality: Allows the user to select a value from a predefined set of options.
- Additional Keys:
options(Array, Yes): Defines the options in the dropdown. Each object in the array requires the following keys:label(String, Yes): The text displayed for the option in the UI.value(String, Yes): The actual value of the option, which is stored and retrieved in scripts viastorage.get().
defaultValue(String, No): Thevalueof the option that is selected by default.
Example of a dropdown menu (option):
"configuration": [
{
"key": "targetLanguage",
"label": "Target Language",
"type": "option",
"defaultValue": "Python (Requests)",
"options": [
{ "label": "Python (Requests)", "value": "Python (Requests)" },
{ "label": "JavaScript (Fetch)", "value": "JavaScript (Fetch)" }
]
}
]
fileExtensionAppRules
- UI: A native suffix-rule editor. Users add one or more file suffixes on the left and choose one macOS app per suffix on the right.
- Functionality: Best for file actions that need to open selected files with specific apps without asking users to type bundle identifiers.
- Stored value: A JSON string with a
rulesarray. Each rule usesfileExtensionandappBundleID. - Default value: Optional stringified JSON in the same format.
Example of suffix-to-app rules:
"configuration": [
{
"key": "rules",
"label": "File Suffix Rules",
"type": "fileExtensionAppRules",
"description": "Add suffixes and choose the app used to open each one.",
"defaultValue": "{\"rules\":[{\"fileExtension\":\"pdf\",\"appBundleID\":\"com.apple.Preview\"}]}"
}
]
Configuration Keys: Generic vs Recognized Conventions
Most configuration key values are entirely plugin-defined. SwiftBiu stores them and returns them through getConfig(...), but their meaning is decided by your own script.
Examples of plugin-level conventions used by the current AI text templates:
pasteBehavior: Read by the template script to decide the default apply mode (appendvsreplace).enableAIResponseUI: Read by the template script to decide whether to open the native AI response bubble or directly paste the final text.- By itself, this key does nothing at the native layer.
- It becomes effective only when your
script.jsexplicitly checksSwiftBiu.getConfig("enableAIResponseUI")and branches intoshowAIResponseBubble(...)instead of the legacy direct-paste flow. - In other words, this is a documented template convention, not a universal built-in manifest switch.
Examples of currently recognized AI bubble convention keys:
responseSystemPrompt: WhenshowAIResponseBubble(...)is called without an explicitsystemPrompt, the native layer will first look for this config value as the default system prompt.
Current fallback order for the bubble's default system prompt:
responseSystemPrompt- The manifest default for
responseSystemPrompt
Recommendation:
- If a key is only used by your own script, you may rename it freely as long as the script stays in sync.
- If you rename
responseSystemPrompt, you must also update the script and any native fallback assumptions you rely on. - If you need multiple fixed prompt personas, prefer duplicating the extension and customizing each copy instead of adding an in-extension preset switcher.
- Treat these AI-related names as documented conventions for the current native AI response workflow, not as universal reserved keywords for every plugin.
Core API Reference
The APIs available to your plugin depend entirely on which plugin architecture (Action Type) you chose in your manifest.json.
1. Standard Action API (Logic-Only)
In a Standard Action, all code executes globally in the background script.js. You have direct access to the system-injected SwiftBiu (or its lowercase alias swiftBiu) object. The methods here are predominantly synchronous property reads or Callback-based asynchronous functions.
Available API List:
- Environment Context (Synchronous):
SwiftBiu.isSandboxed: (Boolean) Whether the app is currently running inside the macOS App Sandbox (restricted App Store version).SwiftBiu.getConfig(key: String): (String) Synchronously reads user preference values defined inmanifest.json.
- Native Capabilities (Synchronous):
SwiftBiu.writeToClipboard(text: String): Writes text to the system clipboard. (Requires:clipboardWrite)SwiftBiu.pasteText(text: String): Writes text to the clipboard and immediately pastes it into the active window. (Requires:paste)SwiftBiu.getClipboard(): Retrieves plain text from the system clipboard. (Requires:clipboardRead)SwiftBiu.getFileMetadata(path: String): Returns metadata for the selected local file, including size, timestamps, and content type. (Requires:localFileRead)SwiftBiu.extractFileIcon(path: String, options?: Object): Extracts the selected file or application icon through SwiftBiu's native host process and returns{ success, base64, fileName, width, height, format }for PNG output, or{ success: false, error }. Use this for App Store-compatible icon extraction instead of shell, AppleScript,sips,qlmanage, orosascript. (Requires:localFileRead)SwiftBiu.setFileIcon(targetPath: String, iconPath: String, options?: Object): Applies an accessible image as the custom Finder icon for an accessible file, folder, or.appbundle through SwiftBiu's native host process. Use this instead of shell tools when targeting the App Store sandbox. (Requires:localFileReadandlocalFileWrite)SwiftBiu.readLocalFile(path: String): Reads any currently selected local file and returns its contents as a Base64 string. (Requires:localFileRead)SwiftBiu.readLocalTextFile(path: String): Convenience API for decoding the current selected file as UTF-8 text. (Requires:localFileRead)SwiftBiu.listDirectory(path: String): Lists items in an accessible directory and returns metadata objects for each child. (Requires:localFileRead)SwiftBiu.fileExists(path: String): Returns whether an accessible path exists and is a file. (Requires:localFileReadorlocalFileWrite)SwiftBiu.directoryExists(path: String): Returns whether an accessible path exists and is a directory. (Requires:localFileReadorlocalFileWrite)SwiftBiu.pickLocalFile(options?: Object): Opens a native file picker, persists authorization for the selected item, and returns its path. Supportskind: "application"orkind: "image"andallowedExtensions. (Requires:localFileReadorlocalFileWrite)SwiftBiu.pickLocalDirectory(): Opens the macOS folder picker, stores the user's authorization, and returns the chosen folder path. (Requires:localFileWrite)SwiftBiu.createLocalDirectory(path: String): Creates a directory inside a selected or authorized location and returns the created path. (Requires:localFileWrite)SwiftBiu.createLocalFile(path: String, base64String: String): Creates a new file from Base64 data inside a selected or authorized location and returns the created path. (Requires:localFileWrite)SwiftBiu.writeLocalTextFile(path: String, text: String): Creates a new UTF-8 text file inside a selected or authorized location and returns the created path. (Requires:localFileWrite)SwiftBiu.overwriteLocalFile(path: String, base64String: String): Replaces the contents of an existing accessible file and returns the file path. (Requires:localFileWrite)SwiftBiu.renameLocalFile(path: String, newName: String): Renames a selected local file within its current directory. (Requires:localFileWrite)SwiftBiu.copyLocalFile(sourcePath: String, destinationPath: String): Copies a selected local file to an accessible destination path. (Requires:localFileWrite)SwiftBiu.moveLocalFile(sourcePath: String, destinationPath: String): Moves a selected local file to an accessible destination path. (Requires:localFileWrite)SwiftBiu.requestDirectoryAuthorization(path: String): Opens the native folder authorization panel, stores the chosen directories, and returns the first authorized path. Use this instead of pretending success when sandbox access is missing. (Requires:localFileWrite)SwiftBiu.hasAuthorizedDirectoryAccess(path: String): Returns whether a path is already covered by a persisted writable folder authorization. (Requires:localFileWrite)SwiftBiu.trashLocalItem(path: String): Moves a selected local file or an item inside an authorized directory to the macOS Trash. (Requires:localFileWrite)SwiftBiu.openURL(urlString: String): Launches the default browser to open a link.SwiftBiu.openFileInPreview(filePath: String): Opens a file using the macOS default app (e.g., Preview).SwiftBiu.openFileWithApp(filePath: String, appBundleID: String): Opens an accessible selected or authorized file with the specified macOS app bundle ID. ReturnsBoolean. (Requires:localFileRead)SwiftBiu.showNotification(title: String, body: String): Sends a system-level notification. (Requires:notifications)SwiftBiu.showImage(imageSource: String, position?: Object, context?: Object): Displays the native image toast card.imageSourceaccepts either a Base64 string or anhttp/httpsURL. (Requires:notifications)SwiftBiu.showInteractiveImage(options, onRegenerate): Creates an interactive image session and returns asessionID. Use it when you need regenerate/update behavior from the same image card. (Requires:notifications)SwiftBiu.updateInteractiveImage(sessionID, options)/SwiftBiu.failInteractiveImage(sessionID, message): Updates or fails an existing interactive image session.SwiftBiu.showLoadingIndicator(position: Object)/SwiftBiu.hideLoadingIndicator(): Displays a native loading spinner at the specified coordinates. Recommended only for lightweight non-UI quick actions. FordisplayUI(...), AI bubble, or image card flows, manage loading state inside your own UI/session.
- Advanced Operations:
SwiftBiu.setConfig(key: String, value: String): (Synchronous) Persists a plugin configuration value back to native storage.SwiftBiu.fetch(url, options, onSuccess, onError): (Callback Async) Initiates a low-level network request. (Requires:network)SwiftBiu.fetchStream(url, options, onEvent, onError): (Synchronous Create) Starts a streaming network request and returns astreamID. (Requires:network)SwiftBiu.cancelFetchStream(streamID: String): (Synchronous Cancel) Cancels an active streaming request created byfetchStream(...).SwiftBiu.runShellScript(script, context): (Synchronous) Executes a Bash/Zsh script and returns the output. Avoid this for App Store-compatible plugins because sandboxed builds can block subprocess execution and file-system access. (Requires:runShellScript)
1.4 Native File Task Progress Panel (Background Script)
For file organizers, compressors, exporters, and other write-heavy actions, prefer the native file task panel instead of chaining multiple notifications.
These APIs are available directly in background script.js:
SwiftBiu.beginFileTask(options): Creates a native file-processing session and returns asessionID.SwiftBiu.updateFileTask(sessionID, options): Pushes incremental progress, logs, and structured status updates.SwiftBiu.finishFileTask(sessionID, options): Marks the task as completed.SwiftBiu.failFileTask(sessionID, options): Marks the task as failed and keeps the panel honest.
Recommended options fields:
- Core progress:
headlineText,detailText,totalCount,completedCount,skippedCount,progress,batchItems - Rich log stream:
activityEntrieswith{ message, category, isPinned } - Plan preview:
summaryChipswith{ title, count, tone } - Grouped failures:
failureGroupswith{ identifier, title, count, items, detailText } - Native panel labels:
sectionTitleswithplanTitle,logTitle,fileTitle,failureTitle,actionTitle - Completion actions:
actionButtonswith supportedkindvaluesrevealTargetsandundoMoves - Action payloads:
targetDirectoryPathsandundoOperations
Recommended UX contract for file-processing plugins:
- Show the category plan before the first write happens.
- Ask for native folder authorization immediately when access is missing, then stop cleanly on cancel.
- Stream structural milestones such as folder creation, move start, conflict skip, and category completion.
- Group conflicts and permission failures separately instead of flattening everything into one “failed” bucket.
- Offer lightweight completion actions such as “open target folder” and “undo this run” only after you have the required payloads.
1.5 Native AI Response Bubble (Background Script)
For AI plugins such as Doubao, OpenAI, or Gemini, prefer SwiftBiu's native AI response bubble instead of building a second floating window from scratch.
These APIs are available directly in background script.js and require the ui permission:
SwiftBiu.showAIResponseBubble(options, onEvent): (Synchronous Create) Displays the native AI response bubble and returns asessionID.SwiftBiu.updateAIResponseBubble(sessionID, options): (Synchronous Update) Updates state, status, generated text, and button availability.SwiftBiu.failAIResponseBubble(sessionID, message): (Synchronous Update) Switches the bubble into a failed state with a message.SwiftBiu.closeAIResponseBubble(sessionID): (Synchronous Close) Closes the current bubble session.
Useful onEvent(event) values:
configChanged: The user changedmode,systemPrompt,userPrompt, or section visibility.submit: The user confirmed applying the current text. The event includestext,mode,systemPrompt, anduserPrompt.regenerate: The user requested a fresh generation using the current prompt values.previewPoster/sharePoster: Poster preview and share actions from the native bubble.
Recommended background workflow:
- Call
showAIResponseBubble(...)with the minimal fields your plugin truly needs, usuallytitle,mode, and anonEventhandler. - For one-shot APIs, use
SwiftBiu.fetch(...)and update the bubble once on completion. - For true streaming APIs, use
SwiftBiu.fetchStream(...), parse SSE or chunked output in your script, and repeatedly callupdateAIResponseBubble(...)with the cumulative full text. - When handling
configChanged, persist settings such asmodeor custom prompts throughSwiftBiu.setConfig(...). - When handling
regenerate, cancel any in-flight stream viacancelFetchStream(...)before starting a new request. - When handling
submit, let the background script decide whether to replace or append, then apply the text withpasteText(...).
Best-practice defaults:
- Omit
systemPromptwhen you want the native layer to resolve it from plugin configuration. The current fallback order isresponseSystemPrompt-> manifest default. - Omit
promptVisibleanduserPromptVisibleif you want both prompt editors hidden by default. - Omit
submitLabel,replaceLabel, andappendLabelunless you truly need a plugin-specific override. Native localization should own those labels. - Only pass
stateorstatuswhen your plugin needs a custom state transition or custom wording.
2. Web App Action API (Custom UI)
Web App Actions employ a physically isolated dual-sandbox system. Under this architecture, APIs are strictly divided into the "Background Launcher" and the "User Frontend Interface", isolating them from one another:
Important
Are the APIs Interchangeable?
They are NOT interchangeable. They are distinct and mutually exclusive. For instance, obtaining a plugin configuration is called SwiftBiu.getConfig() (Synchronous) in the background sandbox, but window.swiftBiu.storage.get() (Async Promise) in the frontend sandbox. Ensure you are referencing the correct API for the sandbox your code is currently running in.
A. Background Launcher API (script.js)
In a Web App's background script, complex business logic is omitted. Its primary responsibility is gathering context and launching the web page.
SwiftBiu.displayUI(options: Object)- Purpose: Called during the
performActionlifecycle to explicitly trigger the rendering ofindex.html. - Parameters
options:htmlPath(String, Required): Relative path strictly to the main HTML document (e.g.,"ui/index.html").width(Number, Optional) /height(Number, Optional): Initial window dimensions for the web popup.isFloating(Boolean, Optional): Should the window continue floating on top after losing focus (Defaultfalse).
- Note: You may still utilize the
SwiftBiu.screenSizeproperty to help compute the popup's initialpositionparameter.
- Purpose: Called during the
B. Web UI API (window.swiftBiu)
Once the HTML UI is successfully displayed, the system assumes control and injects a bridging object into the page’s global scope to communicate natively. It is highly recommended to prefix calls with window. to explicitly state the scope.
- Data Injection Hook (Core):
window.swiftBiu_initialize = async function(context) { ... }: You MUST define this global function in your HTML. After the page finishes loading, the system automatically calls it and injects thecontextparameter (such as highlighted text or selected local files) from the background.context.selectedText: The original selected text.context.selectedFiles: An array of inferred local file descriptors from the current selection. It can contain any local file type. Each item contains{ path, fileURL, fileName, fileExtension }.context.locale: The user's preferred locale identifier, such aszh-Hansoren-US.context.languageCode: A simplified language code such aszhoren.- Use this when the host has already recognized local files for the current context. If the user context only contains text-form paths (for example, newline-separated POSIX paths or
file://URLs), your plugin should parsecontext.selectedTextor the result ofSwiftBiu.getClipboard()itself. - On macOS, some sources such as Finder file copies may provide both display text and native file URLs. SwiftBiu preserves those native file URLs when possible and maps them into
context.selectedFileseven ifcontext.selectedTextonly contains file names. - Plugin JavaScript can currently read plain text from the clipboard via
SwiftBiu.getClipboard(). Reading native file-URL objects directly from the macOS pasteboard, like some built-in native actions do, is not guaranteed by the current plugin API.
- Use this when the host has already recognized local files for the current context. If the user context only contains text-form paths (for example, newline-separated POSIX paths or
- Bridge Capabilities (Mind the Async Boundaries):
While the bridge code wraps all these APIs in a Promise (meaning you can technically
awaitall of them), on the native Swift side they are strictly divided into Data-Returning (true async await) and Trigger-Based (Fire-and-Forget, noawaitneeded).- Methods that REQUIRE
awaitfor data:window.swiftBiu.fetch(url, options): Returns{ status: Number, data: String }. (Requires:network)window.swiftBiu.storage.get(key): Returns{ result: String }.window.swiftBiu.getFileMetadata(path): Returns a metadata object for the selected local file. (Requires:localFileRead)window.swiftBiu.extractFileIcon(path, options): Returns{ success, base64, fileName, width, height, format }or{ success: false, error }. Use this host-mediated PNG icon extraction API for App Store sandbox compatibility. (Requires:localFileRead)window.swiftBiu.setFileIcon(targetPath, iconPath, options): Returns{ success, targetPath, iconPath }or{ success: false, error }. Applies an accessible image as a custom Finder icon for an accessible file, folder, or.appbundle. (Requires:localFileReadandlocalFileWrite)window.swiftBiu.readLocalFile(path): Returns{ base64: String }. Reads any local file from the currentcontext.selectedFilesonly. (Requires:localFileRead)window.swiftBiu.readLocalTextFile(path): Returns{ result: String }. Convenience API for decoding the current selected file as UTF-8 text. (Requires:localFileRead)window.swiftBiu.listDirectory(path): Returns{ items: Array<Object> }. Lists direct children of an accessible directory. (Requires:localFileRead)window.swiftBiu.fileExists(path): Returns{ exists: Boolean }. Checks whether an accessible path exists as a file. (Requires:localFileReadorlocalFileWrite)window.swiftBiu.directoryExists(path): Returns{ exists: Boolean }. Checks whether an accessible path exists as a directory. (Requires:localFileReadorlocalFileWrite)window.swiftBiu.runShellScript(script, context): Returns{ result: String }. Do not rely on this for App Store-compatible plugins. (Highly restricted by App Store sandbox).
- Trigger-Based Methods (No
awaitneeded): (Although they return a JS Promise, the native side resolves them immediately upon receiving the command without blocking to wait for side-effects like dialogs. Treat them as synchronous triggers.)window.swiftBiu.copyText(text): Copies text to the system clipboard.window.swiftBiu.pasteText(text): Copies and actively pastes text into the focused window.window.swiftBiu.openURL(url): Opens a Web URL via the default browser.window.swiftBiu.openFileWithApp(path, appBundleID): Returns{ success: Boolean }. Opens an accessible selected or authorized file with the specified macOS app bundle ID. (Requires:localFileRead)window.swiftBiu.speakText(text): Utilizes the macOS native TTS to speak the given text aloud.window.swiftBiu.pickLocalFile(options): Returns{ path: String }. Opens the native file picker and persists authorization for the selected item. Supportskind: "application"orkind: "image". (Requires:localFileReadorlocalFileWrite)window.swiftBiu.pickLocalDirectory(): Returns{ path: String }. Opens the native folder picker and persists the chosen writable location. (Requires:localFileWrite)window.swiftBiu.createLocalDirectory(path): Returns{ path: String }. Creates a directory inside a selected or authorized location. (Requires:localFileWrite)window.swiftBiu.createLocalFile(path, base64String): Returns{ path: String }. Creates a new file from Base64 data inside a selected or authorized location. (Requires:localFileWrite)window.swiftBiu.writeLocalTextFile(path, text): Returns{ path: String }. Creates a new UTF-8 text file inside a selected or authorized location. (Requires:localFileWrite)window.swiftBiu.overwriteLocalFile(path, base64String): Returns{ path: String }. Replaces the contents of an existing accessible file. (Requires:localFileWrite)window.swiftBiu.renameLocalFile(path, newName): Returns{ path: String }. Renames a selected local file in place. (Requires:localFileWrite)window.swiftBiu.copyLocalFile(sourcePath, destinationPath): Returns{ path: String }. Copies a selected local file to an accessible destination path. (Requires:localFileWrite)window.swiftBiu.moveLocalFile(sourcePath, destinationPath): Returns{ path: String }. Moves a selected local file to an accessible destination path. (Requires:localFileWrite)window.swiftBiu.trashLocalItem(path): Returns{ success: Boolean }. Moves a selected local file or an item in an authorized location to the macOS Trash. (Requires:localFileWrite)window.swiftBiu.saveLocalFile(base64String, filename): Triggers the macOS native "Save As" dialogue for arbitrary file data.window.swiftBiu.exportFile(base64String, filename): Backward-compatible alias forsaveLocalFile(...).
- Methods that REQUIRE
- Window Lifecycles and Fluid Control (Trigger-Based):
window.swiftBiu.ui.resizeWindow({ height: Number }): Dynamically adjusts the height of the Web App window for responsive popups. (Recommend leaving a 30px buffer).window.swiftBiu.closeWindow(): (Trigger-Based) Closes its own Web UI window instantly. (Note: The JS context immediately dies; code after this call may not execute).
Best Practice for Auto-Resizing Height
To achieve perfect, smooth resizing, follow this CSS and JavaScript strategy:
- CSS: Set
background-color: transparent;on<html>and apply your main background styles (like frosted glass) to<body>withmin-height: 100vh;. Let your main content container resize naturally without a fixed height. - JavaScript: After your content is rendered, manually calculate the total height of all visible elements (
element.offsetHeight) and add a sufficient buffer (e.g., 30px - 50px). This buffer is crucial to prevent content from being clipped by window edges or shadows. CallresizeWindowwith this calculated height. This is more reliable thanResizeObserverordocument.body.scrollHeightalone.
Native File and Folder Selection
Plugins can trigger native macOS file and folder selection dialogs directly from the Web UI.
- File Selection: Use a standard
<input type="file">. - Folder Selection: Add the
webkitdirectoryattribute:<input type="file" webkitdirectory>. (Best Practice: use theFileReaderAPI to read the file content as anArrayBufferorDataURLas soon as the user selects the files, and cache that data. Avoid relying on the sameFileobject for too long).
Best Practice for Sandboxed File Creation
When a plugin needs to create files or folders inside the App Store sandbox, prefer this flow:
- Call
pickLocalDirectory()so the user explicitly chooses a writable folder. - Create subfolders with
createLocalDirectory(...)and files withcreateLocalFile(...)underneath that returned path. - Use
trashLocalItem(...)instead of permanently deleting content.
Best Practice for App Icon and File Icon Extraction
If a plugin needs to export a selected app's icon, do not inspect .app/Contents/Info.plist yourself or invoke external tools such as sips, qlmanage, shell scripts, AppleScript, or osascript. Those paths may work in the website/developer build and fail in the App Store sandbox.
Use the host-mediated API instead:
function performAction(context) {
const selectedApp = (context.selectedFiles || []).find(file => {
const path = String(file.path || "").toLowerCase();
return path.endsWith(".app");
});
if (!selectedApp) {
SwiftBiu.showNotification("Extract App Icon", "Select a .app first.");
return;
}
const icon = SwiftBiu.extractFileIcon(selectedApp.path, { size: 1024 });
if (!icon || icon.success !== true || !icon.base64) {
SwiftBiu.showNotification("Extract App Icon", icon && icon.error ? icon.error : "Icon extraction failed.");
return;
}
const folder = SwiftBiu.pickLocalDirectory();
if (!folder) return;
const outputPath = folder.replace(/\/+$/, "") + "/" + (icon.fileName || "App_Icon.png");
const savedPath = SwiftBiu.createLocalFile(outputPath, icon.base64);
if (savedPath) SwiftBiu.openFileInPreview(savedPath);
}
Cross-Platform (macOS & iOS) Compatibility
With SwiftBiu expanding to iOS, your plugins can run seamlessly across both platforms with the exact same .swiftbiux package. However, you must adhere to the following responsive design and API graceful degradation practices:
1. Responsive Web UI (Rich Web Apps)
- Viewport Meta (Required): You must include
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">in yourindex.htmlto prevent iOS from automatically zooming in when users tap input fields. - Fluid Layouts: Do not fixate on desktop split-views. Use CSS
@media (max-width: 600px)to transition desktop sidebars into horizontal scrolling areas or stacked vertical layouts on mobile. - Touch Targets & Font Size: Enlarge clickable elements (buttons, list rows) to at least
44x44px. Ensure<input>and<textarea>font sizes are at least16pxto avoid unexpected iOS WebView zoom behaviors. - Initial Window Size:
widthandheightindisplayUI()are respected on macOS for the physical floating window. On iOS (iPhone), they are ignored, and the UI is presented as a bottom Sheet. Treat these parameters as the "Desktop Preferred Size" and rely on fluid CSS for mobile bounding.
2. API Graceful Degradations
- Clipboard & Paste: On macOS,
swiftBiu.pasteText()writes to the clipboard and simulatesCmd+V. On the iOS Main App, this degrades gracefully to a "Copied to Clipboard" action with a Toast notification. However, if the user triggers the plugin inside the iOS Keyboard Extension, it will insert text directly at the cursor as expected. - Unsupported or restricted scripting APIs:
runShellScriptandrunAppleScriptare unavailable on iOS and should not be used for App Store-compatible macOS plugins. The App Store sandbox can block subprocess execution, automation, and filesystem access even when the same script works in the website/developer build. Prefer SwiftBiu host APIs such asextractFileIcon(...),setFileIcon(...),pickLocalFile(...),readLocalFile(...),pickLocalDirectory(...), andcreateLocalFile(...). If your plugin relies heavily on Node.js, consider using Webpack/Rollup to bundle JS dependencies directly into yourscript.js, or utilize Apple Shortcuts integration for complex iOS automation.
📚 Citation & AI Reference
Cite the manifest schema and background sandbox specifications: https://swiftbiu.com/developer/manifest/