【问题标题】:Can I use the Snapchat SDK (SnapKit) with SwiftUI?我可以将 Snapchat SDK (SnapKit) 与 SwiftUI 一起使用吗?
【发布时间】:2020-04-10 17:57:23
【问题描述】:

我正在尝试将 Snapkit 与 iOS 应用程序集成,但我想使用 SwiftUI 而不是 UIKit。我已经使用 Snapkit 完成了所需的设置,现在我正在尝试让 snapchat 登录按钮显示在我的应用程序中。我知道 Snapkit SDK 是为 UIKit 而不是 SwiftUI 制作的,但是 SwiftUI 可以通过 UIViewRepresentable 协议来wrap UIViews into SwiftUI。我已尝试实现此功能,但登录按钮仍未显示。

这是我的代码:

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

【问题讨论】:

    标签: swift swiftui snapchat uiviewrepresentable


    【解决方案1】:

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

    很遗憾,我无法直接解决您的问题,因为 Snapchat 必须使用他们的 SDK 解决一些关键问题,然后才能使用 iOS 13 中引入的 SceneDelegate 和 AppDelegate 范式进行开发。但我希望我能摆脱阐明您的问题,并将我的发现介绍给处于类似困境中的任何其他人。

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

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

    • 但是,根本问题与 SnapKit SDK 文档尚未更新以向开发人员提供 Snapchat Auth 和您的应用程序逻辑之间的 SceneDelegate 链接这一事实有关。因此,即使您正确实现了 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 接口链接问题的更多信息: 当您不可避免地实现 SCSDKLoginClient.login() 调用时(大概是在按下您的 SCSDKLoginButton 时),Snapchat 将打开,假设您的应用程序已链接到 Snapchat 开发门户中,它将正确显示“授予访问权限”表。

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

    [继续前进]

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

    [延伸阅读]

    【讨论】:

    • 谢谢,当我询问 snap 开发人员支持时,他们告诉我他们“计划在未来集成 swiftui”,但我不知道这实际上意味着什么。我想我现在就走 uikit 路线。
    • 即使 UIKit 也有一个场景委托文件,所以如果你使用 XCode 11,SwiftUI 和 UIKit 都不能开箱即用。
    • @Stephen2697 我想我想出了一个使用场景代理的解决方法。检查我更新的解决方案
    【解决方案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
        }
    

    【讨论】:

    • bze12 这个函数到底去哪儿了?我将它放在我的 App.swift 文件中,因为从最新的 iOS Xcode 版本开始不再使用委托。我在 func 场景上有一个断点,但是当我返回我的应用程序时它没有被击中。任何帮助将不胜感激!我完全被卡住了
    • 不确定它在 App.swift 中的位置,但 ios 14 肯定仍然支持委托。您只需要在创建项目时选择它,目前如果您使用 swiftui 它默认为 App.swift
    猜你喜欢
    • 2012-07-21
    • 1970-01-01
    • 2014-01-15
    • 1970-01-01
    • 2018-04-08
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    相关资源
    最近更新 更多