3

I'm trying to integrate 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 with the UIViewRepresentable protocol. I've tried implementing this but the login button still doesn't display.

Here's my code:

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() {
        }
    }
}

I have a feeling I'm missing something from within SCSDKLoginButton, but not sure what it is so here's the file SCSDKLoginButton.h for reference. Any help would be greatly appreciated!

//
//  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
4

2 回答 2

2

@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
    }
于 2020-05-05T04:04:33.860 回答
2

巧合的是,在您发布问题大约 3 天后,我尝试在一个专有的 SwiftUI/iOS13 项目中实现 SnapKit SDK。

不幸的是,我无法直接解决您的问题,因为 Snapchat 必须使用其 SDK 解决一些关键问题,然后才能使用 iOS 13 中引入的 SceneDelegate 和 AppDelegate Paradigm 进行开发。但我希望我能阐明您的问题提问并将我的发现展示给处于类似困境中的任何其他人。

这些是我在 SwiftUI 中实现 SCSDKLoginKit 和 SCSDKBitmojiKit 时提出的以下问题/观察:

  • 正如您正确意识到的那样,最基本的问题是 SCSDKLoginKit 模块已过时。SCSDKLoginClient.login() 要求调用视图符合 (UIKIT) UIViewController 类。所以我们必须使用带有 UIViewControllerRepresentable 的解决方法来充当我们的 SwiftUI <-> UIKit 中介。

  • 然而,根本问题与 SnapKit SDK 文档尚未更新为开发人员提供 Snapchat Auth 和您的应用程序逻辑之间的 SceneDelegate 链接这一事实有关。因此,即使您正确实现了 SCSDKLoginButton,也并非一帆风顺!

现在直接回答您的问题,您正在尝试将 SCSDKLoginButton 包装在 UIViewControllerRepresentable 中,这是可以做到的,我相信比我更了解协调员等的人可以帮助您解决这个问题。但是,我只是想表明,在 snapchat 提供更新的 SDK 之前,您目前的努力可能会徒劳无功。

这是我的设置:

[内容视图.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()
        }
    }
}

[登录CVWrapper.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
    }
}

[登录视图控制器.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 接口链接问题的更多信息:当您不可避免地实现 SCSDKLoginClient.login() 调用时(可能是按下您的 SCSDKLoginButton 时),Snapchat 将打开,假设您的应用程序链接在 Snapchat 中,它将正确显示“授予访问权限”表开发门户。

当您接受这些权限时,Snapchat 会重定向到您的应用程序。然而,这就是您的应用程序与检索 snapchat 用户名/bitmoji 之间的链接将失效的地方。这是因为在新的 iOS 13 应用程序中,SceneDelegate 会在您的应用程序状态更改时处理,而不是像 iOS13 之前的版本那样处理 AppDelegate。因此 Snapchat 会返回用户数据,但您的应用程序永远不会检索它。

[往前走]

  • SnapKitSDK(当前版本 1.4.3)需要与文档一起更新。
  • 我刚刚向 Snapchat 提交了一个支持问题,询问此更新何时发布,因此如果我听到更多信息,我会更新此内容。如果您正在寻找 SCSDKLoginButton() 问题的直接解决方案,我深表歉意,我只是想让您知道在当前时刻之外还有哪些挑战。

[延伸阅读]

于 2020-04-22T11:53:21.293 回答