iOS分享扩展显示应用但点击无法打开,求问题排查方案
我给iOS应用添加了Share Extension,删除了扩展的storyboard,ShareViewController代码如下:
import UIKit import Social import CoreServices import UniformTypeIdentifiers class ShareViewController: UIViewController { private let typeText = UTType.text.identifier private let typeURL = UTType.url.identifier private let appURL = "MyExtension://" private let groupName = "group.sharingsampletwo" private let urlDefaultName = "incomingURL" override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 1 guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem, let itemProvider = extensionItem.attachments?.first else { self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) return } if itemProvider.hasItemConformingToTypeIdentifier(typeText) { handleIncomingText(itemProvider: itemProvider) } else if itemProvider.hasItemConformingToTypeIdentifier(typeURL) { handleIncomingURL(itemProvider: itemProvider) } else { print("Error: No url or text found") self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil) } } private func handleIncomingText(itemProvider: NSItemProvider) { itemProvider.loadItem(forTypeIdentifier: typeText, options: nil) { (item, error) in if let error = error { print("Text-Error: \(error.localizedDescription)") } if let text = item as? String { do {// 2.1 let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) let matches = detector.matches( in: text, options: [], range: NSRange(location: 0, length: text.utf16.count) ) // 2.2 if let firstMatch = matches.first, let range = Range(firstMatch.range, in: text) { self.saveURLString(String(text[range])) } } catch let error { print("Do-Try Error: \(error.localizedDescription)") } } self.openMainApp() } } private func handleIncomingURL(itemProvider: NSItemProvider) { itemProvider.loadItem(forTypeIdentifier: typeURL, options: nil) { (item, error) in if let error = error { print("URL-Error: \(error.localizedDescription)") } if let url = item as? NSURL, let urlString = url.absoluteString { self.saveURLString(urlString) } self.openMainApp() } } private func saveURLString(_ urlString: String) { UserDefaults(suiteName: self.groupName)?.set(urlString, forKey: self.urlDefaultName) } private func openMainApp() { self.extensionContext?.completeRequest(returningItems: nil, completionHandler: { _ in guard let url = URL(string: self.appURL) else { return } _ = self.openURL(url) }) } // Function must be named exactly like this so a selector can be found by the compiler! // Anyway - it's another selector in another instance that would be "performed" instead. @objc private func openURL(_ url: URL) -> Bool { var responder: UIResponder? = self while responder != nil { if let application = responder as? UIApplication { return application.perform(#selector(openURL(_:)), with: url) != nil } responder = responder?.next } return false } }
我已经为主应用和分享扩展添加了App Groups能力:
接着修改了分享扩展的info.plist:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>NSExtensionActivationRule</key> <dict> <key>NSExtensionActivationSupportsText</key> <true/> <key>NSExtensionActivationSupportsWebURLWithMaxCount</key> <integer>1</integer> </dict> </dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.share-services</string> <key>NSExtensionPrincipalClass</key> <string>Share.ShareViewController</string> </dict> </dict> </plist>
之后在AppDelegate中添加了如下代码:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { if let scheme = url.scheme, scheme.caseInsensitiveCompare("MyExtension") == .orderedSame, let page = url.host { var parameters: [String: String] = [:] URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.forEach { parameters[$0.name] = $0.value } print("redirect(to: \(page), with: \(parameters))") for parameter in parameters where parameter.key.caseInsensitiveCompare("url") == .orderedSame { UserDefaults().set(parameter.value, forKey: "incomingURL") } } return true }
目前分享扩展能显示我的应用,但点击后无法打开主应用,请问是否需要付费Apple开发者账号?还有哪些配置遗漏?
关于付费Apple开发者账号
不需要付费账号也能测试Share Extension和URL Scheme跳转功能,免费账号的真机调试权限足够支持这些功能,问题出在配置或代码逻辑上。
遗漏的配置与代码问题
主应用未配置对应的URL Scheme
你在扩展中用了MyExtension://来唤起主应用,但主应用的Info.plist里没有注册这个Scheme。需要在主应用的Info.plist中添加CFBundleURLTypes数组:<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>MyExtension</string> </array> <key>CFBundleURLName</key> <string>自定义名称(比如com.yourcompany.yourapp)</string> </dict> </array>URL跳转逻辑的兼容性问题
你用的openURL方法在iOS 10及以上已经被废弃,应该改用UIApplication.shared.open(_:options:completionHandler:)。替换扩展中的openURL方法:@objc private func openURL(_ url: URL) -> Bool { if #available(iOS 10.0, *) { UIApplication.shared.open(url, options: [:], completionHandler: nil) return true } else { return UIApplication.shared.openURL(url) } }可以添加日志排查是否执行到了跳转代码,确认逻辑路径是否正常。
UserDefaults的读取问题
主应用中读取共享数据时,应该用UserDefaults(suiteName: groupName)而不是默认的UserDefaults(),否则读不到扩展存在共享组里的数据。修改AppDelegate中的代码:// 替换原来的UserDefaults().set(...) UserDefaults(suiteName: "group.sharingsampletwo")?.set(parameter.value, forKey: "incomingURL")扩展的Info.plist中NSExtensionPrincipalClass的正确性
确认Share.ShareViewController的类名和模块名正确,如果你没有自定义模块名,建议用$(PRODUCT_MODULE_NAME).ShareViewController来避免硬编码错误,保证不同环境下的兼容性。
内容的提问来源于stack exchange,提问作者BraveEvidence

