Как передать URL -адрес в приложение для iOS с общего листа?IOS

Программируем под IOS
Ответить
Anonymous
 Как передать URL -адрес в приложение для iOS с общего листа?

Сообщение Anonymous »

Обновление: кажется, что это поведение не разрешено в iOS, несмотря на то, что популярные приложения, такие как CHATGPT, разрешают это делать ... Чтобы обойти это, теперь я просто передаю URL к приложению, когда значок приложения нажимается с общего листа, а затем отправляю уведомление пользователю, которое говорит им, чтобы щелкнуть его, чтобы продолжить. Я думаю, что это юридическое поведение в соответствии с руководящими принципами Apple Dev, но кто знает больше. Когда пользователь делится веб -страницей через общий лист iOS, нажатие на расширение действия моего приложения должно запустить приложение и передать текущий URL -адрес для отображения. Я установил пользовательскую схему URL («MyApp») в своих типах URL. Например, когда я печатаю myApp: // share? Url = example.com в Safari, я получаю подсказку, чтобы открыть свое приложение, и после подтверждения URL -адрес правильно передается и отображается в моем приложении. Например, вот что напечатано:

Расширение действия: сформирована глубокая ссылка: myApp: // share? /> Основное приложение < /strong> < /p>
import SwiftUI
import SwiftData

// You can keep NavigationManager here or move it to its own file.
class NavigationManager: ObservableObject {
static let shared = NavigationManager()
@Published var sharedURL: URL? = nil

func navigateToURL(_ url: URL) {
sharedURL = url
}
}

// The AppDelegate that handles deep linking
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
print("AppDelegate triggered with URL: \(url)")
// (Your URL parsing and handling code follows here)
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
components.scheme == "myapp",
components.host == "share",
let queryItem = components.queryItems?.first(where: { $0.name == "url" }),
let sharedURLString = queryItem.value,
let sharedURL = URL(string: sharedURLString) else {
return false
}

NavigationManager.shared.navigateToURL(sharedURL)
return true
}

}

@main
struct MyApp: App {
// Connect your AppDelegate to the SwiftUI lifecycle.
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject private var navManager = NavigationManager.shared

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(navManager)
.onOpenURL { url in
// Optional fallback if needed; the AppDelegate should already handle it.
handleSharedURL(url)
}
}
}

private func handleSharedURL(_ url: URL) {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
components.scheme == "myapp",
components.host == "share",
let queryItem = components.queryItems?.first(where: { $0.name == "url" }),
let sharedURLString = queryItem.value,
let sharedURL = URL(string: sharedURLString) else {
return
}
navManager.navigateToURL(sharedURL)
}
}

контроллер представления действия

import UIKit
import UniformTypeIdentifiers

class ActionViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Optionally hide the view if you want no visible UI
view.isHidden = true
processInput()
}

private func processInput() {
print("Action Extension: processInput started")

// Get the first input item
guard let inputItem = extensionContext?.inputItems.first as? NSExtensionItem else {
completeRequest()
return
}

// Try to extract a URL from the item
let urlType = UTType.url.identifier
if let attachment = inputItem.attachments?.first,
attachment.hasItemConformingToTypeIdentifier(urlType) {
attachment.loadItem(forTypeIdentifier: urlType, options: nil) { [weak self] data, error in
guard let self = self else { return }
if let url = data as? URL {
self.handleURL(url)
} else {
print("Action Extension: Failed to load URL from attachment")
self.completeRequest()
}
}
} else {
print("Action Extension: No valid attachment found")
completeRequest()
}
}

private func handleURL(_ url: URL) {
// Encode the URL to form a proper deep link
guard let encodedURL = url.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let deepLink = URL(string: "myapp://share?url=\(encodedURL)") else {
print("Action Extension: Error forming deep link")
completeRequest()
return
}

print("Action Extension: Deep Link formed: \(deepLink)")

// Attempt to open the main app with the deep link
extensionContext?.open(deepLink) { success in
if success {
print("Action Extension: Opened main app successfully")
} else {
print("Action Extension: Failed to open main app")
}
self.completeRequest()
}
}

private func completeRequest() {
// Dismiss the extension
extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
}
}


Плист расширения действия:




LSApplicationQueriesSchemes

myapp

NSExtension

NSExtensionAttributes

NSExtensionActivationRule
TRUEPREDICATE

NSExtensionPointIdentifier
com.apple.ui-services
NSExtensionPrincipalClass
$(PRODUCT_MODULE_NAME).ActionViewController





обработчик запроса действий
import UIKit
import MobileCoreServices
import UniformTypeIdentifiers

class ActionRequestHandler: NSObject, NSExtensionRequestHandling {

var extensionContext: NSExtensionContext?

func beginRequest(with context: NSExtensionContext) {
// Do not call super in an Action extension with no user interface
self.extensionContext = context

var found = false

// Find the item containing the results from the JavaScript preprocessing.
outer:
for item in context.inputItems as! [NSExtensionItem] {
if let attachments = item.attachments {
for itemProvider in attachments {
if itemProvider.hasItemConformingToTypeIdentifier(UTType.propertyList.identifier) {
itemProvider.loadItem(forTypeIdentifier: UTType.propertyList.identifier, options: nil, completionHandler: { (item, error) in
let dictionary = item as! [String: Any]
OperationQueue.main.addOperation {
self.itemLoadCompletedWithPreprocessingResults(dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as! [String: Any]? ?? [:])
}
})
found = true
break outer
}
}
}
}

if !found {
self.doneWithResults(nil)
}
}

func itemLoadCompletedWithPreprocessingResults(_ javaScriptPreprocessingResults: [String: Any]) {
// Here, do something, potentially asynchronously, with the preprocessing
// results.

// In this very simple example, the JavaScript will have passed us the
// current background color style, if there is one. We will construct a
// dictionary to send back with a desired new background color style.
let bgColor: Any? = javaScriptPreprocessingResults["currentBackgroundColor"]
if bgColor == nil || bgColor! as! String == "" {
// No specific background color? Request setting the background to red.
self.doneWithResults(["newBackgroundColor": "red"])
} else {
// Specific background color is set? Request replacing it with green.
self.doneWithResults(["newBackgroundColor": "green"])
}
}

func doneWithResults(_ resultsForJavaScriptFinalizeArg: [String: Any]?) {
if let resultsForJavaScriptFinalize = resultsForJavaScriptFinalizeArg {
// Construct an NSExtensionItem of the appropriate type to return our
// results dictionary in.

// These will be used as the arguments to the JavaScript finalize()
// method.

let resultsDictionary = [NSExtensionJavaScriptFinalizeArgumentKey: resultsForJavaScriptFinalize]

let resultsProvider = NSItemProvider(item: resultsDictionary as NSDictionary, typeIdentifier: UTType.propertyList.identifier)

let resultsItem = NSExtensionItem()
resultsItem.attachments = [resultsProvider]

// Signal that we're complete, returning our results.
self.extensionContext!.completeRequest(returningItems: [resultsItem], completionHandler: nil)
} else {
// We still need to signal that we're done even if we have nothing to
// pass back.
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}

// Don't hold on to this after we finished with it.
self.extensionContext = nil
}

}

Основное приложение PLIST:




CFBundleURLTypes


CFBundleTypeRole
Editor
CFBundleURLName
com.elislothower.URLDisplayApp
CFBundleURLSchemes

myapp



LSApplicationQueriesSchemes






Подробнее здесь: https://stackoverflow.com/questions/795 ... hare-sheet
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»