rshankras/app-extensions
Generates app extension infrastructure for Share Extensions, Action Extensions, Keyboard Extensions, and Safari Web Extensions with data sharing via App Groups. Use when user wants to add a share extension, action extension, keyboard extension, Safari web extension, or any app extension type.
npx skills add https://github.com/rshankras/claude-code-apple-skills --skill app-extensions
Generate production app extension infrastructure -- Share Extensions for receiving content from other apps, Action Extensions for manipulating content in-place, Keyboard Extensions for custom input, and Safari Web Extensions for browser integration. Includes App Group data sharing between the host app and extensions.
Use this skill when the user:
Search for existing extension targets:
Glob: **/*Extension*/*.swift, **/*Extension*/Info.plist
Grep: "NSExtensionPointIdentifier" or "NSExtensionPrincipalClass"
If existing extensions found:
Check for existing App Groups setup:
Glob: **/*.entitlements
Grep: "com.apple.security.application-groups"
If App Groups exist, reuse the existing group identifier.
Ask user via AskUserQuestion:
Read templates.md for production Swift code.
Based on extension type selected:
Share Extension:
ShareViewController.swift -- Main share extension view controller with content handlingInfo.plist -- Extension configuration with activation rulesAction Extension:
ActionViewController.swift -- Action extension with content manipulationInfo.plist -- Extension configurationKeyboard Extension:
KeyboardViewController.swift -- Custom keyboard with UIInputViewControllerInfo.plist -- Keyboard extension configurationSafari Web Extension:
SafariWebExtensionHandler.swift -- Native message handlermanifest.json -- Web extension manifestcontent.js -- Content script templateIf data sharing selected:
10. SharedDataManager.swift -- App Group data sharing helper
Extensions are separate targets:
ShareExtension/ActionExtension/KeyboardExtension/SafariWebExtension/Shared/ or within main app targetAfter generation, provide:
Share Extension:
ShareExtension/
├── ShareViewController.swift # Main share extension view controller
└── Info.plist # Extension activation rules & config
Action Extension:
ActionExtension/
├── ActionViewController.swift # Content manipulation controller
└── Info.plist # Extension activation rules & config
Keyboard Extension:
KeyboardExtension/
├── KeyboardViewController.swift # UIInputViewController subclass
└── Info.plist # Keyboard extension config
Safari Web Extension:
SafariWebExtension/
├── SafariWebExtensionHandler.swift # Native message handler
└── Resources/
├── manifest.json # Web extension manifest
├── content.js # Content script
└── popup.html # Popup UI (optional)
Shared (if data sharing enabled):
Shared/
└── SharedDataManager.swift # App Group data sharing
1. Add Extension Target in Xcode:
com.yourapp.ShareExtension2. Configure App Groups (if data sharing):
group.com.yourapp.shared3. Share code between targets:
Accept shared URLs:
if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
provider.loadItem(forTypeIdentifier: UTType.url.identifier) { item, error in
guard let url = item as? URL else { return }
// Process URL
}
}
Accept shared images:
if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
provider.loadItem(forTypeIdentifier: UTType.image.identifier) { item, error in
if let imageURL = item as? URL {
let imageData = try? Data(contentsOf: imageURL)
// Process image data
}
}
}
Share data to main app via App Groups:
let shared = SharedDataManager.shared
shared.saveSharedContent(url.absoluteString, forKey: "lastSharedURL")
Share Extension:
Action Extension:
Keyboard Extension:
Safari Web Extension:
completeRequest() or cancelRequest() when doneThe system can terminate extensions at any time for resource reclamation. Save state frequently and handle interruption gracefully.
The extension host waits for extensionContext?.completeRequest(returningItems:). If you never call it, the share sheet hangs and the user is stuck. Always call it in both success and error paths.
By default keyboard extensions have no network access. The user must explicitly grant "Allow Full Access" in Settings. Without it, URLSession calls fail silently. Design your keyboard to work without network and enhance when access is granted.
The App Group identifier must be identical in both the main app and extension entitlements. A typo means UserDefaults(suiteName:) returns a different (empty) container.
Content scripts cannot directly access the page's JavaScript variables. Use window.postMessage or the browser messaging API to communicate between content scripts and the page.
Extension bundle identifiers must be prefixed with the main app bundle identifier:
com.yourcompany.myappcom.yourcompany.myapp.ShareExtensiongenerators/deep-linking -- Handle URLs received via extensionsgenerators/push-notifications -- Notification extensions (Service/Content)Take rshankras/app-extensions from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.