iOS Share and Action Extensions¶
OpenMedKit includes reusable Swift targets for redacting selected text inside an iOS Share extension or Action extension. Both paths use bundled policy profiles, return the redacted text to the host app, and keep model loading and inference on the device.
The package provides three products:
OpenMedExtensionSupportcontains the item handler, span result, local model guard, and memory budget.OpenMedShareExtensioncontainsRedactionShareViewControllerand a policy picker backed byPolicy.bundledProfileNames.OpenMedActionExtensioncontainsRedactionActionRequestHandlerfor a non-UI Action extension.
Swift Package Manager supplies the reusable code. Create and embed the Share and Action extension targets in the host Xcode project; App Store provisioning and submission remain host-app responsibilities.
Bundle a Nano model¶
Extensions must not download model or tokenizer files. Add this folder to both extension targets as a folder reference:
OpenMedPIINano/
├── OpenMedPIINano.mlmodelc
├── id2label.json
└── tokenizer/
├── tokenizer.json
└── tokenizer_config.json
Use a precompiled, INT8 Core ML PII model. The extension Nano packaging profile accepts no more than 40 MiB of model, label, and tokenizer assets, caps token sequences at 256, and reserves 56 MiB for tokenizer, Core ML, input, and output working memory. Its maximum estimated peak is therefore 96 MiB, below the package's conservative 120 MiB extension envelope. Model loading fails before inference when the asset budget is exceeded.
NanoModelConfiguration accepts only local file: URLs and verifies that the compiled model and tokenizer are directories, the label map and required tokenizer files are regular files, and no asset is a symbolic link. Hidden files count toward the asset budget. The runtime uses the tokenizer folder with allowNetworkAccess: false, so missing assets fail closed instead of falling back to a download.
Add the Share extension¶
- In Xcode, add an iOS Share Extension target.
- Link the
OpenMedShareExtensionpackage product to that target. - Replace the generated view controller with a thin host-target subclass and keep
$(PRODUCT_MODULE_NAME).ShareViewControlleras the principal class:
- Restrict the activation rule to plain text with
NSExtensionActivationSupportsText = true. - Add the
OpenMedPIINanofolder to the extension target's Copy Bundle Resources phase.
The controller reads NSExtensionItem plain-text attachments, displays the selected text and every bundled policy profile, runs the Nano model after the user confirms, and completes the request with a new plain-text attachment.
Add the Action extension¶
- In Xcode, add an iOS Action Extension target.
- Link the
OpenMedActionExtensionpackage product to that target. - Replace the generated request handler with a thin host-target subclass and keep
$(PRODUCT_MODULE_NAME).ActionRequestHandleras the principal class:
Configure the target with a text activation rule. 4. Add the same OpenMedPIINano folder to the Action target.
The request handler processes text attachments sequentially and returns one redacted NSExtensionItem for each input. It defaults to hipaa_safe_harbor. A host can choose another bundled profile by setting the input item's OpenMedPolicyProfile user-info value.
Privacy and failure behavior¶
- The extension source modules call no networking API and request no networking entitlement. A source guard test rejects additions such as
URLSession,NWConnection, or a network-client entitlement, and a runtime test verifies that missing tokenizer assets fail closed. - Remote model URLs are rejected even if the host app passes one accidentally.
- Each input is limited to 16,384 characters and 64 KiB of UTF-8, with at most eight text attachments and 128 KiB across one request. Image and PDF attachments are not accepted.
- Raw input and detected span text are not logged or written to audit artifacts.
- The model runtime is released after each request and OpenMedKit clears unused runtime buffers on both success and failure before the extension exits.
Run the extension contract tests with: