I want to receive an AirDrop text file, originating from my Mac (macOS 13.4), in my iOS app on my iPhone. Using Swift 5.8, Xcode 14.3 for iOS 16.
I have put this in my Info.plist
<key>UIFileSharingEnabled</key><true/>
<key>CFBundleDocumentTypes</key><array><dict>
<key>CFBundleTypeName</key><string>AirDrop Text File Type</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSItemContentTypes</key><array>
<string>public.text</string>
</array>
</dict>
</array>
On my iPhone I can see my TestApp
in the AirDrop menu, but I don't know how to receive the data.
I have this code, but I cannot get the url
, or the data, or whatever I am supposed to
receive. How can I get the content of the file, or even just its url, so I can read it?
@main
struct TestApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
Text("testing")
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("\n didFinishLaunchingWithOptions \n") // <-- can see this
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
print("\n url: \(url) \n") // <-- cannot see this
return true
}
// what other func do I need here
}
SwiftUI uses new UIScene
based UI LifeCycle, so you have to stick to UIScene
events to handle it.
You have two Options.
UISceneDelegate
proxy
UISceneDelegate.scene(_:openURLContexts:)
In order to make UISceneDelegate
proxy, implement UIApplicationDelegate.application(_:configurationForConnecting:options:)
like below (where SceneDelegate
is NSObject
& UISceneDelegate
but I recommand you to make it also conforms to UIWindowSceneDelegate
and ObservableObject
.)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
let configuration = connectingSceneSession.configuration.copy() as! UISceneConfiguration
switch connectingSceneSession.role {
case .windowApplication:
// use this code to provide your AppDelegate instance to SceneDelegate
// var info = connectingSceneSession.userInfo ?? [:]
// info["proxyAppDelegate"] = self
// connectingSceneSession.userInfo = info
configuration.delegateClass = SceneDelegate.self
case .windowExternalDisplay:
fallthrough
default:
break
}
return configuration
}
In your SceneDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// use this code to retrive the AppDelegate
let appDelegate = session.userInfo?["proxyAppDelegate"] as? AppDelegate
// use this codes to provide your SceneDelegate for later use in UIKit way
var sessionInfo = session.userInfo ?? [:]
sessionInfo["proxySceneDelegate"] = self
session.userInfo = sessionInfo
// use this to handle url actions like universal link
connectionOptions.urlContexts
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
// use this method to handle url actions performed by this scene
}
If your SceneDelegate
conforms to NSObject
and ObservableObject
then SwiftUI inject your SceneDelegate
as EnvironmentObject
in your View
.
If you provide your SceneDelgate
to UISceneSession.userInfo
. you can get that instance later by using UIApplication.shared.connectedScenes
or UIApplication.shared.openSessions