iOS 上的共享扩展无法打开我的 react-native 应用

Posted

技术标签:

【中文标题】iOS 上的共享扩展无法打开我的 react-native 应用【英文标题】:Share extension on iOS won't open my react-native app 【发布时间】:2021-01-07 04:32:36 【问题描述】:

我有一个React Native 项目,我正在尝试使用Xcodeswift 构建共享扩展。我尝试过使用https://github.com/meedan/react-native-share-menu,但它对我不起作用。我也尝试过其他库,但它们没有得到适当的维护,所以我决定自己构建一个。

我只想在我的应用中处理 url 和文本。

我首先创建了一个Share extension 并将其命名为 Share

以下是我的 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>CFBundleDevelopmentRegion</key>
    <string>$(DEVELOPMENT_LANGUAGE)</string>
    <key>CFBundleDisplayName</key>
    <string>Share</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <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>NSExtensionPrincipalClass</key>
    <string>Share.ShareViewController</string>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.share-services</string>
    </dict>
</dict>
</plist>

以下是我的ShareViewController代码

import UIKit
import Social
import CoreServices

class ShareViewController: UIViewController 

    private let typeText = String(kUTTypeText)
    private let typeURL = String(kUTTypeURL)
    private let appURL = "leaaoShare://"
    private let groupName = "group.leaaoShare"
    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) 
      print("here22")
        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) 
      print("here")
        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)
        )
    

    // Courtesy: https://***.com/a/44499222/13363449 ????????
    // 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
    

以下是我的 AppDelegate 代码

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool 
    if let scheme = url.scheme,
      scheme.caseInsensitiveCompare("leaaoShare") == .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
  

我还为我的主要和共享扩展项目创建了App groups

当我尝试从 safari 分享 url 时,我可以在分享表中看到我的应用,但是当我点击我的应用时没有任何反应。感觉就像我的应用程序崩溃或什么的。我在 Xcode 控制台中也看不到任何东西。此外,当我从共享表中单击我的应用程序时,我看不到 ios 在共享 url 时显示的帖子对话框。分享文字时也会出现同样的问题

我使用 Swift 创建了一个小型原生 iOS 应用程序,它可以在https://github.com/PritishSawant/iosDevShare 获得。我正在关注这篇文章https://medium.com/@damisipikuda/how-to-receive-a-shared-content-in-an-ios-application-4d5964229701创建扩展

【问题讨论】:

ShareViewConroller 中的所有 UI 组件是什么?加载项部分可以在 viewDidLoad 中完成。您可以尝试调试共享扩展以获取更多信息。 试试,在关闭扩展之前调用 OpenURL。 【参考方案1】:

我发现了这个问题。我忘了在我的主应用程序的信息列表中添加以下内容

<key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>leaaoShare</string>
            </array>
        </dict>
    </array>

【讨论】:

以上是关于iOS 上的共享扩展无法打开我的 react-native 应用的主要内容,如果未能解决你的问题,请参考以下文章

无法从共享扩展 ios 保存视频

iOS 共享扩展不显示/无法接收 URL

iOS 共享扩展未显示 URL 和文本

NSUserDefaults 线程在 IOS 上的扩展之间共享数据是不是安全?

Swift 中的 iOS 共享扩展抓取 URL

如何在 iOS 中获取共享扩展的状态?