我可以将Snapchat SDK(SnapKit)与SwiftUI一起使用吗?
我正在尝试与iOS应用程序集成,但我想使用SwiftUI而不是UIKit。我已经使用Snapkit完成了所需的设置,现在我正在尝试让snapchat登录按钮显示在我的应用程序中。我知道Snapkit SDK是为UIKit而不是SwiftUI设计的,但SwiftUI有办法使用UIViewRepresentable协议。我已经尝试过实现这个功能,但是登录按钮仍然不显示 这是我的密码:我可以将Snapchat SDK(SnapKit)与SwiftUI一起使用吗?,swift,swiftui,snapchat,uiviewrepresentable,Swift,Swiftui,Snapchat,Uiviewrepresentable,我正在尝试与iOS应用程序集成,但我想使用SwiftUI而不是UIKit。我已经使用Snapkit完成了所需的设置,现在我正在尝试让snapchat登录按钮显示在我的应用程序中。我知道Snapkit SDK是为UIKit而不是SwiftUI设计的,但SwiftUI有办法使用UIViewRepresentable协议。我已经尝试过实现这个功能,但是登录按钮仍然不显示 这是我的密码: import SwiftUI import UIKit import SCSDKLoginKit struct C
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
//
//SCSDKLoginButton.h
//SCSDKLoginKit
//
//版权所有©2018 Snap,Inc.保留所有权利。
//
#进口
@协议scsdkloginbuttonelegate
-(无效)登录Buttondidtap;
@结束
@接口SCSDKLoginButton:UIView
@属性(非原子、弱、可空)id委托;
-(instancetype)initWithCompletion:(可为空的void(^)(BOOL success,NSError*error))完成指定的初始值设定项;
@结束
巧合的是,在您发布您的问题大约3天后,我尝试在一个独家SwiftUI/iOS13项目中实现SnapKit SDK
不幸的是,我无法直接解决您的问题,因为Snapchat在适合使用iOS 13中引入的SceneDelegate&AppDelegate范例进行开发之前,必须通过其SDK解决一些关键问题。但我希望我能阐明你的问题,并将我的发现告诉其他处于类似困境的人
以下是我在寻求在SwiftUI中实现SCSDKLoginKit和SCSDKBitmojiKit时提出的以下问题/意见:
- 最基本的问题是,正如您正确认识到的,SCSDKLoginKit模块已经过时。SCSDKLoginClient.login()要求调用视图符合(UIKIT)UIViewController类。因此,我们必须使用具有UIViewControllerRepresentable的变通方法来充当我们的SwiftUI UIKit中介
- 但是,根本问题在于SnapKit SDK文档尚未更新,无法为开发人员提供Snapchat Auth和应用程序逻辑之间的SceneDelegate链接。因此,即使您正确地实现了SCSDKLoginButton,也不是一帆风顺的
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()
}
}
}
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
}
}
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)
}
}
}
[LoginCVWrapper.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()
}
}
}
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
}
}
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)
}
}
}
[LoginViewController.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()
}
}
}
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
}
}
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)
}
}
}
[运行如下]:
有关SceneDelegate接口链接问题的更多信息:
当您不可避免地实现SCSDKLoginClient.login()调用时(可能是在按下SCSDKLoginButton时),Snapchat将打开,它将正确显示“授权访问”表,假设您的应用程序链接到Snapchat开发门户中
接受这些权限后,Snapchat将重定向到应用程序。但是,这就是应用程序与检索snapchat用户名/bitmoji之间的链接将崩溃的地方。这是因为在新的iOS 13应用程序中,SceneDelegate会在应用程序状态更改时进行处理,而不是像iOS 13之前的版本那样处理AppDelegate。因此,Snapchat返回用户数据,但您的应用程序从未检索到它
[前进]
- SnapKitSDK(当前版本为1.4.3)需要与文档一起更新
- 我刚刚向Snapchat提交了一个支持问题,询问此更新何时发布,因此如果听到更多信息,我将更新此内容。抱歉如果您正在寻找SCSDKLoginButton()问题的直接解决方案,我只是想让您知道在当前时刻,除此之外还有哪些挑战
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()
}
}
}
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
}
}
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)
}
}
}
- Facebook已经更新了他们的工具和文档,以纳入场景/应用程序代理。请参见此处的步骤“5.连接应用程序代理和场景代理”:
- @Stephen2697正确地指出,由于SceneDelegate现在处理的是oauth重定向,而不是AppDelegate,因此snap sdk尚未为iOS 13构建。我找到了一种解决方法,可以在场景委托中使用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)
}
}
谢谢,当我询问snap开发者支持时,他们告诉我他们“计划在将来集成swiftui”,但我不知道这实际上意味着什么。我想我现在就走uikit路线。即使uikit有一个场景代理文件,所以如果您使用的是XCode 11,SwiftUI和uikit都不会立即工作。@Stephen2697我想我已经找到了使用scenedelegate的解决方法。检查我的更新解决方案BZE12此功能的具体用途是什么?我把它放在我的App.swift文件中,因为从最新的iOS Xcode版本开始,不再使用代理。我在func场景中有一个断点,但当我返回到我的应用程序时,它并没有被击中。任何帮助都将不胜感激!我完全不知道它会在App.swift中出现在哪里,但ios 14肯定仍然支持代理。您只需在创建项目时选择它,当前如果您使用swiftui,它默认为App.swift