一段时间以来,我一直在尝试寻找在 SwiftUI 项目中使用 SwiftyDropbox SDK 来验证 Dropbox 的解决方案,但这没有成功。
自述文件中提供的说明使用 AppDelegate 和 SceneDelegate。据我了解,后者对于 SwiftUI 来说是不可能的。我已经能够启动 OAuth2 Safari 窗口,但 DropboxClientsManager.authorizedClient 始终为零。
我终于想通了。
按照 SwiftyDropbox 自述文件的说明设置 info.plist。
// <app_name>.swift
import SwiftUI
import SwiftyDropbox
@main
struct DropboxTestApp: App {
init() {
DropboxClientsManager.setupWithAppKey("<app key>")
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
// ContentView.swift
import SwiftUI
import SwiftyDropbox
struct ContentView: View {
@State var isShown = false
var body: some View {
VStack {
Button(action: {
self.isShown.toggle()
}) {
Text("Login to Dropbox")
}
DropboxView(isShown: $isShown)
Button {
if let client = DropboxClientsManager.authorizedClient {
print("successful login")
} else {
print("Error")
}
} label: {
Text("Test Login")
}
}
.onOpenURL { url in
let oauthCompletion: DropboxOAuthCompletion = {
if let authResult = $0 {
switch authResult {
case .success:
print("Success! User is logged into DropboxClientsManager.")
case .cancel:
print("Authorization flow was manually canceled by user!")
case .error(_, let description):
print("Error: \(String(describing: description))")
}
}
}
DropboxClientsManager.handleRedirectURL(url, completion: oauthCompletion)
}
}
}
struct DropboxView: UIViewControllerRepresentable {
typealias UIViewControllerType = UIViewController
@Binding var isShown : Bool
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
if isShown {
let scopeRequest = ScopeRequest(scopeType: .user, scopes: ["account_info.read", "files.metadata.write", "files.metadata.read", "files.content.write", "files.content.read"], includeGrantedScopes: false)
DropboxClientsManager.authorizeFromControllerV2(
UIApplication.shared,
controller: uiViewController,
loadingStatusDelegate: nil,
openURL: { (url: URL) -> Void in UIApplication.shared.open(url, options: [:], completionHandler: nil) },
scopeRequest: scopeRequest)
}
}
func makeUIViewController(context _: Self.Context) -> UIViewController {
return UIViewController()
}
}
您不需要创建 AppDelegate。
我希望有人会发现这很有用。
此替代解决方案不需要创建 DropboxView,尽管其工作原理完全相同(在新窗口中打开登录流程)。对于对 DropboxClientsManager.setupWithAppKey 的调用,我已将 AppDelegate 添加到 SwiftUI 项目中,并且还通过 Brierfly 测试将其添加到 .active scenePhase 的 .onChange(of: scenePhase) 中,并且似乎也有效。
struct ContentView: View {
var body: some View {
VStack {
Spacer()
Button("Login with Dropbox") {
performLogin()
}
Spacer()
Spacer()
}
.padding()
.onOpenURL { url in
print("url: \(url)")
let oauthCompletion: DropboxOAuthCompletion = {
if let authResult = $0 {
switch authResult {
case .success:
print("Success! User is logged into DropboxClientsManager.")
case .cancel:
print("Authorization flow was manually canceled by user!")
case .error(_, let description):
print("Error: \(String(describing: description))")
}
}
}
DropboxClientsManager.handleRedirectURL(url, backgroundSessionIdentifier: "patata", completion: oauthCompletion)
}
}
func performLogin() {
let scopeRequest = ScopeRequest(scopeType: .user, scopes: ["account_info.read", "files.metadata.write", "files.metadata.read", "files.content.write", "files.content.read"], includeGrantedScopes: false)
DropboxClientsManager.authorizeFromControllerV2(
UIApplication.shared,
controller: nil,
loadingStatusDelegate: nil,
openURL: { (url: URL) -> Void in UIApplication.shared.open(url, options: [:], completionHandler: nil) },
scopeRequest: scopeRequest
)
}
}