我可以将 Snapchat SDK (SnapKit) 与 SwiftUI 一起使用吗?
Can I use the Snapchat SDK (SnapKit) with SwiftUI?
我正在尝试将 Snapkit with an iOS app but I want to use SwiftUI instead of UIKit. I've already done the required setup with Snapkit and now I'm trying to get the snapchat login button to display in my app. I know the Snapkit SDK is made for UIKit and not SwiftUI, but SwiftUI has a way to wrap UIViews into SwiftUI 与 UIViewRepresentable 协议集成。我试过实现这个,但登录按钮仍然没有显示。
这是我的代码:
import SwiftUI
import UIKit
import SCSDKLoginKit
struct ContentView: View {
var body: some View {
SnapchatLoginButtonView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct SnapchatLoginButtonView: UIViewRepresentable {
func makeCoordinator() -> Coordinator {
Coordinator()
}
func makeUIView(context: Context) -> SCSDKLoginButton {
let s = SCSDKLoginButton()
s.delegate = context.coordinator
return s
}
func updateUIView(_ uiView: SCSDKLoginButton, context: Context) {
}
class Coordinator: NSObject, SCSDKLoginButtonDelegate {
func loginButtonDidTap() {
}
}
}
我感觉我在 SCSDKLoginButton 中遗漏了一些东西,但不确定是什么所以这里是文件 SCSDKLoginButton.h 以供参考。任何帮助将不胜感激!
//
// SCSDKLoginButton.h
// SCSDKLoginKit
//
// Copyright © 2018 Snap, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol SCSDKLoginButtonDelegate
- (void)loginButtonDidTap;
@end
@interface SCSDKLoginButton : UIView
@property (nonatomic, weak, nullable) id<SCSDKLoginButtonDelegate> delegate;
- (instancetype)initWithCompletion:(nullable void (^)(BOOL success, NSError *error))completion NS_DESIGNATED_INITIALIZER;
@end
巧合的是,在您发布 Issue 大约 3 天后,我尝试在独家 SwiftUI/ iOS13 项目中实施 SnapKit SDK。
不幸的是,我无法直接解决您的问题,因为 Snapchat 在适合使用 iOS 13 中介绍的 SceneDelegate 和 AppDelegate 范例进行开发之前,必须通过其 SDK 解决一些关键问题。但我希望我能阐明您的问题,并将我的发现展示给其他处于类似困境中的人。
这些是我在寻求在 SwiftUI 中实现 SCSDKLoginKit 和 SCSDKBitmojiKit 时提出的以下问题/观察:
最基本的问题是 SCSDKLoginKit 模块已过时,正如您正确意识到的那样。 SCSDKLoginClient.login() 要求调用视图符合 (UIKIT) UIViewController class。所以我们必须使用 UIViewControllerRepresentable 的解决方法来充当我们的 SwiftUI <-> UIKit 中介。
然而,根本问题在于 SnapKit SDK 文档尚未更新,无法为开发人员提供 Snapchat Auth 和您的应用程序逻辑之间的 SceneDelegate link。所以即使你正确地实现了你的 SCSDKLoginButton 也不是一帆风顺的!
现在直接回答你的问题,你正试图将 SCSDKLoginButton 包装在 UIViewControllerRepresentable 中,这是可以做到的,我相信比我更了解协调器等的人可以帮助你。然而,我只是想表明,在 snapchat 提供更新的 SDK 之前,您目前的努力可能是徒劳的。
这是我的设置:
[ContentView.swift]
import SwiftUI
struct ContentView: View {
@State private var isPresented = false
var body: some View {
Button("Snapchat Login Button") { self.isPresented = true}
.sheet(isPresented: $isPresented) {
LoginCVWrapper()
}
}
}
[LoginCVWrapper.swift]
import SwiftUI
import UIKit
import SCSDKLoginKit
struct LoginCVWrapper: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
return LoginViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
//Unused in demonstration
}
}
[LoginViewController.swift]
import UIKit
import SCSDKLoginKit
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
performLogin() //Attempt Snap Login Here
}
//Snapchat Credential Retrieval Fails Here
private func performLogin() {
//SCSDKLoginClient.login() never completes once scene becomes active again after Snapchat redirect back to this app.
SCSDKLoginClient.login(from: self, completion: { success, error in
if let error = error {
print("***ERROR LOC: manualTrigger() \(error.localizedDescription)***")
return
}
if success {
self.fetchSnapUserInfo({ (userEntity, error) in
print("***SUCCESS LOC: manualTrigger()***")
if let userEntity = userEntity {
DispatchQueue.main.async {
print("SUCCESS:\(userEntity)")
}
}
})
}
})
}
private func fetchSnapUserInfo(_ completion: @escaping ((UserEntity?, Error?) -> ())){
let graphQLQuery = "{me{displayName, bitmoji{avatar}}}"
SCSDKLoginClient
.fetchUserData(
withQuery: graphQLQuery,
variables: nil,
success: { userInfo in
if let userInfo = userInfo,
let data = try? JSONSerialization.data(withJSONObject: userInfo, options: .prettyPrinted),
let userEntity = try? JSONDecoder().decode(UserEntity.self, from: data) {
completion(userEntity, nil)
}
}) { (error, isUserLoggedOut) in
completion(nil, error)
}
}
}
[运行如下]:
GIF: Code Running On Device
有关 SceneDelegate 界面的更多信息 link 问题:
当您不可避免地执行 SCSDKLoginClient.login() 调用时(大概是在按下 SCSDKLoginButton 时),Snapchat 将打开,假设您的应用是 link,它将正确显示 "grant access" sheet在 Snapchat Dev Portal 中编辑。
当您接受这些权限后,Snapchat 会重定向到您的应用程序。然而,这是您的应用程序和检索 snapchat 用户名/bitmoji 之间的 link 崩溃的地方。这是因为在新的 iOS 13 应用程序中,当您的应用程序状态更改时,SceneDelegate 会处理,而不是 iOS13 之前版本中的 AppDelegate。因此 Snapchat returns 用户数据,但您的应用程序永远不会检索它。
[前进]
- SnapKitSDK(当前版本为 1.4.3)需要与文档一起更新。
- 我刚刚向 Snapchat 提交了一个支持问题,询问此更新何时到来,所以如果我听到更多消息,我会更新此问题。如果您正在寻找 SCSDKLoginButton() 问题的直接解决方案,我深表歉意,我只是想让您知道目前还有哪些挑战超出了它。
[进一步阅读]
- Facebook 已更新其工具和文档以合并 Scene/App 代表。请在此处查看步骤“5. 连接您的 App Delegate 和 Scene Delegate”:https://developers.facebook.com/docs/facebook-login/ios/
@Stephen2697 正确地指出 snap sdk 不是为 iOS 13 构建的,但由于 SceneDelegate 现在处理 oauth 重定向而不是 AppDelegate。我想出了一个解决方法,可以在场景委托中使用 SCSDKLoginClient.application() 方法(为 appdelegate 制作)。这是代码,将其添加到您的场景委托中,传递给您的 Snapchat 登录的完成处理程序将 运行:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for urlContext in URLContexts {
let url = urlContext.url
var options: [UIApplication.OpenURLOptionsKey : Any] = [:]
options[.openInPlace] = urlContext.options.openInPlace
options[.sourceApplication] = urlContext.options.sourceApplication
options[.annotation] = urlContext.options.annotation
SCSDKLoginClient.application(UIApplication.shared, open: url, options: options)
}
}
至于登录按钮没有出现,请确保将完成处理程序添加到 SCSDKLoginButton 实例,否则它将无法工作。像这样:
let s = SCSDKLoginButton { (success, error) in
//handle login
}
我正在尝试将 Snapkit with an iOS app but I want to use SwiftUI instead of UIKit. I've already done the required setup with Snapkit and now I'm trying to get the snapchat login button to display in my app. I know the Snapkit SDK is made for UIKit and not SwiftUI, but SwiftUI has a way to wrap UIViews into SwiftUI 与 UIViewRepresentable 协议集成。我试过实现这个,但登录按钮仍然没有显示。
这是我的代码:
import SwiftUI
import UIKit
import SCSDKLoginKit
struct ContentView: View {
var body: some View {
SnapchatLoginButtonView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct SnapchatLoginButtonView: UIViewRepresentable {
func makeCoordinator() -> Coordinator {
Coordinator()
}
func makeUIView(context: Context) -> SCSDKLoginButton {
let s = SCSDKLoginButton()
s.delegate = context.coordinator
return s
}
func updateUIView(_ uiView: SCSDKLoginButton, context: Context) {
}
class Coordinator: NSObject, SCSDKLoginButtonDelegate {
func loginButtonDidTap() {
}
}
}
我感觉我在 SCSDKLoginButton 中遗漏了一些东西,但不确定是什么所以这里是文件 SCSDKLoginButton.h 以供参考。任何帮助将不胜感激!
//
// SCSDKLoginButton.h
// SCSDKLoginKit
//
// Copyright © 2018 Snap, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol SCSDKLoginButtonDelegate
- (void)loginButtonDidTap;
@end
@interface SCSDKLoginButton : UIView
@property (nonatomic, weak, nullable) id<SCSDKLoginButtonDelegate> delegate;
- (instancetype)initWithCompletion:(nullable void (^)(BOOL success, NSError *error))completion NS_DESIGNATED_INITIALIZER;
@end
巧合的是,在您发布 Issue 大约 3 天后,我尝试在独家 SwiftUI/ iOS13 项目中实施 SnapKit SDK。
不幸的是,我无法直接解决您的问题,因为 Snapchat 在适合使用 iOS 13 中介绍的 SceneDelegate 和 AppDelegate 范例进行开发之前,必须通过其 SDK 解决一些关键问题。但我希望我能阐明您的问题,并将我的发现展示给其他处于类似困境中的人。
这些是我在寻求在 SwiftUI 中实现 SCSDKLoginKit 和 SCSDKBitmojiKit 时提出的以下问题/观察:
最基本的问题是 SCSDKLoginKit 模块已过时,正如您正确意识到的那样。 SCSDKLoginClient.login() 要求调用视图符合 (UIKIT) UIViewController class。所以我们必须使用 UIViewControllerRepresentable 的解决方法来充当我们的 SwiftUI <-> UIKit 中介。
然而,根本问题在于 SnapKit SDK 文档尚未更新,无法为开发人员提供 Snapchat Auth 和您的应用程序逻辑之间的 SceneDelegate link。所以即使你正确地实现了你的 SCSDKLoginButton 也不是一帆风顺的!
现在直接回答你的问题,你正试图将 SCSDKLoginButton 包装在 UIViewControllerRepresentable 中,这是可以做到的,我相信比我更了解协调器等的人可以帮助你。然而,我只是想表明,在 snapchat 提供更新的 SDK 之前,您目前的努力可能是徒劳的。
这是我的设置:
[ContentView.swift]
import SwiftUI
struct ContentView: View {
@State private var isPresented = false
var body: some View {
Button("Snapchat Login Button") { self.isPresented = true}
.sheet(isPresented: $isPresented) {
LoginCVWrapper()
}
}
}
[LoginCVWrapper.swift]
import SwiftUI
import UIKit
import SCSDKLoginKit
struct LoginCVWrapper: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
return LoginViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
//Unused in demonstration
}
}
[LoginViewController.swift]
import UIKit
import SCSDKLoginKit
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
performLogin() //Attempt Snap Login Here
}
//Snapchat Credential Retrieval Fails Here
private func performLogin() {
//SCSDKLoginClient.login() never completes once scene becomes active again after Snapchat redirect back to this app.
SCSDKLoginClient.login(from: self, completion: { success, error in
if let error = error {
print("***ERROR LOC: manualTrigger() \(error.localizedDescription)***")
return
}
if success {
self.fetchSnapUserInfo({ (userEntity, error) in
print("***SUCCESS LOC: manualTrigger()***")
if let userEntity = userEntity {
DispatchQueue.main.async {
print("SUCCESS:\(userEntity)")
}
}
})
}
})
}
private func fetchSnapUserInfo(_ completion: @escaping ((UserEntity?, Error?) -> ())){
let graphQLQuery = "{me{displayName, bitmoji{avatar}}}"
SCSDKLoginClient
.fetchUserData(
withQuery: graphQLQuery,
variables: nil,
success: { userInfo in
if let userInfo = userInfo,
let data = try? JSONSerialization.data(withJSONObject: userInfo, options: .prettyPrinted),
let userEntity = try? JSONDecoder().decode(UserEntity.self, from: data) {
completion(userEntity, nil)
}
}) { (error, isUserLoggedOut) in
completion(nil, error)
}
}
}
[运行如下]: GIF: Code Running On Device
有关 SceneDelegate 界面的更多信息 link 问题: 当您不可避免地执行 SCSDKLoginClient.login() 调用时(大概是在按下 SCSDKLoginButton 时),Snapchat 将打开,假设您的应用是 link,它将正确显示 "grant access" sheet在 Snapchat Dev Portal 中编辑。
当您接受这些权限后,Snapchat 会重定向到您的应用程序。然而,这是您的应用程序和检索 snapchat 用户名/bitmoji 之间的 link 崩溃的地方。这是因为在新的 iOS 13 应用程序中,当您的应用程序状态更改时,SceneDelegate 会处理,而不是 iOS13 之前版本中的 AppDelegate。因此 Snapchat returns 用户数据,但您的应用程序永远不会检索它。
[前进]
- SnapKitSDK(当前版本为 1.4.3)需要与文档一起更新。
- 我刚刚向 Snapchat 提交了一个支持问题,询问此更新何时到来,所以如果我听到更多消息,我会更新此问题。如果您正在寻找 SCSDKLoginButton() 问题的直接解决方案,我深表歉意,我只是想让您知道目前还有哪些挑战超出了它。
[进一步阅读]
- Facebook 已更新其工具和文档以合并 Scene/App 代表。请在此处查看步骤“5. 连接您的 App Delegate 和 Scene Delegate”:https://developers.facebook.com/docs/facebook-login/ios/
@Stephen2697 正确地指出 snap sdk 不是为 iOS 13 构建的,但由于 SceneDelegate 现在处理 oauth 重定向而不是 AppDelegate。我想出了一个解决方法,可以在场景委托中使用 SCSDKLoginClient.application() 方法(为 appdelegate 制作)。这是代码,将其添加到您的场景委托中,传递给您的 Snapchat 登录的完成处理程序将 运行:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for urlContext in URLContexts {
let url = urlContext.url
var options: [UIApplication.OpenURLOptionsKey : Any] = [:]
options[.openInPlace] = urlContext.options.openInPlace
options[.sourceApplication] = urlContext.options.sourceApplication
options[.annotation] = urlContext.options.annotation
SCSDKLoginClient.application(UIApplication.shared, open: url, options: options)
}
}
至于登录按钮没有出现,请确保将完成处理程序添加到 SCSDKLoginButton 实例,否则它将无法工作。像这样:
let s = SCSDKLoginButton { (success, error) in
//handle login
}