我可以将 Snapchat SDK (SnapKit) 与 SwiftUI 一起使用吗?

Posted

技术标签:

【中文标题】我可以将 Snapchat SDK (SnapKit) 与 SwiftUI 一起使用吗?【英文标题】:Can I use the Snapchat SDK (SnapKit) with 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

【问题讨论】:

【参考方案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 = "medisplayName, bitmojiavatar"
        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() 问题的直接解决方案,我们深表歉意,我只是想让您知道目前还有哪些挑战。

[延伸阅读]

Facebook 更新了他们的工具和文档,以合并场景/应用程序代表。请参阅此处的步骤“5. 连接您的 App Delegate 和 Scene Delegate”:https://developers.facebook.com/docs/facebook-login/ios/

【讨论】:

谢谢,当我询问 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

以上是关于我可以将 Snapchat SDK (SnapKit) 与 SwiftUI 一起使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

React - 转换 HTML 脚本标签以异步加载 SDK

构建像 Snapchat 这样的 Firebase 数据库

Snap推出AR开发工具,整合Snapchat优质功能

面部过滤器实现,如 MSQRD/SnapChat [关闭]

iOS 自定义弹出过渡 - 就像在 snapchat 故事上向下滑动

Tableview 像 Snapchat 发送功能(多选和可滑动标签)