iOS 上的共享扩展无法打开我的本机反应应用程序
Share extension on iOS won't open my react-native app
我有一个 React Native
项目,我正在尝试使用 Xcode
和 swift
构建共享扩展。我试过使用 https://github.com/meedan/react-native-share-menu 但它对我不起作用。我也尝试过其他库,但它们维护不当,所以我决定自己构建一个。
我只想在我的应用程序中处理 urls 和文本。
我先创建一个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:
// 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[[=13=].name] = [=13=].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 时,我能够在分享 sheet 中看到我的应用程序,但是当我点击我的应用程序时没有任何反应。感觉就像我的应用程序崩溃或什么的。我在 Xcode 控制台中也没有看到任何内容。此外,当我从共享 sheet 单击我的应用程序时,我看不到 iOS 在共享 url 时显示的 post 对话框。共享文本时发生同样的问题
我用 Swift 创建了一个小型原生 iOS 应用程序,可以在 https://github.com/PritishSawant/iosDevShare. I am following this article https://medium.com/@damisipikuda/how-to-receive-a-shared-content-in-an-ios-application-4d5964229701 上使用它来创建扩展程序
我想通了。我忘了在我的主应用程序的信息列表中添加以下内容
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>leaaoShare</string>
</array>
</dict>
</array>
我有一个 React Native
项目,我正在尝试使用 Xcode
和 swift
构建共享扩展。我试过使用 https://github.com/meedan/react-native-share-menu 但它对我不起作用。我也尝试过其他库,但它们维护不当,所以我决定自己构建一个。
我只想在我的应用程序中处理 urls 和文本。
我先创建一个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:
// 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[[=13=].name] = [=13=].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 时,我能够在分享 sheet 中看到我的应用程序,但是当我点击我的应用程序时没有任何反应。感觉就像我的应用程序崩溃或什么的。我在 Xcode 控制台中也没有看到任何内容。此外,当我从共享 sheet 单击我的应用程序时,我看不到 iOS 在共享 url 时显示的 post 对话框。共享文本时发生同样的问题
我用 Swift 创建了一个小型原生 iOS 应用程序,可以在 https://github.com/PritishSawant/iosDevShare. I am following this article https://medium.com/@damisipikuda/how-to-receive-a-shared-content-in-an-ios-application-4d5964229701 上使用它来创建扩展程序
我想通了。我忘了在我的主应用程序的信息列表中添加以下内容
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>leaaoShare</string>
</array>
</dict>
</array>