如何使用Swift在iOS应用中接收共享数据并注册为接收方?
Great question! Getting your iOS app to show up in the share sheet and handle incoming data like images involves two core steps: registering your app as a share target and processing the received data. Let’s break this down with concrete steps and code examples.
Step 1: Add a Share Extension (Recommended Approach)
The modern, seamless way to accept shared data is using a Share Extension. This lets your app appear in the share sheet without needing to be open first, and runs in a separate process to handle the data.
Add the Extension to Your Project
- Open your Xcode project.
- Go to
File > New > Target. - Under "iOS", select Share Extension and click "Next".
- Name your extension (e.g., "ImageShareExtension") and make sure the "Embed in Application" dropdown selects your main app target. Click "Finish".
Configure the Extension to Accept Images
Next, tell the extension what types of data it can handle by editing its Info.plist:
- Open the
Info.plistfor your Share Extension. - Navigate to
NSExtension > NSExtensionAttributes > NSExtensionActivationRule. - Replace the default string with a dictionary that specifies supported types. For images, add:
NSExtensionActivationSupportsImageWithMaxCountset to1(or higher if you want to accept multiple images).- Optional: Add other keys like
NSExtensionActivationSupportsTextif you want to accept text too.
Alternatively, use a predicate for more flexibility (e.g., accept any image type):
<key>NSExtensionActivationRule</key> <string>SUBQUERY (extensionItems, $extensionItem, SUBQUERY ($extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image").@count > 0).@count > 0</string>
Step 2: Handle Incoming Data in the Share Extension
The Share Extension’s main logic lives in the ShareViewController.swift file (a subclass of SLComposeServiceViewController). Here’s how to retrieve the shared image and pass it to your main app:
import UIKit import Social import MobileCoreServices class ShareViewController: SLComposeServiceViewController { override func didSelectPost() { guard let inputItems = extensionContext?.inputItems as? [NSExtensionItem] else { finishProcessing() return } // Loop through incoming items to find image attachments for item in inputItems { guard let attachments = item.attachments as? [NSItemProvider] else { continue } for attachment in attachments { if attachment.hasItemConformingToTypeIdentifier(kUTTypeImage as String) { // Load the image from the attachment attachment.loadObject(ofClass: UIImage.self) { [weak self] (result, error) in guard let self = self, let image = result as? UIImage else { self?.finishProcessing() return } // Pass the image to your main app using an App Group self.saveImageToAppGroup(image: image) // Notify the main app that new data is available self.notifyMainApp() self.finishProcessing() } return // Exit after processing the first image (adjust if handling multiple) } } } finishProcessing() } private func saveImageToAppGroup(image: UIImage) { guard let imageData = image.pngData(), let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "com.yourcompany.yourappgroup") else { return } let fileURL = groupURL.appendingPathComponent("shared_image.png") try? imageData.write(to: fileURL) } private func notifyMainApp() { UserDefaults(suiteName: "com.yourcompany.yourappgroup")?.set(true, forKey: "has_shared_image") } private func finishProcessing() { extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) } }
Set Up App Groups for Data Sharing
Since extensions run in a separate process, you need an App Group to share data between the extension and your main app:
- Go to your main app target in Xcode.
- Select
Signing & Capabilities > Add Capability > App Groups. - Add a group identifier (e.g.,
com.yourcompany.yourappgroup). - Repeat this step for your Share Extension target to enable the same App Group.
Step 3: Receive Data in Your Main App
Now, your main app needs to check for shared data when it launches or becomes active. Add this logic to your SceneDelegate.swift (or AppDelegate.swift if you’re not using scenes):
import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func sceneDidBecomeActive(_ scene: UIScene) { checkForSharedImage() } private func checkForSharedImage() { let defaults = UserDefaults(suiteName: "com.yourcompany.yourappgroup") guard defaults?.bool(forKey: "has_shared_image") == true else { return } guard let groupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "com.yourcompany.yourappgroup"), let imageData = try? Data(contentsOf: groupURL.appendingPathComponent("shared_image.png")), let sharedImage = UIImage(data: imageData) else { defaults?.set(false, forKey: "has_shared_image") return } // Do something with the image (e.g., display it, save to your app's storage) print("Received shared image: \(sharedImage.size)") // Clean up: reset the flag and delete the temporary file defaults?.set(false, forKey: "has_shared_image") try? FileManager.default.removeItem(at: groupURL.appendingPathComponent("shared_image.png")) } }
Alternative: Accept Files Directly in the Main App
If you prefer your main app to open immediately when a user shares a file, you can skip the extension and configure your app to accept specific file types via its Info.plist:
- Open your main app’s
Info.plist. - Add the
CFBundleDocumentTypesarray:
<key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Image Files</string> <key>LSHandlerRank</key> <string>Alternate</string> <key>LSItemContentTypes</key> <array> <string>public.image</string> </array> </dict> </array>
Then, handle the incoming file URL in your SceneDelegate or AppDelegate:
// In SceneDelegate func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { guard let fileURL = URLContexts.first?.url, fileURL.isFileURL else { return } do { let imageData = try Data(contentsOf: fileURL) if let image = UIImage(data: imageData) { // Process the image } } catch { print("Error loading shared file: \(error.localizedDescription)") } }
Testing the Flow
- Run your Share Extension target (select it from the scheme dropdown in Xcode).
- Choose an app to test with (e.g., Photos).
- Select an image, tap the share button, and your extension should appear in the list.
- Tap your extension, then "Post"—your main app will receive the image when it’s opened or activated.
内容的提问来源于stack exchange,提问作者David J

