Game Center Matchmaking Custom Invites - ios

I'm sure theres a 'simple' answer to this, but I've been having a difficult time finding it.
I've created an iOS card game that works in game center. At the moment, it determines the online players automatically and works fine.
What I want to do is have the user invite their game center friends to play. The documentation isn't really helping me.
I'm doing my project in swift, and I feel like I'm dealing with deprecated items and old documentation here?
I've managed to get the users list of friends and then I assume I need to instantiate a matchmaker with that list of friends.
What I'm stuck at, is trying to implement the "RecipientResponseHandler" code as per apple's guidelines:
request.recipientResponseHandler = ^(GKPlayer *player, GKInviteeResponse response)
{
[self updateUIForPlayer: player accepted: (response == GKInviteeResponseAccepted)];
};
Question 1: First of all, What does the ^ symbol represent in the swift language?
Question 2: XCode doesn't seem to like the * symbol in the arguments...I've tried doing things like...
request.recipientResponseHandler = (player: GKPlayer, response: GKInviteeResponse){
print("Do codeStuffHere")
};
But, I can't find a way of wording this that XCode will allow...
Question 3: How can I write this response handler to get it to work?
Question 4: Also,to listen for invites, I need to implement the GKLocalPlayerListener protocol...Anything else?
Question 5: I feel like I'm missing something glaring?
I've been learning on my own, and sometimes it takes a while to understand concepts without any direction, so please go easy on me internet. I'm just starting to understand completion handlers and closures...
Thanks in advance for any help.

What does the ^ symbol represent in the swift language?
XCode doesn't seem to like the * symbol in the arguments.
That's because that code is written in Objective-C, not Swift.
I'm assuming you're looking at the documentation for GKMatchRequest (update as of Jan 2023: It seems Apple has removed the code listing from this page at some point).
If so, then yeah, Apple just hasn't gotten around to updating all their documentation to use Swift instead of Objective-C (even on pages where the language selected is Swift, like this one).
Here's the Swift equivalent of that entire code listing:
func invite(friends: [GKPlayer]) {
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 4
request.recipients = friends
request.inviteMessage = "Your Custom Invitation Message Here"
request.recipientResponseHandler = { player, response in
self.updateUI(for: player, accepted: response == .accepted)
}
}
func updateUI(for player: GKPlayer, accepted: Bool) {
// update your UI here
}

For question 4, be sure to register the GKLocalPlayerListener and only register once, for example:
GKLocalPlayer.local.register(self)

Related

iOS 11.4 not asking Privacy Usage ( Privacy - Motion Usage Description has been set )

I'm stumped, iOS 11.4 ( 15F79 ), iPhone 6. Cannot get the App to Ask for Motion Data. info.plist has been set via the editor and double checked via the info.plist open in textWrangler, Also deleted key and saved via textWrangler.
<key>NSMotionUsageDescription</key>
<string>This app needs your Phones motion manager to update when the phone is tilted. Please allow this App to use your phones tilt devices</string>
I have deleted then reinstalled the app about 10 times. I have restared the phone 5 times. I have checked through settings and my app does NOT show up in Privacy-Motion and Fitness or anywhere else in settings. I am using a free developer account, maybe that has something to do with it?
I created a new Xcode game template and changed nothing apart from importing CoreMotion and this code
**** Edited, sorry I forgot to say I had started the instance, just forgot to put it here, just in case someone thinks that's the problem ************
let motionManager = CMMotionManager()
override func didMove(to view: SKView) {
motionManager.startDeviceMotionUpdates()
if motionManager.isDeviceMotionActive == true {
motionManager.accelerometerUpdateInterval = 0.2
motionManager.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: {
(accelerometerData: CMAccelerometerData!, error: NSError!) in
let acceleration = accelerometerData.acceleration
print(accelerometerData)
} as! CMAccelerometerHandler)
}else{
print(CMMotionActivityManager.authorizationStatus().rawValue)
}
which prints a 0 ( an Enum - case not determined ) to the console.
In my actual app it was a 3 ( same Enum - case Denied ).
As I've said, I have uninstalled, reinstalled, edited plist via Xcode and text wrangler ( a code editor ) , tried different versions of the code above, tried the code in different places ( in did move to view, in class )tried code off apple docs. etc.... I haven't been asked the NSUsage question and the App keeps crashing.
I have looked for ways to get the Alert fired up, As in CLLocationManager.requestWhenInUseAuthorization() but I cannot find a comparable CMMotion version ( I don't think there is one. ) I have created a new swift file , imported Foundation and CMMotion and just put that code there, But still no Alert asking for Motion Data.
I tried a single view app template instead of a game template thinking that might be the issue, Nope.
What do I do?
Any help Appreciated. Thanks
You are confusing two related but different classes.
CMMotionManager gives access to accelerometer, magnetometer and gyroscope data. It does not require any user permission as this information is not considered privacy related.
In your else clause you are checking the authorisation status of CMMotionActivityManager. This object reports the device motion type (walking, running, driving). This information is considered privacy related and when you create an instance of this class and request data from it, the permissions alert is displayed.
The reason your else is being triggered is because you are checking isDeviceMotionActive; this will be false until you call startDeviceMotionUpdates, which you never do. Even if you used isAccelerometerActive you would have a problem because you call startAccelerometerUpdates in the if clause which will never be reached.
You probably meant to check isAccelerometerAvailable. If this returns false then there isn't much you can do; the device doesn't have an accelerometer.
Update
It doesn't make sense to check isDeviceMotionActive immediately after calling startDeviceMotion:
You know it's active; you just started it
I imagine the start up takes some time, so you could expect to get false if you check immediately.
Apple recommends that you do not have more than one observer in place for each motion device type, so the purpose of check the is...Active to ensure you don't call start... again if you have already done so.
If you only want gyroscope data then you don't need to call startDeviceMotionUpdates at all.

How to use SpringboardServices to get notifications count of an app ios

How can I get notifications count of another app into my app by using SpringboardServices and SBSPushStore?
I'm trying to show notification count taken from whatsapp into my app so I was searching around and one thing is for sure that it is possible but I didn't find any approbate way on how to do it.Here is the question which answers it but I didn't get it. How to do it? Can someone please share the step by step procedure.
Based on the question I was able to find the code which can actually lock you iphone using SpringboardServices but I don't know how to use it for SBSPushStore?
void *SpringBoardServices = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY);
NSParameterAssert(SpringBoardServices);
mach_port_t (*SBSSpringBoardServerPort)() = dlsym(SpringBoardServices, "SBSSpringBoardServerPort");
NSParameterAssert(SBSSpringBoardServerPort);
SpringBoardServicesReturn (*SBSLockDevice)(mach_port_t port) = dlsym(SpringBoardServices, "SBSLockDevice");
NSParameterAssert(SBSLockDevice);
mach_port_t sbsMachPort = SBSSpringBoardServerPort();
SBSLockDevice(sbsMachPort);
dlclose(SpringBoardServices);
The answer to that linked question you commented on implies that you don't need any framework, as long as your device is jailbroken.
You simply load the plist file located at /var/mobile/Library/SpringBoard/applicationState.plist. The format of that answer is a bit broken, but I assume the > are meant as indicators to explain the inner structure of the file (i.e. key values).
So from that I assume it's a dictionary, you can load it by
NSDictionary *plistFile = [NSDictionary dictionaryWithContentsOfFile:#"/var/mobile/Library/SpringBoard/applicationState.plist"];
NSDictionary *entryForYourApp = plistFile[#"com.app.identifier"]; // obviously you have to use the identifier of whatever app you wanna check
NSInteger badgeCount = entryForYourApp[#"SBApplicationBadgeKey"];
You probably want to inspect the file yourself first (so set a debug point) and make sure its structure is like I assumed, the types are correct and so forth (not to mention it exists, Apple sometimes changes stuff like that and the other question is already several years old).
In general be aware that you can only do that, as said, on a jailbroken device. Otherwise your application simply doesn't have reading access to the path /var/mobile/Library/SpringBoard/applicationState.plist. Or to anything outside its sandbox, for that matter.

Is it possible to access system classes in swift?

I was trying to access the player inside WKWebView but I did some coding and it turned out it doesn't use AVPlayerViewController it uses a system class called WebFullScreenVideoRootVideoController
I used the code like this
the function in the picture is fired after a UIWindow appears
After that I started digging more and search for notifications fired by WebFullScreenVideoRootVideoController and some class called AVSystemController or something like that... it turned out it has multiple notifications two of them logically do what I want:
NowPlayingAppIsPlayingDidChange // first one
SomeClientPlayingDidChange // second one
But also the object that they return is called FigBaseObject
Is there anyway to access these objects "some hacky way :P" ?
This link should help you to find when to work on particular notification.
http://paulofierro.com/blog/2015/10/12/listening-for-video-playback-within-a-wkwebview
inside the notification, you can find the url
Extract video URL from NSNotification Asset
if let asset = notification.object?.asset as? AVURLAsset {
let videoURL = asset.URL
}
Did test for XAMAarin IOS, notification.object?.asset is not available, but not sure about swift.
Thanks

Google Analytics Integration in SWIFT

Im trying to integrate Google Analytics in SWIFT. I used this user guide and tried to do in SWIFt. But I'm having hard time since this is the first time using Google Analytics. Is there any tutorial/resource for SWIFT ? Thanks in advance.
Edit1: Procedure and code I have used,
1. Added the google headers in bridging-header file
2. Added these in Appdelegate
GAI.sharedInstance().trackUncaughtExceptions = true
GAI.sharedInstance().dispatchInterval = 20
GAI.sharedInstance().trackerWithTrackingId("UA-XXXX-YY")
3. Gave the screen name in viewDidAppear as self.screenName = "Game Screen"
4. Created an event as
var tracker = GAI.sharedInstance().trackerWithTrackingId("UA-XXXX-YY")
tracker.send(GAIDictionaryBuilder.createEventWithCategory("SolveGame", action: "GameSolved", label: "Solve", value: nil).build())
I know I'm late, but I was in a similar situation today - not knowing much about Google Analytics and trying to implement it in Swift, for which there's little help online yet. I got it working with basically the same code you have shown here. One suggestion: If you also set
GAI.sharedInstance().logger.logLevel = GAILogLevel.Verbose
You may get some useful messaging in the console.
One other minor point is that I'm calling trackerWithTrackingId() first, before the other calls. Not sure if order matters.
Also, I'm assuming from your point #3 that you're implementing GAITrackedViewController, but figured I would mention that anyway as a tip.
And one final sanity check - you are using your actual tracking id, rather than "UA-XXXX-YY" in your code, right?
I just had to deal with this. I used both the demo provided AND integrated it into my app.
Nothing. 0s.
Then I came in this morning to take a look. It was working this morning. So evidently there is a good bit of lag before this aspect of Google Analytics kicks in.
As for your event tracking, that should work if you are tracking events, however that isn't how you would track a given page.
Assuming that want to track pages to you would want to use something like this.
var storyboardViewName = "Lender-Details-View"
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// [START GOOGLE ANALYTICS]
var tracker = GAI.sharedInstance().defaultTracker
tracker.set(kGAIScreenName, value: storyboardViewName)
var builder = GAIDictionaryBuilder.createScreenView()
tracker.send(builder.build() as [NSObject : AnyObject])
// [END GOOGLE ANALYTICS]
//.... other code here .....
}

How to get total No. of players from Leaderboard

Is there any way I can get how many player has played my game and successfully reported the score on Leaderboard?
I am currently working on Marmalade for iOS, so I'd prefer if you can let me know the solution in Marmalade. But if not possible, kindly let me know the solution at least in Objective C.
Finally found the solution after searching in the marmalade example. Following is the steps for to get the total count -
1.First you need to authenticate the player to gamecenter, it's like Login. THe authentication method is -
s3eIOSGameCenterAuthenticate(AuthenticationCallback, NULL);
2.Next we need to load the scores from the leaderboard
s3eIOSGameCenterLeaderboardLoadScores(leaderboard,loadScoreCallBack);
3.Now in the callback method i.e. loadScoreCallBack, you will get the TotalCount.
void loadScoreCallBack(s3eIOSGameCenterLoadScoresResult* result)
{
int TotalCount= result->m_ScoreCount;
}

Resources