You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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能力:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:57:03