Why is Game Center matchmaking controller stuck on "connecting"? - ios

Trying to solve a Game Center issue that seems to be happening within the GCMatchmakerViewController, but maybe I'm somehow causing it. There are two ways to match to players via the Invite Friends button: by typing their email (or selecting from contacts) or by tapping from presented list of people played with recently.
If I select via the list of people played with recently, a notification is sent to them, and if they accept, the app launches, goes to the proper screen, presents the GCMatchmakerViewController, connects, accepts, and away we go with the game.
If I select by typing/selecting their contact, an iMessage is sent, they go to Messages, tap the message bubble. If the game app is already running, it is brought to foreground, GCMatchmakerViewController is presented, connects, accepts, and away we go. But if the app is not running, it launches, goes to proper screen, presents GCMatchmakerViewController, tries connecting, and just sits there forever.
Why is the connection not happening in that latter scenario?
The screen that is displayed when it's stuck connecting is this:
The code that presents the vc that issues the invitation:
let localPlayer: GKLocalPlayer = GKLocalPlayer.local
if localPlayer.isAuthenticated {
let matchrequest = GKMatchRequest()
matchrequest.minPlayers = 2
matchrequest.maxPlayers = 4
matchrequest.defaultNumberOfPlayers = 2
matchrequest.inviteMessage = "Want to play: " + "some name"
if let mmVC = GKMatchmakerViewController(matchRequest: matchrequest) {
mmVC.matchmakerDelegate = self
self.present(mmVC, animated: true)
}
}
The code that accepts the invitation:
if let response = GKMatchmakerViewController.init(invite: invite) {
response.matchmakerDelegate = newGameVC
present(response, animated: true, completion: nil)
}
Best as I can tell, my app doesn't know which scenario is in play, and does not choose different behaviors based on that. Stumped, and not sure how to advise users. Thanks for any ideas.

Related

Hide Activity Indicator when firebase authentication redirects to recapcha window (iOS - Swift)

I have implemented a Phone Authentication in my iOS app using Firebase, In that case, I have added an activity indicator to show a loading window. But, in some cases a ReCaptcha appears and, since the activity indicator is still in the window, the ReCaptcha cannot be completed, which makes the app freeze in one state.
Below is my code for login:
let activityIndicator = EAActivityIndicator()
activityIndicator.show()
Auth.auth().languageCode = "en"
PhoneAuthProvider.provider().verifyPhoneNumber(mobileNumber, uiDelegate: nil) { verificationId, error in
activityIndicator.hide()
if let error = error {
// handle error
} else {
self.navigationController?.pushViewController(ViewController(), animated: true)
}
}
As in the code, I show an activity indicator when the login button is tapped, if the mobile number is correct and if a 6 digit code is sent it will redirect to the Code entering View Controller. In certain cases, a ReCaptcha appears, but since the activity indicator is still on the screen, the ReCaptcha cannot be completed.
Screenshots:

How to know if user shared my app or not?

My app is all about getting points and winning money, and what I need to do is let the user share my app then give him some points.
The problem is that I don't know how to detect if the user truly shared the app or not
I'm using the following code:
func shareTapped(){
let text = "example"
let url = URL(string: "example.com")
let image = UIImage(named: "example_image")
let shareViewController = UIActivityViewController(activityItems: [text, image!, url!] ,applicationActivities: nil)
self.present(shareViewController, animated: true, completion: {() in
print("done")
})
}
The sharing method is working perfectly, but I was wondering if there is any delegate we can call in this situation.
Thanks.
So there is 2 scenarios where user can cancel share.
One is when UIActivityViewController present then there is a cancel button on UIActivityViewController from where user can cancel it and yes you can detect it with method
shareViewController.completionWithItemsHandler = { activity, completed, items, error in
}
In above method completed will be false if user canceled from UIActivityViewController cancel button. and it will return true if user share successfully but here comes second case with it.
So for second case suppose user want to share via watsapp and click on watsapp icon from UIActivityViewController and watsapp user list appear.
But there is a cancel button on that screen from where user can cancel sharing but still you will get completed flag true so there is no way you can detect if user click on cancel button from watsapp user list.

Why doesn't my iOS (Swift) app properly recognize some external display devices?

So I have an odd issue and my google-fu utterly fails to even provide me the basis of where to start investigating, so even useful keywords to search on may be of use.
I have an iOS application written in swift. I have a model hooked up to receive notifications about external displays. On some adaptors, I'm able to properly detect and respond to the presence of an external display and programatically switch it out to be something other than a mirror (see code block below). But with another adaptor, instead of just 'magically' becoming a second screen, I'm asked to 'trust' the external device, and it simply mirrors the device screen. Not the intended design at all.
func addSecondScreen(screen: UIScreen){
self.externalWindow = UIWindow.init(frame: screen.bounds)
self.externalWindow!.screen = screen
self.externalWindow!.rootViewController = self.externalVC
self.externalWindow!.isHidden = false;
}
#objc func handleScreenDidConnectNotification( _ notification: NSNotification){
let newScreen = notification.object as! UIScreen
if(self.externalWindow == nil){
addSecondScreen(screen: newScreen)
}
}
#objc func handleScreenDidDisconnectNotification( _ notification: NSNotification){
if let externalWindow = self.externalWindow{
externalWindow.isHidden = true
self.externalWindow = nil
}
}
The worst issue here is that because I'm connecting to an external display to do this, I can't even run this code through the debugger to find out what is going on. I don't know where to even begin.
Any ideas?
Edit:
Thanks to someone pointing out wifi debugging, I can tell you my notifications are firing off, but they're both firing at the same time, one after the other, when the external adaptor is disconnected.

Swift: Animating a view (for in-app notifications) onto the screen for a few seconds before removing

I am attempting to do what is described perfectly here: https://github.com/bryx-inc/BRYXBanner
I want to create a banner that pops down on the screen for a few seconds before being removed (or removed when it is tapped on). The above project is great up until iOS 9. After that and with iOS 10, the banner no longer works as predicted and either shows itself without an animation for a third of a second or it doesn't show.
How can I add a view that animates onto the screen and then back off to provide a user a quick "No Internet" notification in-app. I want to avoid using the notification center.
I had a similar problem and created my own library for it: MDNotificationView
The example app on GitHub implements your idea. Here is a small snippet implementing it:
let view = MDNotificationCompactLayoutView()
view.textLabel.text = "No internet connection."
let notificationView = MDNotificationView(view: view)
notificationView.delegate = self
notificationView.show()
// MARK: - Notification View Delegate
func notificationDidShow(notificationView: MDNotificationView) {
// Hide the notification view automatically after 5 seconds.
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
notificationView.hide()
}
}

Show GameCenter login later if user dismisses login screen at start of game?

We present the GameCenter login screen upon the game's launch. At the end of the game, we show a GameCenter button that lets users view their achievements and the game's leaderboards. If they dismissed the original screen and aren't logged in, how can we present the login screen again? Here's the code we're using, but it's not working.
override func viewDidLoad() {
super.viewDidLoad()
// Configure view
let skView = view as! SKView
skView.multipleTouchEnabled = false
//skView.showsNodeCount = true
//skView.showsFPS = true
// Show intro scene
let introScene = IntroScene(size: skView.bounds.size, controller: self)
introScene.scaleMode = .AspectFill
skView.presentScene(introScene)
// Authenticate GameCenter player
authenticateGameCenterPlayer()
}
private func authenticateGameCenterPlayer() {
var localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController : UIViewController!, error : NSError!) -> Void in
if ((viewController) != nil) {
self.presentViewController(viewController, animated: true, completion: nil)
} else {
println((GKLocalPlayer.localPlayer().authenticated))
}
}
}
func showLeaderboard() {
// User logged into GameCenter?
if (!GKLocalPlayer.localPlayer().authenticated) {
println("Local player not authenticated")
authenticateGameCenterPlayer()
return
}
// If here, user is authenticated so present leaderboards
var gcViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.leaderboardIdentifier = "highScoresLeaderboard"
self.showViewController(gcViewController, sender: self)
self.navigationController?.pushViewController(gcViewController, animated: true)
}
I understand Apple documentation mentions this in the the Game Center Programming Guide under Common Tasks When Working with Players > Authenticating a Local Player on the Device.
Important: Game Kit handles opting out of Game Center across all games
that support Game Center. If a player has already declined to create
an account, when your game authenticates the player, it is told there
is no authenticated player. The player never sees an authentication
dialog. Because Game Kit handles this process across all games, your
game should not include its own mechanism to disable Game Center
authentication or ask a player’s permission to authenticate. Instead,
your game should simply authenticate the player every time it launches
and respond appropriately when authentication completes
.
Game Center remembers the users log-in preferences and if the user dismisses the log-in dialog too many times, it will stop being displayed, even when you call localPlayer.authenticateHandler
The recommended way of handling this is to display a message telling the user to log in through the game center app
Almost a year late, but I encountered a similar issue and implemented a type of work around.
Check to see if the user is authenticated, and if not direct them to use the game center deeplink. This will prompt the login screen.
UIApplication.sharedApplication().openURL(NSURL(string: "gamecenter:")!)
If a user chooses not to login, they will be redirected back to your app. If a user logs in, they will have the ability to navigate back to your app via the back "Back to App" button at the top.

Resources