5

I have the below code to authenticate a local player in Game Center in my SwiftUI app. I want Game Center to prompt user to login if the player is not already login in but this doesn't happen.

class AppSettings: UINavigationController {
    func authenticateUser() {
        let localPlayer = GKLocalPlayer.local
        localPlayer.authenticateHandler = { vc, error in
            guard error == nil else {
                print(error?.localizedDescription ?? "")
                return
            }
        }
    }
}

What could be the problem? I also read about using UIViewControllerRepresentable somewhere in my class to integrate UIKit's ViewController into SwiftUI but I don't understand how I can use it. Can someone help me out?

pawello2222
  • 46,897
  • 22
  • 145
  • 209
Heyman
  • 449
  • 4
  • 13

2 Answers2

8

I didn't get anyone to answer my question correctly and after days of digging I found a solution. So I had to use the UIKit implementation like below and create a wrapper around it using UIViewControllerRepresentable in the GameCenterManager Struct. After that all I had to do was call GameCenterManager() inside my SwiftUI view in a ZStack and the job is done!

import SwiftUI
import UIKit
import GameKit


class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        authenticateUser()
    }
    let localPlayer = GKLocalPlayer.local
    func authenticateUser() {
        
        localPlayer.authenticateHandler = { vc, error in
            guard error == nil else {
                print(error?.localizedDescription ?? "")
                return
            }
            if vc != nil {
                self.present(vc!, animated: true, completion: nil)
            }
            if #available(iOS 14.0, *) {
                GKAccessPoint.shared.location = .bottomLeading
                GKAccessPoint.shared.showHighlights = true
                GKAccessPoint.shared.isActive = self.localPlayer.isAuthenticated
                
                // Fallback on earlier versions
            }
        }
    }
}


struct GameCenterManager: UIViewControllerRepresentable {
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<GameCenterManager>) -> ViewController {
        
        
        let viewController = ViewController()
        return viewController
        
    }
    
    func updateUIViewController(_ uiViewController: ViewController, context: UIViewControllerRepresentableContext<GameCenterManager>) {
        
    }
    
}
Heyman
  • 449
  • 4
  • 13
  • I was looking for exactly those lines of code. Thank you man. I am currently trying to create a turn based card app. Which app did you have in mind? – Kataran Nov 14 '20 at 15:21
  • @Kataran I am glad you found this helpful. I am working on a real-time multiplayer game. Very trivial though. RockPaperX. I have a working version for single player in the App Store already and now I am working on pushing the multiplayer. You can follow me on twitter so we can exchange ideas. – Heyman Nov 15 '20 at 15:26
  • I am only familiar with SwiftUI. How did you implement functions like to show achievements etc.? Would you implement it into the GameCenterManager Struct or into the View Controller? – Kataran Nov 20 '20 at 10:46
  • @Kataran you can implement them in a new class and call them from your SwiftUI view or implement them in the ViewController class. I have implemented them in a new class. – Heyman Nov 20 '20 at 17:42
  • @Kataran this is a very helpful blog. It helped me when I got stuck with sending and receiving invite – Heyman Nov 30 '20 at 13:26
0

The authenticateHandler returns a UIViewController as well which you're not using:

@available(iOS 6.0, *)
open var authenticateHandler: ((UIViewController?, Error?) -> Void)?

You need to present it:

class AppSettings: UINavigationController {
    func authenticateUser() {
        let localPlayer = GKLocalPlayer.local
        localPlayer.authenticateHandler = { vc, error in
            guard error == nil else {
                print(error?.localizedDescription ?? "")
                return
            }
            if let vc = vc {
                self.present(vc, animated: true, completion: nil)
            }
        }
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
  • So I just tried to present the ViewController but it still doesn't prompt the user to login when the user is Logged out of Game Center. I am using iOS 14 and I was expecting that the ViewController should bring up the login screen of Game Center so that the user can login. Do I need to do something further for that to happen? Pls let me know. @pawello2222 – Heyman Sep 26 '20 at 18:33