Могу ли я использовать Snapchat SDK (SnapKit) с SwiftUI? - PullRequest
2 голосов
/ 10 апреля 2020

Я пытаюсь интегрировать Snapkit с приложением iOS, но я хочу использовать SwiftUI вместо UIKit. Я уже выполнил необходимую настройку с помощью Snapkit, и теперь я пытаюсь заставить кнопку входа Snapchat отображаться в моем приложении. Я знаю, что Snapkit SDK создан для UIKit, а не для SwiftUI, но SwiftUI имеет способ оборачивать UIViews в 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

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

По совпадению я попытался внедрить SnapKit SDK в эксклюзивном проекте SwiftUI / iOS13 примерно через 3 дня после того, как вы опубликовали свою проблему.

К сожалению, я не могу напрямую решить вашу проблему, поскольку есть несколько ключевых проблем, которые Snapchat должен решить с помощью своего SDK, прежде чем он будет пригоден для разработки с помощью парадигмы SceneDelegate & AppDelegate, представленной в iOS 13. Но Я надеюсь, что смогу пролить свет на ваш вопрос и представить свои выводы кому-либо еще, кто находится в подобном затруднительном положении.

Это следующие проблемы / наблюдения, которые я сделал в своем стремлении реализовать SCSDKLoginKit & SCSDKBitmojiKit в SwiftUI:

  • Основная проблема c в том, что модуль SCSDKLoginKit устарел, как вы правильно поняли. SCSDKLoginClient.login () требует, чтобы вызывающее представление соответствовало (UIKIT) классу UIViewController. Поэтому мы должны использовать обходной путь с UIViewControllerRepresentable, чтобы выступать в качестве нашего посредника SwiftUI <-> UIKit.

  • Однако фундаментальная проблема связана с тем, что документация SnapKit SDK не была обновлена ​​до предоставьте разработчикам ссылку SceneDelegate между Snapchat Auth и логикой вашего приложения c. Таким образом, даже если вы правильно реализовали 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: код работает на устройстве

Подробнее о проблеме с интерфейсом SceneDelegate: когда вы неизбежно реализуете вызов SCSDKLoginClient.login () (предположительно, когда нажата ваша SCSDKLoginButton), Snapchat откроется, правильно отобразит лист «Предоставить доступ» при условии, что ваше приложение связано с порталом Snapchat Dev.

Когда вы принимаете эти разрешения, Snapchat перенаправляет на ваше приложение. Однако именно здесь связь между вашим приложением и получением имени пользователя / bitmoji в Snapchat будет нарушена. Это связано с тем, что в новых приложениях iOS 13 SceneDelegate обрабатывает, когда состояния вашего приложения изменяются, а не AppDelegate, как в предыдущих версиях iOS13. Поэтому Snapchat возвращает пользовательские данные, но ваше приложение никогда не извлекает их.

[Идет вперед]

  • SnapKitSDK (в настоящее время версия 1.4.3) должен быть обновлено вместе с документацией.
  • Я только что отправил вопрос в службу поддержки Snapchat, спрашивая, когда будет выпущено это обновление, поэтому я буду обновлять его, если услышу больше. Приносим извинения, если вы искали прямое решение вашей проблемы SCSDKLoginButton (), я просто хотел, чтобы вы знали, какие проблемы стоят за ней ie в данный момент времени.

[ Дополнительная литература]

  • Facebook обновил свои инструменты и документацию, чтобы включить делегатов Scene / App. См. Шаг «5. Соедините делегата приложения и делегата сцены» здесь: https://developers.facebook.com/docs/facebook-login/ios/
0 голосов
/ 05 мая 2020

@ 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
    }
...